@stoplight/elements-core 7.13.9 → 7.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ import { IHttpOperation } from '@stoplight/types';
2
+ export declare const httpOperation: IHttpOperation;
3
+ export default httpOperation;
@@ -1,7 +1,8 @@
1
+ import { Choice } from '@stoplight/json-schema-viewer';
1
2
  import { IMediaTypeContent } from '@stoplight/types';
2
3
  import * as React from 'react';
3
4
  import { BodyParameterValues, ParameterOptional } from './request-body-utils';
4
- interface FormDataBodyProps {
5
+ export interface FormDataBodyProps {
5
6
  specification: IMediaTypeContent;
6
7
  values: BodyParameterValues;
7
8
  onChangeValues: (newValues: BodyParameterValues) => void;
@@ -9,4 +10,9 @@ interface FormDataBodyProps {
9
10
  isAllowedEmptyValues: ParameterOptional;
10
11
  }
11
12
  export declare const FormDataBody: React.FC<FormDataBodyProps>;
12
- export {};
13
+ export interface OneOfMenuProps {
14
+ choices: Choice[];
15
+ choice: Choice;
16
+ onChange: (choice: Choice) => void;
17
+ }
18
+ export declare function OneOfMenu({ choices: subSchemas, choice, onChange }: OneOfMenuProps): JSX.Element | null;
@@ -1,5 +1,6 @@
1
+ import { RegularNode, SchemaNode } from '@stoplight/json-schema-tree';
1
2
  import type { IHttpParam, INodeExample, INodeExternalExample } from '@stoplight/types';
2
- import { JSONSchema7Definition } from 'json-schema';
3
+ import { JSONSchema7, JSONSchema7Definition } from 'json-schema';
3
4
  export declare type ParameterSpec = Pick<IHttpParam, 'name' | 'schema' | 'required'> & {
4
5
  examples?: (Omit<INodeExample, 'id'> | Omit<INodeExternalExample, 'id'>)[];
5
6
  };
@@ -17,7 +18,7 @@ export declare function exampleOptions(parameter: ParameterSpec): {
17
18
  value: string;
18
19
  label: string;
19
20
  }[] | null;
20
- export declare function parameterSupportsFileUpload(parameter: Pick<ParameterSpec, 'schema'>): boolean;
21
+ export declare function parameterSupportsFileUpload(parameter?: Pick<ParameterSpec, 'schema'>): boolean | undefined;
21
22
  export declare function getPlaceholderForParameter(parameter: ParameterSpec): string;
22
23
  export declare const initialParameterValues: (params: readonly ParameterSpec[]) => Record<string, string>;
23
24
  export declare function mapSchemaPropertiesToParameters(properties: {
@@ -25,9 +26,11 @@ export declare function mapSchemaPropertiesToParameters(properties: {
25
26
  }, required: string[] | undefined): {
26
27
  required?: boolean | undefined;
27
28
  name: string;
28
- schema: import("json-schema").JSONSchema7 | undefined;
29
+ schema: JSONSchema7 | undefined;
29
30
  examples: {
30
31
  key: string;
31
32
  value: any;
32
33
  }[] | undefined;
33
34
  }[];
35
+ export declare function toParameterSpec(jsonTreeNode: RegularNode): ParameterSpec;
36
+ export declare function isRequired(n: SchemaNode): boolean | undefined;
@@ -6,6 +6,7 @@ export declare const SimpleGET: Story<TryItProps>;
6
6
  export declare const WithParameters: Story<TryItProps>;
7
7
  export declare const WithVariables: Story<TryItProps>;
8
8
  export declare const UrlEncoded: Story<TryItProps>;
9
+ export declare const UrlEncodedOneOf: Story<TryItProps>;
9
10
  export declare const Multipart: Story<TryItProps>;
10
11
  export declare const RequestBodySchema: Story<TryItProps>;
11
12
  export declare const RequestBodyExamples: Story<TryItProps>;
package/index.esm.js CHANGED
@@ -25,8 +25,11 @@ import filter from 'lodash/filter.js';
25
25
  import flatten from 'lodash/flatten.js';
26
26
  import { nanoid } from 'nanoid';
27
27
  import curry from 'lodash/curry.js';
28
+ import { isRegularNode, SchemaTree } from '@stoplight/json-schema-tree';
29
+ import { useChoices, visibleChildren, JsonSchemaViewer } from '@stoplight/json-schema-viewer';
28
30
  import omit from 'lodash/omit.js';
29
31
  import keyBy from 'lodash/keyBy.js';
32
+ import last from 'lodash/last.js';
30
33
  import map from 'lodash/map.js';
31
34
  import mapValues from 'lodash/mapValues.js';
32
35
  import isString from 'lodash/isString.js';
@@ -40,7 +43,6 @@ import uniqBy from 'lodash/uniqBy.js';
40
43
  import formatXml from 'xml-formatter';
41
44
  import entries from 'lodash/entries.js';
42
45
  import keys from 'lodash/keys.js';
43
- import { JsonSchemaViewer } from '@stoplight/json-schema-viewer';
44
46
  import sortBy from 'lodash/sortBy.js';
45
47
  import isEmpty from 'lodash/isEmpty.js';
46
48
  import isNil from 'lodash/isNil.js';
@@ -1176,7 +1178,9 @@ function exampleOptions(parameter) {
1176
1178
  }
1177
1179
  function parameterSupportsFileUpload(parameter) {
1178
1180
  var _a, _b, _c;
1179
- return (((_a = parameter.schema) === null || _a === void 0 ? void 0 : _a.type) === 'string' &&
1181
+ return (parameter &&
1182
+ parameter.schema &&
1183
+ ((_a = parameter.schema) === null || _a === void 0 ? void 0 : _a.type) === 'string' &&
1180
1184
  (((_b = parameter.schema) === null || _b === void 0 ? void 0 : _b.contentEncoding) === 'base64' ||
1181
1185
  ((_c = parameter.schema) === null || _c === void 0 ? void 0 : _c.contentMediaType) === 'application/octet-stream'));
1182
1186
  }
@@ -1232,6 +1236,35 @@ function mapSchemaPropertiesToParameters(properties, required) {
1232
1236
  return Object.entries(properties).map(([name, schema]) => (Object.assign({ name, schema: typeof schema !== 'boolean' ? schema : undefined, examples: typeof schema !== 'boolean' && schema.examples && schema.examples[0]
1233
1237
  ? [{ key: 'example', value: schema.examples[0] }]
1234
1238
  : undefined }, ((required === null || required === void 0 ? void 0 : required.includes(name)) && { required: true }))));
1239
+ }
1240
+ function toParameterSpec(jsonTreeNode) {
1241
+ var _a;
1242
+ const isBoolean = jsonTreeNode.primaryType === 'boolean';
1243
+ const schema = !isBoolean ? jsonTreeNode.fragment : undefined;
1244
+ const examples = !isBoolean && jsonTreeNode.fragment.examples && jsonTreeNode.fragment.examples[0]
1245
+ ? [{ key: 'example', value: jsonTreeNode.fragment.examples[0] }]
1246
+ : undefined;
1247
+ const lastJsonPathSegment = (_a = last(jsonTreeNode.path)) !== null && _a !== void 0 ? _a : '<<UNKNOWN>>';
1248
+ return {
1249
+ name: lastJsonPathSegment,
1250
+ schema,
1251
+ examples,
1252
+ required: isRequired(jsonTreeNode),
1253
+ };
1254
+ }
1255
+ function isRequired(n) {
1256
+ if (!isRegularNode(n)) {
1257
+ return undefined;
1258
+ }
1259
+ const name = last(n.path);
1260
+ if (name === undefined) {
1261
+ return undefined;
1262
+ }
1263
+ const parent = n.parent;
1264
+ if (parent === null || !isRegularNode(parent)) {
1265
+ return undefined;
1266
+ }
1267
+ return parent.required !== null && parent.required.includes(name);
1235
1268
  }
1236
1269
 
1237
1270
  const ParameterEditor = ({ parameter, value, onChange, isOptional, onChangeOptional, canChangeOptional, validate, }) => {
@@ -1261,31 +1294,53 @@ const ParameterEditor = ({ parameter, value, onChange, isOptional, onChangeOptio
1261
1294
  };
1262
1295
 
1263
1296
  const FormDataBody = ({ specification, values, onChangeValues, onChangeParameterAllow, isAllowedEmptyValues, }) => {
1264
- const schema = specification.schema;
1265
- const parameters = schema === null || schema === void 0 ? void 0 : schema.properties;
1266
- const required = schema === null || schema === void 0 ? void 0 : schema.required;
1267
- React.useEffect(() => {
1268
- if (parameters === undefined) {
1269
- console.warn(`Invalid schema in form data spec: ${safeStringify(schema)}`);
1270
- }
1271
- }, [parameters, schema]);
1272
- if (parameters === undefined) {
1273
- return null;
1274
- }
1297
+ const schema = React.useMemo(() => {
1298
+ var _a;
1299
+ const schema = (_a = specification.schema) !== null && _a !== void 0 ? _a : {};
1300
+ const tree = new SchemaTree(schema, { mergeAllOf: true, refResolver: null });
1301
+ tree.populate();
1302
+ return tree.root.children[0];
1303
+ }, [specification]);
1304
+ const { selectedChoice, choices, setSelectedChoice } = useChoices(schema);
1305
+ const formFieldRows = visibleChildren(selectedChoice.type);
1306
+ const onSchemaChange = (choice) => {
1307
+ onChangeValues({});
1308
+ setSelectedChoice(choice);
1309
+ };
1275
1310
  return (React.createElement(Panel, { defaultIsOpen: true },
1276
- React.createElement(Panel.Titlebar, null, "Body"),
1277
- React.createElement(Panel.Content, { className: "sl-overflow-y-auto ParameterGrid OperationParametersContent" }, mapSchemaPropertiesToParameters(parameters, required).map(parameter => {
1278
- var _a;
1311
+ React.createElement(Panel.Titlebar, { rightComponent: React.createElement(OneOfMenu, { choices: choices, choice: selectedChoice, onChange: onSchemaChange }) }, "Body"),
1312
+ React.createElement(Panel.Content, { className: "sl-overflow-y-auto ParameterGrid OperationParametersContent" }, formFieldRows
1313
+ .filter(isRegularNode)
1314
+ .map(toParameterSpec)
1315
+ .map(parameter => {
1316
+ var _a, _b;
1279
1317
  const supportsFileUpload = parameterSupportsFileUpload(parameter);
1280
- const value = values[parameter.name];
1318
+ const value = values[(_a = parameter.name) !== null && _a !== void 0 ? _a : ''];
1281
1319
  if (supportsFileUpload) {
1282
1320
  return (React.createElement(FileUploadParameterEditor, { key: parameter.name, parameter: parameter, value: value instanceof File ? value : undefined, onChange: newValue => newValue
1283
1321
  ? onChangeValues(Object.assign(Object.assign({}, values), { [parameter.name]: newValue }))
1284
1322
  : onChangeValues(omit(values, parameter.name)) }));
1285
1323
  }
1286
- 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 }));
1324
+ 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: (_b = isAllowedEmptyValues[parameter.name]) !== null && _b !== void 0 ? _b : false }));
1287
1325
  }))));
1288
- };
1326
+ };
1327
+ function OneOfMenu({ choices: subSchemas, choice, onChange }) {
1328
+ var _a;
1329
+ const onSubSchemaSelect = React.useCallback(onChange, [onChange]);
1330
+ const menuItems = React.useMemo(() => subSchemas.map(subSchema => {
1331
+ const label = subSchema.title;
1332
+ return {
1333
+ id: `request-subschema-${label}`,
1334
+ title: label,
1335
+ onPress: () => onSubSchemaSelect(subSchema),
1336
+ };
1337
+ }), [subSchemas, onSubSchemaSelect]);
1338
+ if (!subSchemas || subSchemas.length < 2) {
1339
+ return null;
1340
+ }
1341
+ const title = (_a = choice === null || choice === void 0 ? void 0 : choice.title) !== null && _a !== void 0 ? _a : 'Variants';
1342
+ return (React.createElement(Menu, { "aria-label": title, items: menuItems, renderTrigger: ({ isOpen }) => (React.createElement(Button, { appearance: "minimal", size: "sm", iconRight: ['fas', 'sort'], active: isOpen, "data-testid": "oneof-menu" }, title)) }));
1343
+ }
1289
1344
 
1290
1345
  const fileToBase64 = (file) => new Promise((resolve, reject) => {
1291
1346
  const reader = new FileReader();
package/index.js CHANGED
@@ -27,8 +27,11 @@ var filter = require('lodash/filter.js');
27
27
  var flatten = require('lodash/flatten.js');
28
28
  var nanoid = require('nanoid');
29
29
  var curry = require('lodash/curry.js');
30
+ var jsonSchemaTree = require('@stoplight/json-schema-tree');
31
+ var jsonSchemaViewer = require('@stoplight/json-schema-viewer');
30
32
  var omit = require('lodash/omit.js');
31
33
  var keyBy = require('lodash/keyBy.js');
34
+ var last = require('lodash/last.js');
32
35
  var map = require('lodash/map.js');
33
36
  var mapValues = require('lodash/mapValues.js');
34
37
  var isString = require('lodash/isString.js');
@@ -42,7 +45,6 @@ var uniqBy = require('lodash/uniqBy.js');
42
45
  var formatXml = require('xml-formatter');
43
46
  var entries = require('lodash/entries.js');
44
47
  var keys = require('lodash/keys.js');
45
- var jsonSchemaViewer = require('@stoplight/json-schema-viewer');
46
48
  var sortBy = require('lodash/sortBy.js');
47
49
  var isEmpty = require('lodash/isEmpty.js');
48
50
  var isNil = require('lodash/isNil.js');
@@ -87,6 +89,7 @@ var flatten__default = /*#__PURE__*/_interopDefaultLegacy(flatten);
87
89
  var curry__default = /*#__PURE__*/_interopDefaultLegacy(curry);
88
90
  var omit__default = /*#__PURE__*/_interopDefaultLegacy(omit);
89
91
  var keyBy__default = /*#__PURE__*/_interopDefaultLegacy(keyBy);
92
+ var last__default = /*#__PURE__*/_interopDefaultLegacy(last);
90
93
  var map__default = /*#__PURE__*/_interopDefaultLegacy(map);
91
94
  var mapValues__default = /*#__PURE__*/_interopDefaultLegacy(mapValues);
92
95
  var isString__default = /*#__PURE__*/_interopDefaultLegacy(isString);
@@ -1232,7 +1235,9 @@ function exampleOptions(parameter) {
1232
1235
  }
1233
1236
  function parameterSupportsFileUpload(parameter) {
1234
1237
  var _a, _b, _c;
1235
- return (((_a = parameter.schema) === null || _a === void 0 ? void 0 : _a.type) === 'string' &&
1238
+ return (parameter &&
1239
+ parameter.schema &&
1240
+ ((_a = parameter.schema) === null || _a === void 0 ? void 0 : _a.type) === 'string' &&
1236
1241
  (((_b = parameter.schema) === null || _b === void 0 ? void 0 : _b.contentEncoding) === 'base64' ||
1237
1242
  ((_c = parameter.schema) === null || _c === void 0 ? void 0 : _c.contentMediaType) === 'application/octet-stream'));
1238
1243
  }
@@ -1288,6 +1293,35 @@ function mapSchemaPropertiesToParameters(properties, required) {
1288
1293
  return Object.entries(properties).map(([name, schema]) => (Object.assign({ name, schema: typeof schema !== 'boolean' ? schema : undefined, examples: typeof schema !== 'boolean' && schema.examples && schema.examples[0]
1289
1294
  ? [{ key: 'example', value: schema.examples[0] }]
1290
1295
  : undefined }, ((required === null || required === void 0 ? void 0 : required.includes(name)) && { required: true }))));
1296
+ }
1297
+ function toParameterSpec(jsonTreeNode) {
1298
+ var _a;
1299
+ const isBoolean = jsonTreeNode.primaryType === 'boolean';
1300
+ const schema = !isBoolean ? jsonTreeNode.fragment : undefined;
1301
+ const examples = !isBoolean && jsonTreeNode.fragment.examples && jsonTreeNode.fragment.examples[0]
1302
+ ? [{ key: 'example', value: jsonTreeNode.fragment.examples[0] }]
1303
+ : undefined;
1304
+ const lastJsonPathSegment = (_a = last__default["default"](jsonTreeNode.path)) !== null && _a !== void 0 ? _a : '<<UNKNOWN>>';
1305
+ return {
1306
+ name: lastJsonPathSegment,
1307
+ schema,
1308
+ examples,
1309
+ required: isRequired(jsonTreeNode),
1310
+ };
1311
+ }
1312
+ function isRequired(n) {
1313
+ if (!jsonSchemaTree.isRegularNode(n)) {
1314
+ return undefined;
1315
+ }
1316
+ const name = last__default["default"](n.path);
1317
+ if (name === undefined) {
1318
+ return undefined;
1319
+ }
1320
+ const parent = n.parent;
1321
+ if (parent === null || !jsonSchemaTree.isRegularNode(parent)) {
1322
+ return undefined;
1323
+ }
1324
+ return parent.required !== null && parent.required.includes(name);
1291
1325
  }
1292
1326
 
1293
1327
  const ParameterEditor = ({ parameter, value, onChange, isOptional, onChangeOptional, canChangeOptional, validate, }) => {
@@ -1317,31 +1351,53 @@ const ParameterEditor = ({ parameter, value, onChange, isOptional, onChangeOptio
1317
1351
  };
1318
1352
 
1319
1353
  const FormDataBody = ({ specification, values, onChangeValues, onChangeParameterAllow, isAllowedEmptyValues, }) => {
1320
- const schema = specification.schema;
1321
- const parameters = schema === null || schema === void 0 ? void 0 : schema.properties;
1322
- const required = schema === null || schema === void 0 ? void 0 : schema.required;
1323
- React__namespace.useEffect(() => {
1324
- if (parameters === undefined) {
1325
- console.warn(`Invalid schema in form data spec: ${json.safeStringify(schema)}`);
1326
- }
1327
- }, [parameters, schema]);
1328
- if (parameters === undefined) {
1329
- return null;
1330
- }
1354
+ const schema = React__namespace.useMemo(() => {
1355
+ var _a;
1356
+ const schema = (_a = specification.schema) !== null && _a !== void 0 ? _a : {};
1357
+ const tree = new jsonSchemaTree.SchemaTree(schema, { mergeAllOf: true, refResolver: null });
1358
+ tree.populate();
1359
+ return tree.root.children[0];
1360
+ }, [specification]);
1361
+ const { selectedChoice, choices, setSelectedChoice } = jsonSchemaViewer.useChoices(schema);
1362
+ const formFieldRows = jsonSchemaViewer.visibleChildren(selectedChoice.type);
1363
+ const onSchemaChange = (choice) => {
1364
+ onChangeValues({});
1365
+ setSelectedChoice(choice);
1366
+ };
1331
1367
  return (React__namespace.createElement(mosaic.Panel, { defaultIsOpen: true },
1332
- React__namespace.createElement(mosaic.Panel.Titlebar, null, "Body"),
1333
- React__namespace.createElement(mosaic.Panel.Content, { className: "sl-overflow-y-auto ParameterGrid OperationParametersContent" }, mapSchemaPropertiesToParameters(parameters, required).map(parameter => {
1334
- var _a;
1368
+ React__namespace.createElement(mosaic.Panel.Titlebar, { rightComponent: React__namespace.createElement(OneOfMenu, { choices: choices, choice: selectedChoice, onChange: onSchemaChange }) }, "Body"),
1369
+ React__namespace.createElement(mosaic.Panel.Content, { className: "sl-overflow-y-auto ParameterGrid OperationParametersContent" }, formFieldRows
1370
+ .filter(jsonSchemaTree.isRegularNode)
1371
+ .map(toParameterSpec)
1372
+ .map(parameter => {
1373
+ var _a, _b;
1335
1374
  const supportsFileUpload = parameterSupportsFileUpload(parameter);
1336
- const value = values[parameter.name];
1375
+ const value = values[(_a = parameter.name) !== null && _a !== void 0 ? _a : ''];
1337
1376
  if (supportsFileUpload) {
1338
1377
  return (React__namespace.createElement(FileUploadParameterEditor, { key: parameter.name, parameter: parameter, value: value instanceof File ? value : undefined, onChange: newValue => newValue
1339
1378
  ? onChangeValues(Object.assign(Object.assign({}, values), { [parameter.name]: newValue }))
1340
1379
  : onChangeValues(omit__default["default"](values, parameter.name)) }));
1341
1380
  }
1342
- 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 }));
1381
+ 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: (_b = isAllowedEmptyValues[parameter.name]) !== null && _b !== void 0 ? _b : false }));
1343
1382
  }))));
1344
- };
1383
+ };
1384
+ function OneOfMenu({ choices: subSchemas, choice, onChange }) {
1385
+ var _a;
1386
+ const onSubSchemaSelect = React__namespace.useCallback(onChange, [onChange]);
1387
+ const menuItems = React__namespace.useMemo(() => subSchemas.map(subSchema => {
1388
+ const label = subSchema.title;
1389
+ return {
1390
+ id: `request-subschema-${label}`,
1391
+ title: label,
1392
+ onPress: () => onSubSchemaSelect(subSchema),
1393
+ };
1394
+ }), [subSchemas, onSubSchemaSelect]);
1395
+ if (!subSchemas || subSchemas.length < 2) {
1396
+ return null;
1397
+ }
1398
+ const title = (_a = choice === null || choice === void 0 ? void 0 : choice.title) !== null && _a !== void 0 ? _a : 'Variants';
1399
+ return (React__namespace.createElement(mosaic.Menu, { "aria-label": title, items: menuItems, renderTrigger: ({ isOpen }) => (React__namespace.createElement(mosaic.Button, { appearance: "minimal", size: "sm", iconRight: ['fas', 'sort'], active: isOpen, "data-testid": "oneof-menu" }, title)) }));
1400
+ }
1345
1401
 
1346
1402
  const fileToBase64 = (file) => new Promise((resolve, reject) => {
1347
1403
  const reader = new FileReader();
package/index.mjs CHANGED
@@ -25,8 +25,11 @@ import filter from 'lodash/filter.js';
25
25
  import flatten from 'lodash/flatten.js';
26
26
  import { nanoid } from 'nanoid';
27
27
  import curry from 'lodash/curry.js';
28
+ import { isRegularNode, SchemaTree } from '@stoplight/json-schema-tree';
29
+ import { useChoices, visibleChildren, JsonSchemaViewer } from '@stoplight/json-schema-viewer';
28
30
  import omit from 'lodash/omit.js';
29
31
  import keyBy from 'lodash/keyBy.js';
32
+ import last from 'lodash/last.js';
30
33
  import map from 'lodash/map.js';
31
34
  import mapValues from 'lodash/mapValues.js';
32
35
  import isString from 'lodash/isString.js';
@@ -40,7 +43,6 @@ import uniqBy from 'lodash/uniqBy.js';
40
43
  import formatXml from 'xml-formatter';
41
44
  import entries from 'lodash/entries.js';
42
45
  import keys from 'lodash/keys.js';
43
- import { JsonSchemaViewer } from '@stoplight/json-schema-viewer';
44
46
  import sortBy from 'lodash/sortBy.js';
45
47
  import isEmpty from 'lodash/isEmpty.js';
46
48
  import isNil from 'lodash/isNil.js';
@@ -1176,7 +1178,9 @@ function exampleOptions(parameter) {
1176
1178
  }
1177
1179
  function parameterSupportsFileUpload(parameter) {
1178
1180
  var _a, _b, _c;
1179
- return (((_a = parameter.schema) === null || _a === void 0 ? void 0 : _a.type) === 'string' &&
1181
+ return (parameter &&
1182
+ parameter.schema &&
1183
+ ((_a = parameter.schema) === null || _a === void 0 ? void 0 : _a.type) === 'string' &&
1180
1184
  (((_b = parameter.schema) === null || _b === void 0 ? void 0 : _b.contentEncoding) === 'base64' ||
1181
1185
  ((_c = parameter.schema) === null || _c === void 0 ? void 0 : _c.contentMediaType) === 'application/octet-stream'));
1182
1186
  }
@@ -1232,6 +1236,35 @@ function mapSchemaPropertiesToParameters(properties, required) {
1232
1236
  return Object.entries(properties).map(([name, schema]) => (Object.assign({ name, schema: typeof schema !== 'boolean' ? schema : undefined, examples: typeof schema !== 'boolean' && schema.examples && schema.examples[0]
1233
1237
  ? [{ key: 'example', value: schema.examples[0] }]
1234
1238
  : undefined }, ((required === null || required === void 0 ? void 0 : required.includes(name)) && { required: true }))));
1239
+ }
1240
+ function toParameterSpec(jsonTreeNode) {
1241
+ var _a;
1242
+ const isBoolean = jsonTreeNode.primaryType === 'boolean';
1243
+ const schema = !isBoolean ? jsonTreeNode.fragment : undefined;
1244
+ const examples = !isBoolean && jsonTreeNode.fragment.examples && jsonTreeNode.fragment.examples[0]
1245
+ ? [{ key: 'example', value: jsonTreeNode.fragment.examples[0] }]
1246
+ : undefined;
1247
+ const lastJsonPathSegment = (_a = last(jsonTreeNode.path)) !== null && _a !== void 0 ? _a : '<<UNKNOWN>>';
1248
+ return {
1249
+ name: lastJsonPathSegment,
1250
+ schema,
1251
+ examples,
1252
+ required: isRequired(jsonTreeNode),
1253
+ };
1254
+ }
1255
+ function isRequired(n) {
1256
+ if (!isRegularNode(n)) {
1257
+ return undefined;
1258
+ }
1259
+ const name = last(n.path);
1260
+ if (name === undefined) {
1261
+ return undefined;
1262
+ }
1263
+ const parent = n.parent;
1264
+ if (parent === null || !isRegularNode(parent)) {
1265
+ return undefined;
1266
+ }
1267
+ return parent.required !== null && parent.required.includes(name);
1235
1268
  }
1236
1269
 
1237
1270
  const ParameterEditor = ({ parameter, value, onChange, isOptional, onChangeOptional, canChangeOptional, validate, }) => {
@@ -1261,31 +1294,53 @@ const ParameterEditor = ({ parameter, value, onChange, isOptional, onChangeOptio
1261
1294
  };
1262
1295
 
1263
1296
  const FormDataBody = ({ specification, values, onChangeValues, onChangeParameterAllow, isAllowedEmptyValues, }) => {
1264
- const schema = specification.schema;
1265
- const parameters = schema === null || schema === void 0 ? void 0 : schema.properties;
1266
- const required = schema === null || schema === void 0 ? void 0 : schema.required;
1267
- React.useEffect(() => {
1268
- if (parameters === undefined) {
1269
- console.warn(`Invalid schema in form data spec: ${safeStringify(schema)}`);
1270
- }
1271
- }, [parameters, schema]);
1272
- if (parameters === undefined) {
1273
- return null;
1274
- }
1297
+ const schema = React.useMemo(() => {
1298
+ var _a;
1299
+ const schema = (_a = specification.schema) !== null && _a !== void 0 ? _a : {};
1300
+ const tree = new SchemaTree(schema, { mergeAllOf: true, refResolver: null });
1301
+ tree.populate();
1302
+ return tree.root.children[0];
1303
+ }, [specification]);
1304
+ const { selectedChoice, choices, setSelectedChoice } = useChoices(schema);
1305
+ const formFieldRows = visibleChildren(selectedChoice.type);
1306
+ const onSchemaChange = (choice) => {
1307
+ onChangeValues({});
1308
+ setSelectedChoice(choice);
1309
+ };
1275
1310
  return (React.createElement(Panel, { defaultIsOpen: true },
1276
- React.createElement(Panel.Titlebar, null, "Body"),
1277
- React.createElement(Panel.Content, { className: "sl-overflow-y-auto ParameterGrid OperationParametersContent" }, mapSchemaPropertiesToParameters(parameters, required).map(parameter => {
1278
- var _a;
1311
+ React.createElement(Panel.Titlebar, { rightComponent: React.createElement(OneOfMenu, { choices: choices, choice: selectedChoice, onChange: onSchemaChange }) }, "Body"),
1312
+ React.createElement(Panel.Content, { className: "sl-overflow-y-auto ParameterGrid OperationParametersContent" }, formFieldRows
1313
+ .filter(isRegularNode)
1314
+ .map(toParameterSpec)
1315
+ .map(parameter => {
1316
+ var _a, _b;
1279
1317
  const supportsFileUpload = parameterSupportsFileUpload(parameter);
1280
- const value = values[parameter.name];
1318
+ const value = values[(_a = parameter.name) !== null && _a !== void 0 ? _a : ''];
1281
1319
  if (supportsFileUpload) {
1282
1320
  return (React.createElement(FileUploadParameterEditor, { key: parameter.name, parameter: parameter, value: value instanceof File ? value : undefined, onChange: newValue => newValue
1283
1321
  ? onChangeValues(Object.assign(Object.assign({}, values), { [parameter.name]: newValue }))
1284
1322
  : onChangeValues(omit(values, parameter.name)) }));
1285
1323
  }
1286
- 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 }));
1324
+ 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: (_b = isAllowedEmptyValues[parameter.name]) !== null && _b !== void 0 ? _b : false }));
1287
1325
  }))));
1288
- };
1326
+ };
1327
+ function OneOfMenu({ choices: subSchemas, choice, onChange }) {
1328
+ var _a;
1329
+ const onSubSchemaSelect = React.useCallback(onChange, [onChange]);
1330
+ const menuItems = React.useMemo(() => subSchemas.map(subSchema => {
1331
+ const label = subSchema.title;
1332
+ return {
1333
+ id: `request-subschema-${label}`,
1334
+ title: label,
1335
+ onPress: () => onSubSchemaSelect(subSchema),
1336
+ };
1337
+ }), [subSchemas, onSubSchemaSelect]);
1338
+ if (!subSchemas || subSchemas.length < 2) {
1339
+ return null;
1340
+ }
1341
+ const title = (_a = choice === null || choice === void 0 ? void 0 : choice.title) !== null && _a !== void 0 ? _a : 'Variants';
1342
+ return (React.createElement(Menu, { "aria-label": title, items: menuItems, renderTrigger: ({ isOpen }) => (React.createElement(Button, { appearance: "minimal", size: "sm", iconRight: ['fas', 'sort'], active: isOpen, "data-testid": "oneof-menu" }, title)) }));
1343
+ }
1289
1344
 
1290
1345
  const fileToBase64 = (file) => new Promise((resolve, reject) => {
1291
1346
  const reader = new FileReader();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stoplight/elements-core",
3
- "version": "7.13.9",
3
+ "version": "7.14.0",
4
4
  "main": "./index.js",
5
5
  "sideEffects": [
6
6
  "web-components.min.js",
@@ -28,7 +28,8 @@
28
28
  "@stoplight/json": "^3.18.1",
29
29
  "@stoplight/json-schema-ref-parser": "^9.0.5",
30
30
  "@stoplight/json-schema-sampler": "0.2.3",
31
- "@stoplight/json-schema-viewer": "^4.12.1",
31
+ "@stoplight/json-schema-tree": "^2.2.5",
32
+ "@stoplight/json-schema-viewer": "^4.13.0",
32
33
  "@stoplight/markdown-viewer": "^5.6.0",
33
34
  "@stoplight/mosaic": "^1.44.4",
34
35
  "@stoplight/mosaic-code-editor": "^1.44.4",