@stoplight/elements-core 7.5.9 → 7.5.13

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.
@@ -5,5 +5,5 @@ interface HelperReturn<P> {
5
5
  createStory(name: string, input: Partial<P>): Story<P>;
6
6
  createHoistedStory(input: Partial<P>): Story<P>;
7
7
  }
8
- export declare const createStoriesForDocsComponent: <P>(Component: React.ComponentType<P>) => HelperReturn<P>;
8
+ export declare const createStoriesForDocsComponent: <P>(Component: React.ComponentType<P>, title?: string | undefined) => HelperReturn<P>;
9
9
  export {};
@@ -1,10 +1,12 @@
1
1
  import { IMediaTypeContent } from '@stoplight/types';
2
2
  import * as React from 'react';
3
- import { BodyParameterValues } from './request-body-utils';
3
+ import { BodyParameterValues, ParameterOptional } from './request-body-utils';
4
4
  interface FormDataBodyProps {
5
5
  specification: IMediaTypeContent;
6
6
  values: BodyParameterValues;
7
7
  onChangeValues: (newValues: BodyParameterValues) => void;
8
+ onChangeParameterAllow: (newValue: ParameterOptional) => void;
9
+ isAllowedEmptyValues: ParameterOptional;
8
10
  }
9
11
  export declare const FormDataBody: React.FC<FormDataBodyProps>;
10
12
  export {};
@@ -1,12 +1,13 @@
1
1
  import { IMediaTypeContent } from '@stoplight/types';
2
2
  import * as React from 'react';
3
3
  export declare type BodyParameterValues = Record<string, string | File>;
4
+ export declare type ParameterOptional = Record<string, boolean>;
4
5
  export declare const isFormDataContent: (content: IMediaTypeContent) => boolean;
5
6
  export declare function createRequestBody(mediaTypeContent: IMediaTypeContent | undefined, bodyParameterValues: BodyParameterValues | undefined): Promise<string | Blob | ArrayBuffer | ArrayBufferView | FormData | ReadableStream<Uint8Array> | undefined>;
6
- export declare const useBodyParameterState: (mediaTypeContent: IMediaTypeContent | undefined) => readonly [BodyParameterValues, React.Dispatch<React.SetStateAction<BodyParameterValues>>, {
7
+ export declare const useBodyParameterState: (mediaTypeContent: IMediaTypeContent | undefined) => readonly [BodyParameterValues, React.Dispatch<React.SetStateAction<BodyParameterValues>>, ParameterOptional, React.Dispatch<React.SetStateAction<ParameterOptional>>, {
7
8
  readonly isFormDataBody: true;
8
9
  readonly bodySpecification: IMediaTypeContent;
9
- }] | readonly [BodyParameterValues, React.Dispatch<React.SetStateAction<BodyParameterValues>>, {
10
+ }] | readonly [BodyParameterValues, React.Dispatch<React.SetStateAction<BodyParameterValues>>, ParameterOptional, React.Dispatch<React.SetStateAction<ParameterOptional>>, {
10
11
  readonly isFormDataBody: false;
11
12
  readonly bodySpecification: undefined;
12
13
  }];
@@ -5,6 +5,9 @@ interface ParameterProps {
5
5
  parameter: ParameterSpec;
6
6
  value?: string;
7
7
  onChange: SelectProps['onChange'];
8
+ isOptional: boolean;
9
+ onChangeOptional: (optional: boolean) => void;
10
+ canChangeOptional: boolean;
8
11
  validate?: boolean;
9
12
  }
10
13
  export declare const ParameterEditor: React.FC<ParameterProps>;
package/core.css ADDED
@@ -0,0 +1,87 @@
1
+ .sl-elements {
2
+ font-size: 13px;
3
+ }
4
+
5
+ .sl-elements .svg-inline--fa {
6
+ display: inline-block;
7
+ }
8
+
9
+ /* Docs */
10
+
11
+ .sl-elements .DocsSkeleton {
12
+ animation: 500ms linear infinite alternate skeleton-glow;
13
+ background: rgba(206, 217, 224, 0.2);
14
+ background-clip: padding-box !important;
15
+ border-color: rgba(206, 217, 224, 0.2) !important;
16
+ border-radius: 2px;
17
+ box-shadow: none !important;
18
+ color: transparent !important;
19
+ cursor: default;
20
+ pointer-events: none;
21
+ user-select: none;
22
+ }
23
+
24
+ .sl-elements .Model {
25
+ --fs-code: 12px;
26
+ }
27
+
28
+ /* Table of Contents */
29
+
30
+ .sl-elements .ElementsTableOfContentsItem:hover {
31
+ text-decoration: none;
32
+ color: inherit;
33
+ }
34
+
35
+ /* TryIt */
36
+
37
+ .sl-elements .ParameterGrid {
38
+ display: grid;
39
+ grid-template-columns: fit-content(120px) 20px auto;
40
+ row-gap: 3px;
41
+ align-items: center;
42
+ padding-bottom: 0;
43
+ margin-bottom: 16px;
44
+ }
45
+
46
+ .sl-elements .TryItPanel > :nth-child(2) {
47
+ /* This, along with the padding:0 margin: 16s above causes margin collapse to guarantee correct spacing around the panels & send button */
48
+ overflow: auto;
49
+ }
50
+
51
+ .sl-elements .OperationParametersContent {
52
+ max-height: 162px; /* 4.5 lines plus padding */
53
+ }
54
+
55
+ .sl-elements .Checkbox {
56
+ max-width: 15px;
57
+ padding-right: 3px;
58
+ }
59
+
60
+ .sl-elements .TextForCheckBox {
61
+ padding-top: 6px;
62
+ padding-left: 9px;
63
+ }
64
+
65
+ .sl-elements .TextRequestBody {
66
+ max-height: 200px;
67
+ overflow-y: auto;
68
+ padding-bottom: 0;
69
+ margin-bottom: 16px;
70
+ }
71
+
72
+ /* HttpOperation */
73
+
74
+ .sl-elements .HttpOperation .JsonSchemaViewer .sl-markdown-viewer p {
75
+ font-size: 12px;
76
+ line-height: 1.5em;
77
+ }
78
+
79
+ .sl-elements .HttpOperation__Parameters .sl-markdown-viewer p {
80
+ font-size: 12px;
81
+ line-height: 1.5em;
82
+ }
83
+
84
+ .sl-elements .Model .JsonSchemaViewer .sl-markdown-viewer p {
85
+ font-size: 12px;
86
+ line-height: 1.5em;
87
+ }
package/index.esm.js CHANGED
@@ -141,9 +141,9 @@ function isHttpService(maybeHttpService) {
141
141
  function isHttpOperation(maybeHttpOperation) {
142
142
  return isStoplightNode(maybeHttpOperation) && 'method' in maybeHttpOperation && 'path' in maybeHttpOperation;
143
143
  }
144
+ const properUrl = new RegExp(/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?)/);
144
145
  function isProperUrl(url) {
145
- const properUrl = new RegExp(/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?)/);
146
- return url.match(properUrl);
146
+ return properUrl.test(url);
147
147
  }
148
148
 
149
149
  function useParsedData(nodeType, data) {
@@ -357,13 +357,16 @@ function createNamedContext(name, defaultValue) {
357
357
 
358
358
  const chosenServerAtom = atom(undefined);
359
359
 
360
+ function isValidServer(server) {
361
+ return server.url !== null && isProperUrl(server.url);
362
+ }
360
363
  const getServersToDisplay = (originalServers, mockUrl) => {
361
364
  const servers = originalServers
362
365
  .map((server, i) => {
363
366
  const fallbackDescription = originalServers.length === 1 ? 'Live Server' : `Server ${i + 1}`;
364
367
  return Object.assign(Object.assign({}, server), { url: getServerUrlWithDefaultValues(server), description: server.description || fallbackDescription });
365
368
  })
366
- .filter(server => isProperUrl(server.url));
369
+ .filter(isValidServer);
367
370
  if (mockUrl) {
368
371
  servers.push({
369
372
  description: 'Mock Server',
@@ -379,7 +382,13 @@ const getServerUrlWithDefaultValues = (server) => {
379
382
  variables.forEach(([variableName, variableInfo]) => {
380
383
  urlString = urlString.replace(`{${variableName}}`, variableInfo.default);
381
384
  });
382
- let url = URI(urlString);
385
+ let url;
386
+ try {
387
+ url = URI(urlString);
388
+ }
389
+ catch (_b) {
390
+ return null;
391
+ }
383
392
  if (url.is('relative') && typeof window !== 'undefined') {
384
393
  url = url.absoluteTo(window.location.origin);
385
394
  }
@@ -969,9 +978,10 @@ function mapSchemaPropertiesToParameters(properties, required) {
969
978
  return Object.entries(properties).map(([name, schema]) => (Object.assign({ name, schema: typeof schema !== 'boolean' ? schema : undefined, examples: typeof schema !== 'boolean' && schema.examples ? [{ key: 'example', value: schema.examples }] : undefined }, ((required === null || required === void 0 ? void 0 : required.includes(name)) && { required: true }))));
970
979
  }
971
980
 
972
- const ParameterEditor = ({ parameter, value, onChange, validate }) => {
981
+ const ParameterEditor = ({ parameter, value, onChange, isOptional, onChangeOptional, canChangeOptional, validate, }) => {
973
982
  var _a, _b;
974
983
  const inputId = useUniqueId(`id_${parameter.name}_`);
984
+ const inputCheckId = useUniqueId(`id_${parameter.name}_checked`);
975
985
  const parameterValueOptions = parameterOptions(parameter);
976
986
  const examples = exampleOptions(parameter);
977
987
  const selectedExample = (_a = examples === null || examples === void 0 ? void 0 : examples.find(e => e.value === value)) !== null && _a !== void 0 ? _a : selectExampleOption;
@@ -982,10 +992,19 @@ const ParameterEditor = ({ parameter, value, onChange, validate }) => {
982
992
  React.createElement(Text, { mx: 3 }, ":"),
983
993
  React.createElement("div", null, parameterValueOptions ? (React.createElement(Select, { flex: 1, "aria-label": parameter.name, options: parameterValueOptions, value: value || '', onChange: onChange })) : (React.createElement(Flex, { flex: 1 },
984
994
  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) }),
985
- examples && (React.createElement(Select, { "aria-label": `${parameter.name}-select`, flex: 1, value: selectedExample.value, options: examples, onChange: onChange })))))));
995
+ examples && (React.createElement(Select, { "aria-label": `${parameter.name}-select`, flex: 1, value: selectedExample.value, options: examples, onChange: onChange }))))),
996
+ canChangeOptional && !parameter.required && (React.createElement(React.Fragment, null,
997
+ React.createElement("div", null),
998
+ React.createElement("div", null),
999
+ React.createElement("div", null,
1000
+ React.createElement(Flex, { flex: 1 },
1001
+ React.createElement(Input, { className: "Checkbox", "aria-label": `${parameter.name}-checkbox`, id: inputCheckId, flex: 1, type: "checkbox", intent: "success", size: "sm", checked: isOptional, onChange: e => onChangeOptional(!e.target.checked) }),
1002
+ React.createElement(Text, { className: "TextForCheckBox", flex: 1, as: "label", "aria-hidden": "true", "data-testid": "param-check", htmlFor: inputCheckId, fontSize: "base" },
1003
+ "Omit ",
1004
+ parameterDisplayName)))))));
986
1005
  };
987
1006
 
988
- const FormDataBody = ({ specification, values, onChangeValues }) => {
1007
+ const FormDataBody = ({ specification, values, onChangeValues, onChangeParameterAllow, isAllowedEmptyValues, }) => {
989
1008
  const schema = specification.schema;
990
1009
  const parameters = schema === null || schema === void 0 ? void 0 : schema.properties;
991
1010
  const required = schema === null || schema === void 0 ? void 0 : schema.required;
@@ -1000,6 +1019,7 @@ const FormDataBody = ({ specification, values, onChangeValues }) => {
1000
1019
  return (React.createElement(Panel, { defaultIsOpen: true },
1001
1020
  React.createElement(Panel.Titlebar, null, "Body"),
1002
1021
  React.createElement(Panel.Content, { className: "sl-overflow-y-auto ParameterGrid OperationParametersContent" }, mapSchemaPropertiesToParameters(parameters, required).map(parameter => {
1022
+ var _a;
1003
1023
  const supportsFileUpload = parameterSupportsFileUpload(parameter);
1004
1024
  const value = values[parameter.name];
1005
1025
  if (supportsFileUpload) {
@@ -1007,7 +1027,7 @@ const FormDataBody = ({ specification, values, onChangeValues }) => {
1007
1027
  ? onChangeValues(Object.assign(Object.assign({}, values), { [parameter.name]: newValue }))
1008
1028
  : onChangeValues(omit(values, parameter.name)) }));
1009
1029
  }
1010
- return (React.createElement(ParameterEditor, { key: parameter.name, parameter: parameter, value: typeof value === 'string' ? value : undefined, onChange: (value) => onChangeValues(Object.assign(Object.assign({}, values), { [parameter.name]: typeof value === 'number' ? String(value) : value })) }));
1030
+ return (React.createElement(ParameterEditor, { key: parameter.name, parameter: parameter, value: typeof value === 'string' ? value : undefined, onChange: (value) => onChangeValues(Object.assign(Object.assign({}, values), { [parameter.name]: typeof value === 'number' ? String(value) : value })), onChangeOptional: value => onChangeParameterAllow(Object.assign(Object.assign({}, isAllowedEmptyValues), { [parameter.name]: value })), canChangeOptional: true, isOptional: (_a = isAllowedEmptyValues[parameter.name]) !== null && _a !== void 0 ? _a : false }));
1011
1031
  }))));
1012
1032
  };
1013
1033
 
@@ -1081,6 +1101,7 @@ const useBodyParameterState = (mediaTypeContent) => {
1081
1101
  return initialParameterValues(parameters);
1082
1102
  }, [isFormDataBody, mediaTypeContent]);
1083
1103
  const [bodyParameterValues, setBodyParameterValues] = React.useState(initialState);
1104
+ const [isAllowedEmptyValue, setAllowedEmptyValue] = React.useState({});
1084
1105
  React.useEffect(() => {
1085
1106
  setBodyParameterValues(initialState);
1086
1107
  }, [initialState]);
@@ -1088,6 +1109,8 @@ const useBodyParameterState = (mediaTypeContent) => {
1088
1109
  return [
1089
1110
  bodyParameterValues,
1090
1111
  setBodyParameterValues,
1112
+ isAllowedEmptyValue,
1113
+ setAllowedEmptyValue,
1091
1114
  { isFormDataBody: true, bodySpecification: mediaTypeContent },
1092
1115
  ];
1093
1116
  }
@@ -1095,6 +1118,8 @@ const useBodyParameterState = (mediaTypeContent) => {
1095
1118
  return [
1096
1119
  bodyParameterValues,
1097
1120
  setBodyParameterValues,
1121
+ isAllowedEmptyValue,
1122
+ setAllowedEmptyValue,
1098
1123
  { isFormDataBody: false, bodySpecification: undefined },
1099
1124
  ];
1100
1125
  }
@@ -1231,14 +1256,14 @@ function buildFetchRequest({ httpOperation, mediaTypeContent, bodyInput, paramet
1231
1256
  .filter(({ value }) => value.length > 0);
1232
1257
  const [queryParamsWithAuth, headersWithAuth] = runAuthRequestEhancements(auth, queryParams, rawHeaders);
1233
1258
  const expandedPath = uriExpand(httpOperation.path, parameterValues);
1234
- const url = new URL(URI(serverUrl).segment(expandedPath).toString());
1235
- url.search = new URLSearchParams(queryParamsWithAuth.map(nameAndValueObjectToPair)).toString();
1259
+ const urlObject = new URL(serverUrl + expandedPath);
1260
+ urlObject.search = new URLSearchParams(queryParamsWithAuth.map(nameAndValueObjectToPair)).toString();
1236
1261
  const body = typeof bodyInput === 'object' ? yield createRequestBody(mediaTypeContent, bodyInput) : bodyInput;
1237
1262
  const headers = Object.assign(Object.assign(Object.assign({}, ((mediaTypeContent === null || mediaTypeContent === void 0 ? void 0 : mediaTypeContent.mediaType) !== 'multipart/form-data' && {
1238
1263
  'Content-Type': (_f = mediaTypeContent === null || mediaTypeContent === void 0 ? void 0 : mediaTypeContent.mediaType) !== null && _f !== void 0 ? _f : 'application/json',
1239
1264
  })), Object.fromEntries(headersWithAuth.map(nameAndValueObjectToPair))), mockData === null || mockData === void 0 ? void 0 : mockData.header);
1240
1265
  return [
1241
- url.toString(),
1266
+ urlObject.href,
1242
1267
  {
1243
1268
  credentials,
1244
1269
  method: httpOperation.method.toUpperCase(),
@@ -1306,7 +1331,8 @@ function buildHarRequest({ httpOperation, bodyInput, parameterValues, mediaTypeC
1306
1331
  headerParams.push({ name: 'Prefer', value: mockData.header.Prefer });
1307
1332
  }
1308
1333
  const [queryParamsWithAuth, headerParamsWithAuth] = runAuthRequestEhancements(auth, queryParams, headerParams);
1309
- const extendedPath = uriExpand(httpOperation.path, parameterValues);
1334
+ const expandedPath = uriExpand(httpOperation.path, parameterValues);
1335
+ const urlObject = new URL(serverUrl + expandedPath);
1310
1336
  let postData = undefined;
1311
1337
  if (shouldIncludeBody && typeof bodyInput === 'string') {
1312
1338
  postData = { mimeType, text: bodyInput };
@@ -1331,7 +1357,7 @@ function buildHarRequest({ httpOperation, bodyInput, parameterValues, mediaTypeC
1331
1357
  }
1332
1358
  return {
1333
1359
  method: httpOperation.method.toUpperCase(),
1334
- url: URI(serverUrl).segment(extendedPath).toString(),
1360
+ url: urlObject.href,
1335
1361
  httpVersion: 'HTTP/1.1',
1336
1362
  cookies: [],
1337
1363
  headers: [{ name: 'Content-Type', value: mimeType }, ...headerParamsWithAuth],
@@ -1465,7 +1491,7 @@ const useMockingOptions = () => useAtom(mockingOptionsAtom);
1465
1491
  const OperationParameters = ({ parameters, values, onChangeValue, validate, }) => {
1466
1492
  return (React.createElement(Panel, { defaultIsOpen: true },
1467
1493
  React.createElement(Panel.Titlebar, null, "Parameters"),
1468
- React.createElement(Panel.Content, { className: "sl-overflow-y-auto ParameterGrid OperationParametersContent" }, parameters.map(parameter => (React.createElement(ParameterEditor, { key: parameter.name, parameter: parameter, value: values[parameter.name], onChange: (value) => onChangeValue(parameter.name, String(value)), validate: validate }))))));
1494
+ React.createElement(Panel.Content, { className: "sl-overflow-y-auto ParameterGrid OperationParametersContent" }, parameters.map(parameter => (React.createElement(ParameterEditor, { key: parameter.name, parameter: parameter, value: values[parameter.name], onChange: (value) => onChangeValue(parameter.name, String(value)), validate: validate, isOptional: false, canChangeOptional: false, onChangeOptional: () => { } }))))));
1469
1495
  };
1470
1496
 
1471
1497
  const persistedParameterValuesAtom = atom({});
@@ -1617,6 +1643,7 @@ ServersDropdown.displayName = 'ServersDropdown';
1617
1643
  const defaultServers = [];
1618
1644
  const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embeddedInMd = false, tryItCredentialsPolicy, corsProxy, }) => {
1619
1645
  var _a, _b, _c, _d, _e, _f, _g;
1646
+ TryIt.displayName = 'TryIt';
1620
1647
  const isDark = useThemeIsDark();
1621
1648
  const [response, setResponse] = React.useState();
1622
1649
  const [requestData, setRequestData] = React.useState();
@@ -1625,7 +1652,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
1625
1652
  const mediaTypeContent = (_c = (_b = (_a = httpOperation.request) === null || _a === void 0 ? void 0 : _a.body) === null || _b === void 0 ? void 0 : _b.contents) === null || _c === void 0 ? void 0 : _c[requestBodyIndex !== null && requestBodyIndex !== void 0 ? requestBodyIndex : 0];
1626
1653
  const { allParameters, updateParameterValue, parameterValuesWithDefaults } = useRequestParameters(httpOperation);
1627
1654
  const [mockingOptions, setMockingOptions] = useMockingOptions();
1628
- const [bodyParameterValues, setBodyParameterValues, formDataState] = useBodyParameterState(mediaTypeContent);
1655
+ const [bodyParameterValues, setBodyParameterValues, isAllowedEmptyValues, setAllowedEmptyValues, formDataState] = useBodyParameterState(mediaTypeContent);
1629
1656
  const [textRequestBody, setTextRequestBody] = useTextRequestBodyState(mediaTypeContent);
1630
1657
  const [operationAuthValue, setOperationAuthValue] = usePersistedSecuritySchemeWithValues();
1631
1658
  const servers = React.useMemo(() => {
@@ -1636,6 +1663,12 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
1636
1663
  const [chosenServer, setChosenServer] = useAtom(chosenServerAtom);
1637
1664
  const isMockingEnabled = mockUrl && (chosenServer === null || chosenServer === void 0 ? void 0 : chosenServer.url) === mockUrl;
1638
1665
  const hasRequiredButEmptyParameters = allParameters.some(parameter => parameter.required && !parameterValuesWithDefaults[parameter.name]);
1666
+ const getValues = () => Object.keys(bodyParameterValues)
1667
+ .filter(param => { var _a; return (_a = !isAllowedEmptyValues[param]) !== null && _a !== void 0 ? _a : true; })
1668
+ .reduce((previousValue, currentValue) => {
1669
+ previousValue[currentValue] = bodyParameterValues[currentValue];
1670
+ return previousValue;
1671
+ }, {});
1639
1672
  React.useEffect(() => {
1640
1673
  const currentUrl = chosenServer === null || chosenServer === void 0 ? void 0 : chosenServer.url;
1641
1674
  const exists = currentUrl && servers.find(s => s.url === currentUrl);
@@ -1649,7 +1682,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
1649
1682
  React.useEffect(() => {
1650
1683
  let isMounted = true;
1651
1684
  if (onRequestChange || embeddedInMd) {
1652
- buildHarRequest(Object.assign(Object.assign({ mediaTypeContent, parameterValues: parameterValuesWithDefaults, httpOperation, bodyInput: formDataState.isFormDataBody ? bodyParameterValues : textRequestBody, auth: operationAuthValue }, (isMockingEnabled && { mockData: getMockData(mockUrl, httpOperation, mockingOptions) })), { chosenServer,
1685
+ buildHarRequest(Object.assign(Object.assign({ mediaTypeContent, parameterValues: parameterValuesWithDefaults, httpOperation, bodyInput: formDataState.isFormDataBody ? getValues() : textRequestBody, auth: operationAuthValue }, (isMockingEnabled && { mockData: getMockData(mockUrl, httpOperation, mockingOptions) })), { chosenServer,
1653
1686
  corsProxy })).then(request => {
1654
1687
  if (isMounted) {
1655
1688
  if (onRequestChange) {
@@ -1669,6 +1702,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
1669
1702
  parameterValuesWithDefaults,
1670
1703
  formDataState.isFormDataBody,
1671
1704
  bodyParameterValues,
1705
+ isAllowedEmptyValues,
1672
1706
  textRequestBody,
1673
1707
  operationAuthValue,
1674
1708
  mockingOptions,
@@ -1687,7 +1721,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
1687
1721
  parameterValues: parameterValuesWithDefaults,
1688
1722
  httpOperation,
1689
1723
  mediaTypeContent,
1690
- bodyInput: formDataState.isFormDataBody ? bodyParameterValues : textRequestBody,
1724
+ bodyInput: formDataState.isFormDataBody ? getValues() : textRequestBody,
1691
1725
  mockData,
1692
1726
  auth: operationAuthValue,
1693
1727
  chosenServer,
@@ -1723,7 +1757,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
1723
1757
  const tryItPanelContents = (React.createElement(React.Fragment, null,
1724
1758
  ((_e = httpOperation.security) === null || _e === void 0 ? void 0 : _e.length) ? (React.createElement(TryItAuth, { onChange: setOperationAuthValue, operationSecurityScheme: (_f = httpOperation.security) !== null && _f !== void 0 ? _f : [], value: operationAuthValue })) : null,
1725
1759
  allParameters.length > 0 && (React.createElement(OperationParameters, { parameters: allParameters, values: parameterValuesWithDefaults, onChangeValue: updateParameterValue, validate: validateParameters })),
1726
- formDataState.isFormDataBody ? (React.createElement(FormDataBody, { specification: formDataState.bodySpecification, values: bodyParameterValues, onChangeValues: setBodyParameterValues })) : mediaTypeContent ? (React.createElement(RequestBody, { examples: (_g = mediaTypeContent.examples) !== null && _g !== void 0 ? _g : [], requestBody: textRequestBody, onChange: setTextRequestBody })) : null,
1760
+ formDataState.isFormDataBody ? (React.createElement(FormDataBody, { specification: formDataState.bodySpecification, values: bodyParameterValues, onChangeValues: setBodyParameterValues, onChangeParameterAllow: setAllowedEmptyValues, isAllowedEmptyValues: isAllowedEmptyValues })) : mediaTypeContent ? (React.createElement(RequestBody, { examples: (_g = mediaTypeContent.examples) !== null && _g !== void 0 ? _g : [], requestBody: textRequestBody, onChange: setTextRequestBody })) : null,
1727
1761
  React.createElement(Panel.Content, { className: "SendButtonHolder", mt: 4, pt: !isOnlySendButton && !embeddedInMd ? 0 : undefined },
1728
1762
  React.createElement(HStack, { alignItems: "center", spacing: 2 },
1729
1763
  React.createElement(Button, { appearance: "primary", loading: loading, disabled: loading, onPress: handleSendRequest, size: "sm" }, "Send API Request"),
@@ -2295,7 +2329,7 @@ const SidebarLayout = React.forwardRef(({ sidebar, children, maxContentWidth = M
2295
2329
  paddingLeft: `calc((100% - ${maxContentWidth}px) / 2)`,
2296
2330
  minWidth: `${sidebarWidth}px`,
2297
2331
  } }, sidebar),
2298
- React.createElement(Box, { ref: scrollRef, bg: "canvas", px: 24, flex: 1, w: "full" },
2332
+ React.createElement(Box, { ref: scrollRef, bg: "canvas", px: 24, flex: 1, w: "full", overflowY: "auto" },
2299
2333
  React.createElement(Box, { style: { maxWidth: `${maxContentWidth - sidebarWidth}px` }, py: 16 }, children))));
2300
2334
  });
2301
2335
 
@@ -2350,8 +2384,8 @@ const SchemaAndDescription = ({ title: titleProp, schema }) => {
2350
2384
  React__default.createElement(JsonSchemaViewer, { resolveRef: resolveRef, schema: getOriginalObject(schema) })));
2351
2385
  };
2352
2386
  const CodeComponent = props => {
2353
- const { title, jsonSchema, http, children } = props;
2354
- const value = String(Array.isArray(children) ? children[0] : children);
2387
+ const { title, jsonSchema, http, resolved, children } = props;
2388
+ const value = resolved || String(Array.isArray(children) ? children[0] : children);
2355
2389
  const parsedValue = useParsedValue(value);
2356
2390
  if (jsonSchema) {
2357
2391
  if (!isJSONSchema(parsedValue)) {
package/index.js CHANGED
@@ -195,9 +195,9 @@ function isHttpService(maybeHttpService) {
195
195
  function isHttpOperation(maybeHttpOperation) {
196
196
  return isStoplightNode(maybeHttpOperation) && 'method' in maybeHttpOperation && 'path' in maybeHttpOperation;
197
197
  }
198
+ const properUrl = new RegExp(/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?)/);
198
199
  function isProperUrl(url) {
199
- const properUrl = new RegExp(/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?)/);
200
- return url.match(properUrl);
200
+ return properUrl.test(url);
201
201
  }
202
202
 
203
203
  function useParsedData(nodeType, data) {
@@ -411,13 +411,16 @@ function createNamedContext(name, defaultValue) {
411
411
 
412
412
  const chosenServerAtom = jotai.atom(undefined);
413
413
 
414
+ function isValidServer(server) {
415
+ return server.url !== null && isProperUrl(server.url);
416
+ }
414
417
  const getServersToDisplay = (originalServers, mockUrl) => {
415
418
  const servers = originalServers
416
419
  .map((server, i) => {
417
420
  const fallbackDescription = originalServers.length === 1 ? 'Live Server' : `Server ${i + 1}`;
418
421
  return Object.assign(Object.assign({}, server), { url: getServerUrlWithDefaultValues(server), description: server.description || fallbackDescription });
419
422
  })
420
- .filter(server => isProperUrl(server.url));
423
+ .filter(isValidServer);
421
424
  if (mockUrl) {
422
425
  servers.push({
423
426
  description: 'Mock Server',
@@ -433,7 +436,13 @@ const getServerUrlWithDefaultValues = (server) => {
433
436
  variables.forEach(([variableName, variableInfo]) => {
434
437
  urlString = urlString.replace(`{${variableName}}`, variableInfo.default);
435
438
  });
436
- let url = URI__default["default"](urlString);
439
+ let url;
440
+ try {
441
+ url = URI__default["default"](urlString);
442
+ }
443
+ catch (_b) {
444
+ return null;
445
+ }
437
446
  if (url.is('relative') && typeof window !== 'undefined') {
438
447
  url = url.absoluteTo(window.location.origin);
439
448
  }
@@ -1023,9 +1032,10 @@ function mapSchemaPropertiesToParameters(properties, required) {
1023
1032
  return Object.entries(properties).map(([name, schema]) => (Object.assign({ name, schema: typeof schema !== 'boolean' ? schema : undefined, examples: typeof schema !== 'boolean' && schema.examples ? [{ key: 'example', value: schema.examples }] : undefined }, ((required === null || required === void 0 ? void 0 : required.includes(name)) && { required: true }))));
1024
1033
  }
1025
1034
 
1026
- const ParameterEditor = ({ parameter, value, onChange, validate }) => {
1035
+ const ParameterEditor = ({ parameter, value, onChange, isOptional, onChangeOptional, canChangeOptional, validate, }) => {
1027
1036
  var _a, _b;
1028
1037
  const inputId = useUniqueId(`id_${parameter.name}_`);
1038
+ const inputCheckId = useUniqueId(`id_${parameter.name}_checked`);
1029
1039
  const parameterValueOptions = parameterOptions(parameter);
1030
1040
  const examples = exampleOptions(parameter);
1031
1041
  const selectedExample = (_a = examples === null || examples === void 0 ? void 0 : examples.find(e => e.value === value)) !== null && _a !== void 0 ? _a : selectExampleOption;
@@ -1036,10 +1046,19 @@ const ParameterEditor = ({ parameter, value, onChange, validate }) => {
1036
1046
  React__namespace.createElement(mosaic.Text, { mx: 3 }, ":"),
1037
1047
  React__namespace.createElement("div", null, parameterValueOptions ? (React__namespace.createElement(mosaic.Select, { flex: 1, "aria-label": parameter.name, options: parameterValueOptions, value: value || '', onChange: onChange })) : (React__namespace.createElement(mosaic.Flex, { flex: 1 },
1038
1048
  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) }),
1039
- examples && (React__namespace.createElement(mosaic.Select, { "aria-label": `${parameter.name}-select`, flex: 1, value: selectedExample.value, options: examples, onChange: onChange })))))));
1049
+ examples && (React__namespace.createElement(mosaic.Select, { "aria-label": `${parameter.name}-select`, flex: 1, value: selectedExample.value, options: examples, onChange: onChange }))))),
1050
+ canChangeOptional && !parameter.required && (React__namespace.createElement(React__namespace.Fragment, null,
1051
+ React__namespace.createElement("div", null),
1052
+ React__namespace.createElement("div", null),
1053
+ React__namespace.createElement("div", null,
1054
+ React__namespace.createElement(mosaic.Flex, { flex: 1 },
1055
+ React__namespace.createElement(mosaic.Input, { className: "Checkbox", "aria-label": `${parameter.name}-checkbox`, id: inputCheckId, flex: 1, type: "checkbox", intent: "success", size: "sm", checked: isOptional, onChange: e => onChangeOptional(!e.target.checked) }),
1056
+ React__namespace.createElement(mosaic.Text, { className: "TextForCheckBox", flex: 1, as: "label", "aria-hidden": "true", "data-testid": "param-check", htmlFor: inputCheckId, fontSize: "base" },
1057
+ "Omit ",
1058
+ parameterDisplayName)))))));
1040
1059
  };
1041
1060
 
1042
- const FormDataBody = ({ specification, values, onChangeValues }) => {
1061
+ const FormDataBody = ({ specification, values, onChangeValues, onChangeParameterAllow, isAllowedEmptyValues, }) => {
1043
1062
  const schema = specification.schema;
1044
1063
  const parameters = schema === null || schema === void 0 ? void 0 : schema.properties;
1045
1064
  const required = schema === null || schema === void 0 ? void 0 : schema.required;
@@ -1054,6 +1073,7 @@ const FormDataBody = ({ specification, values, onChangeValues }) => {
1054
1073
  return (React__namespace.createElement(mosaic.Panel, { defaultIsOpen: true },
1055
1074
  React__namespace.createElement(mosaic.Panel.Titlebar, null, "Body"),
1056
1075
  React__namespace.createElement(mosaic.Panel.Content, { className: "sl-overflow-y-auto ParameterGrid OperationParametersContent" }, mapSchemaPropertiesToParameters(parameters, required).map(parameter => {
1076
+ var _a;
1057
1077
  const supportsFileUpload = parameterSupportsFileUpload(parameter);
1058
1078
  const value = values[parameter.name];
1059
1079
  if (supportsFileUpload) {
@@ -1061,7 +1081,7 @@ const FormDataBody = ({ specification, values, onChangeValues }) => {
1061
1081
  ? onChangeValues(Object.assign(Object.assign({}, values), { [parameter.name]: newValue }))
1062
1082
  : onChangeValues(omit__default["default"](values, parameter.name)) }));
1063
1083
  }
1064
- return (React__namespace.createElement(ParameterEditor, { key: parameter.name, parameter: parameter, value: typeof value === 'string' ? value : undefined, onChange: (value) => onChangeValues(Object.assign(Object.assign({}, values), { [parameter.name]: typeof value === 'number' ? String(value) : value })) }));
1084
+ return (React__namespace.createElement(ParameterEditor, { key: parameter.name, parameter: parameter, value: typeof value === 'string' ? value : undefined, onChange: (value) => onChangeValues(Object.assign(Object.assign({}, values), { [parameter.name]: typeof value === 'number' ? String(value) : value })), onChangeOptional: value => onChangeParameterAllow(Object.assign(Object.assign({}, isAllowedEmptyValues), { [parameter.name]: value })), canChangeOptional: true, isOptional: (_a = isAllowedEmptyValues[parameter.name]) !== null && _a !== void 0 ? _a : false }));
1065
1085
  }))));
1066
1086
  };
1067
1087
 
@@ -1135,6 +1155,7 @@ const useBodyParameterState = (mediaTypeContent) => {
1135
1155
  return initialParameterValues(parameters);
1136
1156
  }, [isFormDataBody, mediaTypeContent]);
1137
1157
  const [bodyParameterValues, setBodyParameterValues] = React__namespace.useState(initialState);
1158
+ const [isAllowedEmptyValue, setAllowedEmptyValue] = React__namespace.useState({});
1138
1159
  React__namespace.useEffect(() => {
1139
1160
  setBodyParameterValues(initialState);
1140
1161
  }, [initialState]);
@@ -1142,6 +1163,8 @@ const useBodyParameterState = (mediaTypeContent) => {
1142
1163
  return [
1143
1164
  bodyParameterValues,
1144
1165
  setBodyParameterValues,
1166
+ isAllowedEmptyValue,
1167
+ setAllowedEmptyValue,
1145
1168
  { isFormDataBody: true, bodySpecification: mediaTypeContent },
1146
1169
  ];
1147
1170
  }
@@ -1149,6 +1172,8 @@ const useBodyParameterState = (mediaTypeContent) => {
1149
1172
  return [
1150
1173
  bodyParameterValues,
1151
1174
  setBodyParameterValues,
1175
+ isAllowedEmptyValue,
1176
+ setAllowedEmptyValue,
1152
1177
  { isFormDataBody: false, bodySpecification: undefined },
1153
1178
  ];
1154
1179
  }
@@ -1285,14 +1310,14 @@ function buildFetchRequest({ httpOperation, mediaTypeContent, bodyInput, paramet
1285
1310
  .filter(({ value }) => value.length > 0);
1286
1311
  const [queryParamsWithAuth, headersWithAuth] = runAuthRequestEhancements(auth, queryParams, rawHeaders);
1287
1312
  const expandedPath = uriExpand(httpOperation.path, parameterValues);
1288
- const url = new URL(URI__default["default"](serverUrl).segment(expandedPath).toString());
1289
- url.search = new URLSearchParams(queryParamsWithAuth.map(nameAndValueObjectToPair)).toString();
1313
+ const urlObject = new URL(serverUrl + expandedPath);
1314
+ urlObject.search = new URLSearchParams(queryParamsWithAuth.map(nameAndValueObjectToPair)).toString();
1290
1315
  const body = typeof bodyInput === 'object' ? yield createRequestBody(mediaTypeContent, bodyInput) : bodyInput;
1291
1316
  const headers = Object.assign(Object.assign(Object.assign({}, ((mediaTypeContent === null || mediaTypeContent === void 0 ? void 0 : mediaTypeContent.mediaType) !== 'multipart/form-data' && {
1292
1317
  'Content-Type': (_f = mediaTypeContent === null || mediaTypeContent === void 0 ? void 0 : mediaTypeContent.mediaType) !== null && _f !== void 0 ? _f : 'application/json',
1293
1318
  })), Object.fromEntries(headersWithAuth.map(nameAndValueObjectToPair))), mockData === null || mockData === void 0 ? void 0 : mockData.header);
1294
1319
  return [
1295
- url.toString(),
1320
+ urlObject.href,
1296
1321
  {
1297
1322
  credentials,
1298
1323
  method: httpOperation.method.toUpperCase(),
@@ -1360,7 +1385,8 @@ function buildHarRequest({ httpOperation, bodyInput, parameterValues, mediaTypeC
1360
1385
  headerParams.push({ name: 'Prefer', value: mockData.header.Prefer });
1361
1386
  }
1362
1387
  const [queryParamsWithAuth, headerParamsWithAuth] = runAuthRequestEhancements(auth, queryParams, headerParams);
1363
- const extendedPath = uriExpand(httpOperation.path, parameterValues);
1388
+ const expandedPath = uriExpand(httpOperation.path, parameterValues);
1389
+ const urlObject = new URL(serverUrl + expandedPath);
1364
1390
  let postData = undefined;
1365
1391
  if (shouldIncludeBody && typeof bodyInput === 'string') {
1366
1392
  postData = { mimeType, text: bodyInput };
@@ -1385,7 +1411,7 @@ function buildHarRequest({ httpOperation, bodyInput, parameterValues, mediaTypeC
1385
1411
  }
1386
1412
  return {
1387
1413
  method: httpOperation.method.toUpperCase(),
1388
- url: URI__default["default"](serverUrl).segment(extendedPath).toString(),
1414
+ url: urlObject.href,
1389
1415
  httpVersion: 'HTTP/1.1',
1390
1416
  cookies: [],
1391
1417
  headers: [{ name: 'Content-Type', value: mimeType }, ...headerParamsWithAuth],
@@ -1519,7 +1545,7 @@ const useMockingOptions = () => jotai.useAtom(mockingOptionsAtom);
1519
1545
  const OperationParameters = ({ parameters, values, onChangeValue, validate, }) => {
1520
1546
  return (React__namespace.createElement(mosaic.Panel, { defaultIsOpen: true },
1521
1547
  React__namespace.createElement(mosaic.Panel.Titlebar, null, "Parameters"),
1522
- React__namespace.createElement(mosaic.Panel.Content, { className: "sl-overflow-y-auto ParameterGrid OperationParametersContent" }, parameters.map(parameter => (React__namespace.createElement(ParameterEditor, { key: parameter.name, parameter: parameter, value: values[parameter.name], onChange: (value) => onChangeValue(parameter.name, String(value)), validate: validate }))))));
1548
+ React__namespace.createElement(mosaic.Panel.Content, { className: "sl-overflow-y-auto ParameterGrid OperationParametersContent" }, parameters.map(parameter => (React__namespace.createElement(ParameterEditor, { key: parameter.name, parameter: parameter, value: values[parameter.name], onChange: (value) => onChangeValue(parameter.name, String(value)), validate: validate, isOptional: false, canChangeOptional: false, onChangeOptional: () => { } }))))));
1523
1549
  };
1524
1550
 
1525
1551
  const persistedParameterValuesAtom = jotai.atom({});
@@ -1671,6 +1697,7 @@ ServersDropdown.displayName = 'ServersDropdown';
1671
1697
  const defaultServers = [];
1672
1698
  const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embeddedInMd = false, tryItCredentialsPolicy, corsProxy, }) => {
1673
1699
  var _a, _b, _c, _d, _e, _f, _g;
1700
+ TryIt.displayName = 'TryIt';
1674
1701
  const isDark = mosaic.useThemeIsDark();
1675
1702
  const [response, setResponse] = React__namespace.useState();
1676
1703
  const [requestData, setRequestData] = React__namespace.useState();
@@ -1679,7 +1706,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
1679
1706
  const mediaTypeContent = (_c = (_b = (_a = httpOperation.request) === null || _a === void 0 ? void 0 : _a.body) === null || _b === void 0 ? void 0 : _b.contents) === null || _c === void 0 ? void 0 : _c[requestBodyIndex !== null && requestBodyIndex !== void 0 ? requestBodyIndex : 0];
1680
1707
  const { allParameters, updateParameterValue, parameterValuesWithDefaults } = useRequestParameters(httpOperation);
1681
1708
  const [mockingOptions, setMockingOptions] = useMockingOptions();
1682
- const [bodyParameterValues, setBodyParameterValues, formDataState] = useBodyParameterState(mediaTypeContent);
1709
+ const [bodyParameterValues, setBodyParameterValues, isAllowedEmptyValues, setAllowedEmptyValues, formDataState] = useBodyParameterState(mediaTypeContent);
1683
1710
  const [textRequestBody, setTextRequestBody] = useTextRequestBodyState(mediaTypeContent);
1684
1711
  const [operationAuthValue, setOperationAuthValue] = usePersistedSecuritySchemeWithValues();
1685
1712
  const servers = React__namespace.useMemo(() => {
@@ -1690,6 +1717,12 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
1690
1717
  const [chosenServer, setChosenServer] = jotai.useAtom(chosenServerAtom);
1691
1718
  const isMockingEnabled = mockUrl && (chosenServer === null || chosenServer === void 0 ? void 0 : chosenServer.url) === mockUrl;
1692
1719
  const hasRequiredButEmptyParameters = allParameters.some(parameter => parameter.required && !parameterValuesWithDefaults[parameter.name]);
1720
+ const getValues = () => Object.keys(bodyParameterValues)
1721
+ .filter(param => { var _a; return (_a = !isAllowedEmptyValues[param]) !== null && _a !== void 0 ? _a : true; })
1722
+ .reduce((previousValue, currentValue) => {
1723
+ previousValue[currentValue] = bodyParameterValues[currentValue];
1724
+ return previousValue;
1725
+ }, {});
1693
1726
  React__namespace.useEffect(() => {
1694
1727
  const currentUrl = chosenServer === null || chosenServer === void 0 ? void 0 : chosenServer.url;
1695
1728
  const exists = currentUrl && servers.find(s => s.url === currentUrl);
@@ -1703,7 +1736,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
1703
1736
  React__namespace.useEffect(() => {
1704
1737
  let isMounted = true;
1705
1738
  if (onRequestChange || embeddedInMd) {
1706
- buildHarRequest(Object.assign(Object.assign({ mediaTypeContent, parameterValues: parameterValuesWithDefaults, httpOperation, bodyInput: formDataState.isFormDataBody ? bodyParameterValues : textRequestBody, auth: operationAuthValue }, (isMockingEnabled && { mockData: getMockData(mockUrl, httpOperation, mockingOptions) })), { chosenServer,
1739
+ buildHarRequest(Object.assign(Object.assign({ mediaTypeContent, parameterValues: parameterValuesWithDefaults, httpOperation, bodyInput: formDataState.isFormDataBody ? getValues() : textRequestBody, auth: operationAuthValue }, (isMockingEnabled && { mockData: getMockData(mockUrl, httpOperation, mockingOptions) })), { chosenServer,
1707
1740
  corsProxy })).then(request => {
1708
1741
  if (isMounted) {
1709
1742
  if (onRequestChange) {
@@ -1723,6 +1756,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
1723
1756
  parameterValuesWithDefaults,
1724
1757
  formDataState.isFormDataBody,
1725
1758
  bodyParameterValues,
1759
+ isAllowedEmptyValues,
1726
1760
  textRequestBody,
1727
1761
  operationAuthValue,
1728
1762
  mockingOptions,
@@ -1741,7 +1775,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
1741
1775
  parameterValues: parameterValuesWithDefaults,
1742
1776
  httpOperation,
1743
1777
  mediaTypeContent,
1744
- bodyInput: formDataState.isFormDataBody ? bodyParameterValues : textRequestBody,
1778
+ bodyInput: formDataState.isFormDataBody ? getValues() : textRequestBody,
1745
1779
  mockData,
1746
1780
  auth: operationAuthValue,
1747
1781
  chosenServer,
@@ -1777,7 +1811,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
1777
1811
  const tryItPanelContents = (React__namespace.createElement(React__namespace.Fragment, null,
1778
1812
  ((_e = httpOperation.security) === null || _e === void 0 ? void 0 : _e.length) ? (React__namespace.createElement(TryItAuth, { onChange: setOperationAuthValue, operationSecurityScheme: (_f = httpOperation.security) !== null && _f !== void 0 ? _f : [], value: operationAuthValue })) : null,
1779
1813
  allParameters.length > 0 && (React__namespace.createElement(OperationParameters, { parameters: allParameters, values: parameterValuesWithDefaults, onChangeValue: updateParameterValue, validate: validateParameters })),
1780
- formDataState.isFormDataBody ? (React__namespace.createElement(FormDataBody, { specification: formDataState.bodySpecification, values: bodyParameterValues, onChangeValues: setBodyParameterValues })) : mediaTypeContent ? (React__namespace.createElement(RequestBody, { examples: (_g = mediaTypeContent.examples) !== null && _g !== void 0 ? _g : [], requestBody: textRequestBody, onChange: setTextRequestBody })) : null,
1814
+ formDataState.isFormDataBody ? (React__namespace.createElement(FormDataBody, { specification: formDataState.bodySpecification, values: bodyParameterValues, onChangeValues: setBodyParameterValues, onChangeParameterAllow: setAllowedEmptyValues, isAllowedEmptyValues: isAllowedEmptyValues })) : mediaTypeContent ? (React__namespace.createElement(RequestBody, { examples: (_g = mediaTypeContent.examples) !== null && _g !== void 0 ? _g : [], requestBody: textRequestBody, onChange: setTextRequestBody })) : null,
1781
1815
  React__namespace.createElement(mosaic.Panel.Content, { className: "SendButtonHolder", mt: 4, pt: !isOnlySendButton && !embeddedInMd ? 0 : undefined },
1782
1816
  React__namespace.createElement(mosaic.HStack, { alignItems: "center", spacing: 2 },
1783
1817
  React__namespace.createElement(mosaic.Button, { appearance: "primary", loading: loading, disabled: loading, onPress: handleSendRequest, size: "sm" }, "Send API Request"),
@@ -2349,7 +2383,7 @@ const SidebarLayout = React__namespace.forwardRef(({ sidebar, children, maxConte
2349
2383
  paddingLeft: `calc((100% - ${maxContentWidth}px) / 2)`,
2350
2384
  minWidth: `${sidebarWidth}px`,
2351
2385
  } }, sidebar),
2352
- React__namespace.createElement(mosaic.Box, { ref: scrollRef, bg: "canvas", px: 24, flex: 1, w: "full" },
2386
+ React__namespace.createElement(mosaic.Box, { ref: scrollRef, bg: "canvas", px: 24, flex: 1, w: "full", overflowY: "auto" },
2353
2387
  React__namespace.createElement(mosaic.Box, { style: { maxWidth: `${maxContentWidth - sidebarWidth}px` }, py: 16 }, children))));
2354
2388
  });
2355
2389
 
@@ -2404,8 +2438,8 @@ const SchemaAndDescription = ({ title: titleProp, schema }) => {
2404
2438
  React__default["default"].createElement(jsonSchemaViewer.JsonSchemaViewer, { resolveRef: resolveRef, schema: getOriginalObject(schema) })));
2405
2439
  };
2406
2440
  const CodeComponent = props => {
2407
- const { title, jsonSchema, http, children } = props;
2408
- const value = String(Array.isArray(children) ? children[0] : children);
2441
+ const { title, jsonSchema, http, resolved, children } = props;
2442
+ const value = resolved || String(Array.isArray(children) ? children[0] : children);
2409
2443
  const parsedValue = useParsedValue(value);
2410
2444
  if (jsonSchema) {
2411
2445
  if (!isJSONSchema(parsedValue)) {