@scalar/api-client 3.18.0 → 3.19.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.
Files changed (189) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/components/HttpMethod/HttpMethod.vue.d.ts +2 -2
  3. package/dist/components/SectionFilter.vue.d.ts +2 -1
  4. package/dist/components/SectionFilter.vue.d.ts.map +1 -1
  5. package/dist/components/SectionFilter.vue.js +1 -1
  6. package/dist/components/SectionFilter.vue.js.map +1 -1
  7. package/dist/components/SectionFilter.vue.script.js.map +1 -1
  8. package/dist/hooks/use-file-dialog.d.ts.map +1 -1
  9. package/dist/hooks/use-file-dialog.js +1 -0
  10. package/dist/hooks/use-file-dialog.js.map +1 -1
  11. package/dist/style.css +101 -85
  12. package/dist/v2/blocks/operation-block/OperationBlock.vue.d.ts +2 -2
  13. package/dist/v2/blocks/operation-block/OperationBlock.vue.d.ts.map +1 -1
  14. package/dist/v2/blocks/operation-block/OperationBlock.vue.js.map +1 -1
  15. package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js +15 -10
  16. package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js.map +1 -1
  17. package/dist/v2/blocks/operation-block/components/Header.vue.d.ts +1 -1
  18. package/dist/v2/blocks/operation-block/components/Header.vue.js +1 -1
  19. package/dist/v2/blocks/operation-block/components/Header.vue.js.map +1 -1
  20. package/dist/v2/blocks/operation-block/components/Header.vue.script.js.map +1 -1
  21. package/dist/v2/blocks/operation-block/helpers/send-request.d.ts +3 -1
  22. package/dist/v2/blocks/operation-block/helpers/send-request.d.ts.map +1 -1
  23. package/dist/v2/blocks/operation-block/helpers/send-request.js +9 -5
  24. package/dist/v2/blocks/operation-block/helpers/send-request.js.map +1 -1
  25. package/dist/v2/blocks/operation-block/helpers/validate-path-parameters.d.ts +1 -1
  26. package/dist/v2/blocks/operation-block/helpers/validate-path-parameters.js +1 -1
  27. package/dist/v2/blocks/operation-block/helpers/validate-path-parameters.js.map +1 -1
  28. package/dist/v2/blocks/request-block/RequestBlock.vue.d.ts +3 -1
  29. package/dist/v2/blocks/request-block/RequestBlock.vue.d.ts.map +1 -1
  30. package/dist/v2/blocks/request-block/RequestBlock.vue.js +1 -1
  31. package/dist/v2/blocks/request-block/RequestBlock.vue.js.map +1 -1
  32. package/dist/v2/blocks/request-block/RequestBlock.vue.script.js +58 -3
  33. package/dist/v2/blocks/request-block/RequestBlock.vue.script.js.map +1 -1
  34. package/dist/v2/blocks/request-block/components/RequestBody.vue.d.ts +11 -3
  35. package/dist/v2/blocks/request-block/components/RequestBody.vue.d.ts.map +1 -1
  36. package/dist/v2/blocks/request-block/components/RequestBody.vue.js +1 -1
  37. package/dist/v2/blocks/request-block/components/RequestBody.vue.js.map +1 -1
  38. package/dist/v2/blocks/request-block/components/RequestBody.vue.script.js +38 -18
  39. package/dist/v2/blocks/request-block/components/RequestBody.vue.script.js.map +1 -1
  40. package/dist/v2/blocks/request-block/components/RequestBodyForm.vue.d.ts +5 -3
  41. package/dist/v2/blocks/request-block/components/RequestBodyForm.vue.d.ts.map +1 -1
  42. package/dist/v2/blocks/request-block/components/RequestBodyForm.vue.js.map +1 -1
  43. package/dist/v2/blocks/request-block/components/RequestBodyForm.vue.script.js +6 -3
  44. package/dist/v2/blocks/request-block/components/RequestBodyForm.vue.script.js.map +1 -1
  45. package/dist/v2/blocks/request-block/components/RequestBodyStructured.vue.d.ts +1 -1
  46. package/dist/v2/blocks/request-block/components/RequestBodyStructured.vue.d.ts.map +1 -1
  47. package/dist/v2/blocks/request-block/components/RequestBodyStructured.vue.js.map +1 -1
  48. package/dist/v2/blocks/request-block/components/RequestBodyStructured.vue.script.js +1 -0
  49. package/dist/v2/blocks/request-block/components/RequestBodyStructured.vue.script.js.map +1 -1
  50. package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.d.ts.map +1 -1
  51. package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.js.map +1 -1
  52. package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.script.js +4 -3
  53. package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.script.js.map +1 -1
  54. package/dist/v2/blocks/request-block/components/RequestTable.vue.d.ts +2 -0
  55. package/dist/v2/blocks/request-block/components/RequestTable.vue.d.ts.map +1 -1
  56. package/dist/v2/blocks/request-block/components/RequestTable.vue.js +1 -1
  57. package/dist/v2/blocks/request-block/components/RequestTable.vue.js.map +1 -1
  58. package/dist/v2/blocks/request-block/components/RequestTable.vue.script.js +7 -3
  59. package/dist/v2/blocks/request-block/components/RequestTable.vue.script.js.map +1 -1
  60. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.d.ts +7 -1
  61. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.d.ts.map +1 -1
  62. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.js.map +1 -1
  63. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.script.js +17 -5
  64. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.script.js.map +1 -1
  65. package/dist/v2/blocks/request-block/components/RequestTableTooltip.vue.d.ts +1 -1
  66. package/dist/v2/blocks/request-block/components/RequestTableTooltip.vue.js.map +1 -1
  67. package/dist/v2/blocks/request-block/components/RequestTableTooltip.vue.script.js.map +1 -1
  68. package/dist/v2/blocks/request-block/helpers/create-parameter-rows.d.ts +1 -1
  69. package/dist/v2/blocks/request-block/helpers/create-parameter-rows.d.ts.map +1 -1
  70. package/dist/v2/blocks/request-block/helpers/create-parameter-rows.js +17 -8
  71. package/dist/v2/blocks/request-block/helpers/create-parameter-rows.js.map +1 -1
  72. package/dist/v2/blocks/request-block/helpers/fold-structured-body-rows.d.ts +1 -1
  73. package/dist/v2/blocks/request-block/helpers/fold-structured-body-rows.js.map +1 -1
  74. package/dist/v2/blocks/request-block/helpers/get-form-body-rows.d.ts +3 -1
  75. package/dist/v2/blocks/request-block/helpers/get-form-body-rows.d.ts.map +1 -1
  76. package/dist/v2/blocks/request-block/helpers/get-form-body-rows.js +34 -17
  77. package/dist/v2/blocks/request-block/helpers/get-form-body-rows.js.map +1 -1
  78. package/dist/v2/blocks/request-block/helpers/get-parameter-content.d.ts +1 -1
  79. package/dist/v2/blocks/request-block/helpers/get-parameter-content.js.map +1 -1
  80. package/dist/v2/blocks/request-block/helpers/get-parameter-schema.d.ts +1 -1
  81. package/dist/v2/blocks/request-block/helpers/get-parameter-schema.js.map +1 -1
  82. package/dist/v2/blocks/request-block/helpers/get-structured-body-rows.d.ts +1 -1
  83. package/dist/v2/blocks/request-block/helpers/get-structured-body-rows.js +1 -1
  84. package/dist/v2/blocks/request-block/helpers/get-structured-body-rows.js.map +1 -1
  85. package/dist/v2/blocks/request-block/helpers/group-by.d.ts +3 -4
  86. package/dist/v2/blocks/request-block/helpers/group-by.d.ts.map +1 -1
  87. package/dist/v2/blocks/request-block/helpers/group-by.js +12 -10
  88. package/dist/v2/blocks/request-block/helpers/group-by.js.map +1 -1
  89. package/dist/v2/blocks/request-block/helpers/validate-parameter.d.ts +1 -1
  90. package/dist/v2/blocks/request-block/helpers/validate-parameter.js.map +1 -1
  91. package/dist/v2/blocks/response-block/ResponseBlock.vue.js +1 -1
  92. package/dist/v2/blocks/response-block/ResponseBlock.vue.js.map +1 -1
  93. package/dist/v2/blocks/response-block/ResponseBlock.vue.script.js +6 -1
  94. package/dist/v2/blocks/response-block/ResponseBlock.vue.script.js.map +1 -1
  95. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.d.ts +2 -2
  96. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.d.ts.map +1 -1
  97. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.js +1 -1
  98. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.js.map +1 -1
  99. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.script.js +2 -2
  100. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.script.js.map +1 -1
  101. package/dist/v2/blocks/scalar-address-bar-block/helpers/refocus-blur-target.js.map +1 -1
  102. package/dist/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue.d.ts +1 -1
  103. package/dist/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue.js.map +1 -1
  104. package/dist/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue.script.js.map +1 -1
  105. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.d.ts +5 -5
  106. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.d.ts.map +1 -1
  107. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.js.map +1 -1
  108. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.script.js +10 -7
  109. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.script.js.map +1 -1
  110. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuthScopesInput.vue.d.ts +1 -1
  111. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuthScopesInput.vue.js.map +1 -1
  112. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuthScopesInput.vue.script.js.map +1 -1
  113. package/dist/v2/blocks/scalar-auth-selector-block/components/OpenIDConnect.vue.d.ts +1 -1
  114. package/dist/v2/blocks/scalar-auth-selector-block/components/OpenIDConnect.vue.js.map +1 -1
  115. package/dist/v2/blocks/scalar-auth-selector-block/components/OpenIDConnect.vue.script.js.map +1 -1
  116. package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthDataTable.vue.d.ts +1 -1
  117. package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthDataTable.vue.js.map +1 -1
  118. package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthDataTable.vue.script.js.map +1 -1
  119. package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthTab.vue.d.ts +5 -5
  120. package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthTab.vue.d.ts.map +1 -1
  121. package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthTab.vue.js.map +1 -1
  122. package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthTab.vue.script.js +20 -154
  123. package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthTab.vue.script.js.map +1 -1
  124. package/dist/v2/blocks/scalar-auth-selector-block/helpers/auth-options.d.ts +1 -1
  125. package/dist/v2/blocks/scalar-auth-selector-block/helpers/auth-options.js.map +1 -1
  126. package/dist/v2/blocks/scalar-auth-selector-block/helpers/extract-security-scheme-secrets.d.ts +1 -1
  127. package/dist/v2/blocks/scalar-auth-selector-block/helpers/extract-security-scheme-secrets.d.ts.map +1 -1
  128. package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth.d.ts +1 -1
  129. package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth.js.map +1 -1
  130. package/dist/v2/blocks/scalar-auth-selector-block/helpers/openid-discovery-to-flows.js.map +1 -1
  131. package/dist/v2/blocks/scalar-auth-selector-block/helpers/run-oauth2-authorize.d.ts +1 -1
  132. package/dist/v2/blocks/scalar-auth-selector-block/helpers/run-oauth2-authorize.js.map +1 -1
  133. package/dist/v2/blocks/scalar-auth-selector-block/helpers/security-scheme.d.ts +1 -1
  134. package/dist/v2/blocks/scalar-auth-selector-block/helpers/security-scheme.d.ts.map +1 -1
  135. package/dist/v2/blocks/scalar-auth-selector-block/helpers/security-scheme.js.map +1 -1
  136. package/dist/v2/components/code-input/CodeInput.vue.d.ts.map +1 -1
  137. package/dist/v2/components/code-input/CodeInput.vue.js +1 -1
  138. package/dist/v2/components/code-input/CodeInput.vue.js.map +1 -1
  139. package/dist/v2/components/code-input/CodeInput.vue.script.js +1 -1
  140. package/dist/v2/components/code-input/CodeInput.vue.script.js.map +1 -1
  141. package/dist/v2/components/code-input/CodeInputLite.vue.d.ts.map +1 -1
  142. package/dist/v2/components/code-input/CodeInputLite.vue.js +1 -1
  143. package/dist/v2/components/code-input/CodeInputLite.vue.js.map +1 -1
  144. package/dist/v2/components/code-input/CodeInputLite.vue.script.js +7 -6
  145. package/dist/v2/components/code-input/CodeInputLite.vue.script.js.map +1 -1
  146. package/dist/v2/components/code-input/helpers/build-pill-context.d.ts.map +1 -1
  147. package/dist/v2/components/code-input/helpers/build-pill-context.js.map +1 -1
  148. package/dist/v2/components/data-table/DataTableCheckbox.vue.d.ts +1 -1
  149. package/dist/v2/components/data-table/DataTableCheckbox.vue.d.ts.map +1 -1
  150. package/dist/v2/components/layout/CollapsibleSection.vue.js.map +1 -1
  151. package/dist/v2/components/layout/CollapsibleSection.vue.script.js.map +1 -1
  152. package/dist/v2/components/server/ServerDropdown.vue.d.ts +1 -1
  153. package/dist/v2/components/server/ServerDropdown.vue.js.map +1 -1
  154. package/dist/v2/components/server/ServerDropdown.vue.script.js.map +1 -1
  155. package/dist/v2/components/server/ServerDropdownItem.vue.d.ts +1 -1
  156. package/dist/v2/components/server/ServerDropdownItem.vue.js +1 -1
  157. package/dist/v2/components/server/ServerDropdownItem.vue.js.map +1 -1
  158. package/dist/v2/components/server/ServerDropdownItem.vue.script.js.map +1 -1
  159. package/dist/v2/constants.js +1 -1
  160. package/dist/v2/features/command-palette/components/CommandActionInput.vue.js.map +1 -1
  161. package/dist/v2/features/command-palette/components/CommandActionInput.vue.script.js +1 -1
  162. package/dist/v2/features/command-palette/components/CommandActionInput.vue.script.js.map +1 -1
  163. package/dist/v2/features/environments/components/EnvironmentColors.vue.js.map +1 -1
  164. package/dist/v2/features/environments/components/EnvironmentColors.vue.script.js +1 -1
  165. package/dist/v2/features/environments/components/EnvironmentColors.vue.script.js.map +1 -1
  166. package/dist/v2/features/modal/Modal.vue.d.ts +1 -1
  167. package/dist/v2/features/modal/Modal.vue.js.map +1 -1
  168. package/dist/v2/features/modal/Modal.vue.script.js.map +1 -1
  169. package/dist/v2/features/modal/helpers/create-api-client-modal.js.map +1 -1
  170. package/dist/v2/features/modal/helpers/resolve-route-parameters.js +1 -1
  171. package/dist/v2/features/modal/hooks/use-modal-sidebar.js +1 -1
  172. package/dist/v2/features/modal/modal-events.d.ts.map +1 -1
  173. package/dist/v2/features/modal/modal-events.js +10 -1
  174. package/dist/v2/features/modal/modal-events.js.map +1 -1
  175. package/dist/v2/features/operation/Operation.vue.d.ts +1 -1
  176. package/dist/v2/features/operation/Operation.vue.js.map +1 -1
  177. package/dist/v2/features/operation/Operation.vue.script.js.map +1 -1
  178. package/dist/v2/features/search/components/DocumentSearchModal.vue.d.ts +1 -1
  179. package/dist/v2/features/search/components/DocumentSearchModal.vue.js +1 -1
  180. package/dist/v2/features/search/components/DocumentSearchModal.vue.js.map +1 -1
  181. package/dist/v2/features/search/components/DocumentSearchModal.vue.script.js.map +1 -1
  182. package/dist/v2/features/search/helpers/create-search-index.d.ts +1 -1
  183. package/dist/v2/features/search/helpers/create-search-index.js.map +1 -1
  184. package/dist/v2/features/search/hooks/use-document-search.d.ts +1 -1
  185. package/dist/v2/features/search/hooks/use-document-search.js.map +1 -1
  186. package/dist/v2/features/search/hooks/use-search-index.d.ts +1 -1
  187. package/dist/v2/features/search/hooks/use-search-index.js.map +1 -1
  188. package/dist/vue-styles.css +84 -84
  189. package/package.json +12 -12
@@ -1,5 +1,5 @@
1
1
  import type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments';
2
- import type { RequestBodyObject } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document';
2
+ import type { RequestBodyObject } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document';
3
3
  type __VLS_Props = {
4
4
  /** Request body */
5
5
  requestBody?: RequestBodyObject;
@@ -22,8 +22,9 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
22
22
  "update:formValue": (payload: Pick<{
23
23
  payload: {
24
24
  name: string;
25
- value: string | File;
25
+ value: string | File | unknown[] | undefined;
26
26
  isDisabled: boolean;
27
+ isArray?: boolean;
27
28
  }[];
28
29
  contentType: string;
29
30
  meta: import("@scalar/workspace-store/events").OperationExampleMeta;
@@ -36,12 +37,16 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
36
37
  "update:contentType": (payload: {
37
38
  value: string;
38
39
  }) => any;
40
+ "generate:example": (payload: {
41
+ contentType: string;
42
+ }) => any;
39
43
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
40
44
  "onUpdate:formValue"?: ((payload: Pick<{
41
45
  payload: {
42
46
  name: string;
43
- value: string | File;
47
+ value: string | File | unknown[] | undefined;
44
48
  isDisabled: boolean;
49
+ isArray?: boolean;
45
50
  }[];
46
51
  contentType: string;
47
52
  meta: import("@scalar/workspace-store/events").OperationExampleMeta;
@@ -54,6 +59,9 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
54
59
  "onUpdate:contentType"?: ((payload: {
55
60
  value: string;
56
61
  }) => any) | undefined;
62
+ "onGenerate:example"?: ((payload: {
63
+ contentType: string;
64
+ }) => any) | undefined;
57
65
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
58
66
  declare const _default: typeof __VLS_export;
59
67
  export default _default;
@@ -1 +1 @@
1
- {"version":3,"file":"RequestBody.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestBody.vue"],"names":[],"mappings":"AAyeA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AACnH,OAAO,KAAK,EACV,iBAAiB,EAElB,MAAM,8DAA8D,CAAA;AAkBrE,KAAK,WAAW,GAAG;IACjB,mBAAmB;IACnB,WAAW,CAAC,EAAE,iBAAiB,CAAA;IAC/B,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAA;IAClB,oBAAoB;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,2BAA2B;IAC3B,WAAW,EAAE,kBAAkB,CAAA;IAC/B,sEAAsE;IACtE,+BAA+B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACxD;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;CAC7B,CAAC;AAwtBF,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;eA5sB4B,MAAM;;;;;;;;;;;;;;;;;;eAAN,MAAM;;kFA+sBlD,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
1
+ {"version":3,"file":"RequestBody.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestBody.vue"],"names":[],"mappings":"AAshBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AACnH,OAAO,KAAK,EACV,iBAAiB,EAElB,MAAM,8DAA8D,CAAA;AAkBrE,KAAK,WAAW,GAAG;IACjB,mBAAmB;IACnB,WAAW,CAAC,EAAE,iBAAiB,CAAA;IAC/B,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAA;IAClB,oBAAoB;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,2BAA2B;IAC3B,WAAW,EAAE,kBAAkB,CAAA;IAC/B,sEAAsE;IACtE,+BAA+B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACxD;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;CAC7B,CAAC;AA8xBF,QAAA,MAAM,YAAY;;;;;;mBAt1BlB,CA1NoC;;;;;;;;;;;eA8RU,MAAM;;;qBAuBF,MAAM;;;;;;;;mBA3FxD,CA1NoC;;;;;;;;;;;eA8RU,MAAM;;;qBAuBF,MAAM;;kFA8vBtD,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
@@ -2,7 +2,7 @@ import _plugin_vue_export_helper_default from "../../../../_virtual/_plugin-vue_
2
2
  import RequestBody_vue_vue_type_script_setup_true_lang_default from "./RequestBody.vue.script.js";
3
3
  /* empty css */
4
4
  //#region src/v2/blocks/request-block/components/RequestBody.vue
5
- var RequestBody_default = /*#__PURE__*/ _plugin_vue_export_helper_default(RequestBody_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-928dfb0c"]]);
5
+ var RequestBody_default = /*#__PURE__*/ _plugin_vue_export_helper_default(RequestBody_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-ed64587d"]]);
6
6
  //#endregion
7
7
  export { RequestBody_default as default };
8
8
 
@@ -1 +1 @@
1
- {"version":3,"file":"RequestBody.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestBody.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarIcon } from '@scalar/components/icon'\nimport { ScalarListbox } from '@scalar/components/listbox'\nimport { CONTENT_TYPES } from '@scalar/helpers/http/content-types'\nimport { parseMimeType } from '@scalar/helpers/http/mime-type'\nimport { isObject } from '@scalar/helpers/object/is-object'\nimport { objectEntries } from '@scalar/helpers/object/object-entries'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n getExampleFromBody,\n getSchemaExampleFromBody,\n getSelectedBodyContentType,\n} from '@scalar/workspace-store/request-example'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n RequestBodyObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { isObjectSchema } from '@scalar/workspace-store/schemas/v3.1/strict/type-guards'\nimport { computed, ref, watch } from 'vue'\n\nimport { useFileDialog } from '@/hooks/use-file-dialog'\nimport RequestBodyForm from '@/v2/blocks/request-block/components/RequestBodyForm.vue'\nimport RequestBodyStructured from '@/v2/blocks/request-block/components/RequestBodyStructured.vue'\nimport RequestBodyViewToggle from '@/v2/blocks/request-block/components/RequestBodyViewToggle.vue'\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { getStructuredBodyCodec } from '@/v2/blocks/request-block/helpers/structured-body-codec'\nimport { CodeInput } from '@/v2/components/code-input'\nimport {\n DataTable,\n DataTableHeader,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { CollapsibleSection } from '@/v2/components/layout'\n\nconst {\n requestBody,\n exampleKey,\n environment,\n requestBodyCompositionSelection,\n title,\n defaultView = 'raw',\n} = defineProps<{\n /** Request body */\n requestBody?: RequestBodyObject\n /** Currently selected example key for the current operation */\n exampleKey: string\n /** Display title */\n title: string\n /** Selected environment */\n environment: XScalarEnvironment\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n /**\n * Initial view for structured (JSON/YAML) bodies. Comes from the\n * `x-scalar-default-request-body-view` document extension and falls back to `raw`\n * whenever the body cannot be shown as a form.\n */\n defaultView?: 'form' | 'raw'\n}>()\n\nconst emits = defineEmits<{\n (e: 'update:contentType', payload: { value: string }): void\n /** We use this event to update raw values */\n (\n e: 'update:value',\n payload: Pick<\n ApiReferenceEvents['operation:update:requestBody:value'],\n 'payload' | 'contentType'\n >,\n ): void\n /** We use this event when updating form data only */\n (\n e: 'update:formValue',\n payload: Pick<\n ApiReferenceEvents['operation:update:requestBody:formValue'],\n 'payload' | 'contentType'\n >,\n ): void\n}>()\n\n// Map a content type to a language for the code editor\nconst contentTypeToLanguageMap = {\n 'application/json': 'json',\n 'application/xml': 'xml',\n 'application/yaml': 'yaml',\n} as const\n\n/** Selected content type with default */\nconst selectedContentType = computed(\n () => getSelectedBodyContentType(requestBody, exampleKey) ?? 'none',\n)\n\n/**\n * Strips MIME parameters (such as `charset=utf-8`) for dropdown labels, aligned with how we treat\n * media types elsewhere (see api-reference `normalizeMimeType` / WHATWG essence).\n */\nconst contentTypeLabel = (raw: string): string => parseMimeType(raw).essence\n\n/**\n * Build the dropdown options for the content type selector.\n *\n * The list is composed of two groups:\n * 1. The built-in content types we ship friendly labels for (JSON, XML, Multipart Form, etc.).\n * 2. Any additional content types defined on the OpenAPI request body that are not in the built-in list\n * (for example `text/csv`, `application/pdf`, vendor types like `application/vnd.api+json`, ...).\n *\n * The OpenAPI-defined extras are appended at the bottom so the well-known options stay on top, and\n * users can always pick the exact content type the operation actually accepts.\n */\nconst contentTypeOptions = computed<{ id: string; label: string }[]>(() => {\n const builtIn = objectEntries(CONTENT_TYPES).map(([id, label]) => ({\n id,\n label,\n }))\n\n const extras = Object.keys(requestBody?.content ?? {})\n .filter((type) => {\n if (type in CONTENT_TYPES) {\n return false\n }\n // Same essence as a built-in (e.g. `application/json; charset=utf-8`) — do not duplicate the row.\n return !(contentTypeLabel(type) in CONTENT_TYPES)\n })\n .map((type) => ({ id: type, label: contentTypeLabel(type) }))\n\n return [...builtIn, ...extras]\n})\n\nconst selectedContentTypeModel = computed<{ id: string; label: string }>({\n get: () => {\n const found = contentTypeOptions.value.find(\n (it) => it.id === selectedContentType.value,\n )\n if (found) {\n return found\n }\n\n const essence = contentTypeLabel(selectedContentType.value)\n const friendly =\n CONTENT_TYPES[essence as keyof typeof CONTENT_TYPES] ?? essence\n\n return {\n id: selectedContentType.value,\n label: friendly,\n }\n },\n set: (v) => {\n emits('update:contentType', { value: v.id })\n },\n})\n\nfunction handleFileUpload(callback: (file: File) => void) {\n const { open } = useFileDialog({\n onChange: (files) => {\n const file = files?.[0]\n if (file) {\n callback(file)\n }\n },\n multiple: false,\n accept: '*/*',\n })\n open()\n}\n\n/** Dereferenced example */\nconst example = computed(\n () =>\n requestBody &&\n getExampleFromBody(\n requestBody,\n selectedContentType.value,\n exampleKey,\n requestBodyCompositionSelection,\n ),\n)\n\n/** Convert the example value to a string for the code editor */\nconst bodyValue = computed(() => {\n if (!example.value) {\n return ''\n }\n\n const value = example.value.value\n if (typeof value === 'string') {\n return value\n }\n\n return JSON.stringify(value, null, 2)\n})\n\n/** Resolved schema for the request body */\nconst bodySchema = computed<SchemaObject | undefined>(() => {\n return resolve.schema(\n requestBody?.content?.[selectedContentType.value]?.schema,\n )\n})\n\n/** Codec for structured (JSON/YAML) bodies, undefined for everything else */\nconst structuredCodec = computed(() =>\n selectedContentType.value === 'none'\n ? undefined\n : getStructuredBodyCodec(selectedContentType.value),\n)\n\n/** Parsed body value for the form view — `ok: false` when the raw text is not parseable */\nconst parsedBody = computed<{ ok: boolean; value?: unknown }>(() => {\n const codec = structuredCodec.value\n if (!codec) {\n return { ok: false }\n }\n\n const raw = example.value?.value\n // An empty body is still form-editable: rows come from the schema.\n if (raw === undefined || raw === null || raw === '') {\n return { ok: true, value: {} }\n }\n if (typeof raw === 'string') {\n try {\n return { ok: true, value: codec.parse(raw) }\n } catch {\n return { ok: false }\n }\n }\n // Spec-provided examples can be stored as objects directly.\n return { ok: true, value: raw }\n})\n\n/**\n * An edited example normally takes precedence over schema-generated data. When a different\n * composition branch is selected, however, keeping that example leaves the editor showing the\n * previous branch. Track the selection itself instead of inspecting discriminator fields so this\n * also works for compositions whose members are distinguished only by their shape.\n */\nconst compositionSelectionKey = computed(() =>\n JSON.stringify(requestBodyCompositionSelection ?? {}),\n)\n\n// Switching operations changes the body (and often the selection) at once, which is not a branch\n// change, so we only regenerate the body when the selection changes while the operation and example\n// stay the same. Watching all three together and comparing against the watcher's own previous values\n// keeps this correct regardless of the order in which props update or watchers flush.\nwatch(\n [() => requestBody, () => exampleKey, compositionSelectionKey],\n (\n [, , selection],\n [previousRequestBody, previousExampleKey, previousSelection],\n ) => {\n const operationChanged =\n requestBody !== previousRequestBody || exampleKey !== previousExampleKey\n const selectionChanged = selection !== previousSelection\n\n // Only a genuine branch switch within the same operation should reset the edited body. An empty\n // selection means there is no composition to switch between (or the selection was cleared on an\n // operation change), so there is nothing to reset.\n if (\n operationChanged ||\n !selectionChanged ||\n Object.keys(requestBodyCompositionSelection ?? {}).length === 0\n ) {\n return\n }\n\n const codec = structuredCodec.value\n if (!requestBody || !codec) {\n return\n }\n\n // Regenerate through the same helper the initial example uses so a reset produces exactly the\n // value a fresh render of this branch would, rather than a hand-copied second code path.\n const selectedValue = getSchemaExampleFromBody(\n requestBody,\n selectedContentType.value,\n requestBodyCompositionSelection,\n )\n\n emits('update:value', {\n // A branch with no writable content generates `null`/`undefined`; clear the editor rather than\n // writing the literal text `null` or leaving the previously selected branch's body behind.\n payload: selectedValue == null ? '' : codec.stringify(selectedValue),\n contentType: selectedContentType.value,\n })\n },\n)\n\n/** The form view only works on an object-shaped body root */\nconst isFormViewAvailable = computed(\n () => parsedBody.value.ok && isObject(parsedBody.value.value),\n)\n\n/**\n * Show the Form/Raw toggle for structured bodies that are (or per schema should be)\n * an object at the root. Non-object roots (arrays, primitives) stay raw-only.\n */\nconst showBodyViewToggle = computed(\n () =>\n Boolean(structuredCodec.value) &&\n (isFormViewAvailable.value ||\n Boolean(bodySchema.value && isObjectSchema(bodySchema.value))),\n)\n\n/** Selected body view, seeded from the document default (raw unless configured) */\nconst bodyView = ref<'form' | 'raw'>(defaultView)\n\n// Fall back to raw when the form view stops being available (e.g. the content type\n// changed to a non-structured one, or an external edit made the body unparseable).\nwatch(isFormViewAvailable, (ok) => {\n if (!ok) {\n bodyView.value = 'raw'\n }\n})\n</script>\n<template>\n <CollapsibleSection>\n <template #title>{{ title }}</template>\n <DataTable\n :columns=\"['']\"\n presentational>\n <DataTableHeader\n class=\"relative col-span-full flex h-8 cursor-pointer items-center justify-between border-r-0 !p-0\">\n <ScalarListbox\n v-model=\"selectedContentTypeModel\"\n :options=\"contentTypeOptions\"\n teleport>\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-3 font-normal\"\n fullWidth\n variant=\"ghost\">\n <span>{{ selectedContentTypeModel.label }}</span>\n <ScalarIcon\n icon=\"ChevronDown\"\n size=\"md\" />\n </ScalarButton>\n </ScalarListbox>\n <RequestBodyViewToggle\n v-if=\"showBodyViewToggle\"\n :disabled=\"!isFormViewAvailable\"\n :modelValue=\"bodyView\"\n @update:modelValue=\"(v) => (bodyView = v)\" />\n </DataTableHeader>\n <DataTableRow>\n <!-- No Body -->\n <template v-if=\"selectedContentType === 'none'\">\n <div\n class=\"text-c-3 flex min-h-10 w-full items-center justify-center border-t p-2 text-sm\">\n <span>No Body</span>\n </div>\n </template>\n\n <!-- Binary File -->\n <template\n v-else-if=\"selectedContentType === 'application/octet-stream'\">\n <div\n class=\"flex items-center justify-center overflow-hidden border-t p-1.5\">\n <template\n v-if=\"\n getFileName(unpackProxyObject(example?.value)) !== undefined\n \">\n <span\n class=\"text-c-2 w-full max-w-full overflow-hidden rounded border px-1.5 py-1 text-xs whitespace-nowrap\">\n {{ getFileName(unpackProxyObject(example?.value)) }}\n </span>\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 ml-1 border-0 shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n emits('update:value', {\n payload: undefined,\n contentType: selectedContentType,\n })\n \">\n Delete\n </ScalarButton>\n </template>\n <template v-else>\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 border-0 shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n () =>\n handleFileUpload((file) =>\n emits('update:value', {\n payload: file,\n contentType: selectedContentType,\n }),\n )\n \">\n <span>Select File</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </template>\n </div>\n </template>\n\n <!-- Form Data / URL Encoded -->\n <template\n v-else-if=\"\n selectedContentType === 'multipart/form-data' ||\n selectedContentType === 'application/x-www-form-urlencoded'\n \">\n <RequestBodyForm\n :bodySchema\n :environment\n :example\n :selectedContentType\n @update:formValue=\"\n (payload) =>\n emits('update:formValue', {\n payload,\n contentType: selectedContentType,\n })\n \" />\n </template>\n\n <!-- Code/Other -->\n <template v-else>\n <!-- Schema-driven form view for structured (JSON/YAML) bodies -->\n <RequestBodyStructured\n v-if=\"bodyView === 'form' && isFormViewAvailable\"\n :bodySchema\n :contentType=\"selectedContentType\"\n :environment\n :parsedValue=\"parsedBody.value\"\n @update:value=\"\n (value) =>\n emits('update:value', {\n payload: value,\n contentType: selectedContentType,\n })\n \" />\n <CodeInput\n v-else\n class=\"border-t px-3\"\n content=\"\"\n :environment=\"environment\"\n :language=\"\n contentTypeToLanguageMap[\n selectedContentType as keyof typeof contentTypeToLanguageMap\n ] ?? 'plaintext'\n \"\n lineNumbers\n lint\n :modelValue=\"bodyValue\"\n withFakeData\n @update:modelValue=\"\n (value) =>\n emits('update:value', {\n payload: value,\n contentType: selectedContentType,\n })\n \" />\n </template>\n </DataTableRow>\n </DataTable>\n </CollapsibleSection>\n</template>\n<style scoped>\n:deep(.cm-content) {\n font-size: var(--scalar-small);\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"RequestBody.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestBody.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarIcon } from '@scalar/components/icon'\nimport { ScalarIconButton } from '@scalar/components/icon-button'\nimport { ScalarListbox } from '@scalar/components/listbox'\nimport { CONTENT_TYPES } from '@scalar/helpers/http/content-types'\nimport { parseMimeType } from '@scalar/helpers/http/mime-type'\nimport { isObject } from '@scalar/helpers/object/is-object'\nimport { objectEntries } from '@scalar/helpers/object/object-entries'\nimport { ScalarIconMagicWand } from '@scalar/icons'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n getExampleFromBody,\n getSchemaExampleFromBody,\n getSelectedBodyContentType,\n} from '@scalar/workspace-store/request-example'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n RequestBodyObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { isObjectSchema } from '@scalar/workspace-store/schemas/v3.2/strict/type-guards'\nimport { computed, ref, watch } from 'vue'\n\nimport { useFileDialog } from '@/hooks/use-file-dialog'\nimport RequestBodyForm from '@/v2/blocks/request-block/components/RequestBodyForm.vue'\nimport RequestBodyStructured from '@/v2/blocks/request-block/components/RequestBodyStructured.vue'\nimport RequestBodyViewToggle from '@/v2/blocks/request-block/components/RequestBodyViewToggle.vue'\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { getStructuredBodyCodec } from '@/v2/blocks/request-block/helpers/structured-body-codec'\nimport { CodeInput } from '@/v2/components/code-input'\nimport {\n DataTable,\n DataTableHeader,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { CollapsibleSection } from '@/v2/components/layout'\n\nconst {\n requestBody,\n exampleKey,\n environment,\n requestBodyCompositionSelection,\n title,\n defaultView = 'raw',\n} = defineProps<{\n /** Request body */\n requestBody?: RequestBodyObject\n /** Currently selected example key for the current operation */\n exampleKey: string\n /** Display title */\n title: string\n /** Selected environment */\n environment: XScalarEnvironment\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n /**\n * Initial view for structured (JSON/YAML) bodies. Comes from the\n * `x-scalar-default-request-body-view` document extension and falls back to `raw`\n * whenever the body cannot be shown as a form.\n */\n defaultView?: 'form' | 'raw'\n}>()\n\nconst emits = defineEmits<{\n (e: 'update:contentType', payload: { value: string }): void\n /** We use this event to update raw values */\n (\n e: 'update:value',\n payload: Pick<\n ApiReferenceEvents['operation:update:requestBody:value'],\n 'payload' | 'contentType'\n >,\n ): void\n /** We use this event when updating form data only */\n (\n e: 'update:formValue',\n payload: Pick<\n ApiReferenceEvents['operation:update:requestBody:formValue'],\n 'payload' | 'contentType'\n >,\n ): void\n /**\n * Create a new example seeded with values generated from the request body schema.\n *\n * The block itself owns the document and operation identity needed to create an example, so we\n * only report the content type the user is currently looking at.\n */\n (e: 'generate:example', payload: { contentType: string }): void\n}>()\n\n// Map a content type to a language for the code editor\nconst contentTypeToLanguageMap = {\n 'application/json': 'json',\n 'application/xml': 'xml',\n 'application/yaml': 'yaml',\n} as const\n\n/** Selected content type with default */\nconst selectedContentType = computed(\n () => getSelectedBodyContentType(requestBody, exampleKey) ?? 'none',\n)\n\n/**\n * Strips MIME parameters (such as `charset=utf-8`) for dropdown labels, aligned with how we treat\n * media types elsewhere (see api-reference `normalizeMimeType` / WHATWG essence).\n */\nconst contentTypeLabel = (raw: string): string => parseMimeType(raw).essence\n\n/**\n * Build the dropdown options for the content type selector.\n *\n * The list is composed of two groups:\n * 1. The built-in content types we ship friendly labels for (JSON, XML, Multipart Form, etc.).\n * 2. Any additional content types defined on the OpenAPI request body that are not in the built-in list\n * (for example `text/csv`, `application/pdf`, vendor types like `application/vnd.api+json`, ...).\n *\n * The OpenAPI-defined extras are appended at the bottom so the well-known options stay on top, and\n * users can always pick the exact content type the operation actually accepts.\n */\nconst contentTypeOptions = computed<{ id: string; label: string }[]>(() => {\n const builtIn = objectEntries(CONTENT_TYPES).map(([id, label]) => ({\n id,\n label,\n }))\n\n const extras = Object.keys(requestBody?.content ?? {})\n .filter((type) => {\n if (type in CONTENT_TYPES) {\n return false\n }\n // Same essence as a built-in (e.g. `application/json; charset=utf-8`) — do not duplicate the row.\n return !(contentTypeLabel(type) in CONTENT_TYPES)\n })\n .map((type) => ({ id: type, label: contentTypeLabel(type) }))\n\n return [...builtIn, ...extras]\n})\n\nconst selectedContentTypeModel = computed<{ id: string; label: string }>({\n get: () => {\n const found = contentTypeOptions.value.find(\n (it) => it.id === selectedContentType.value,\n )\n if (found) {\n return found\n }\n\n const essence = contentTypeLabel(selectedContentType.value)\n const friendly =\n CONTENT_TYPES[essence as keyof typeof CONTENT_TYPES] ?? essence\n\n return {\n id: selectedContentType.value,\n label: friendly,\n }\n },\n set: (v) => {\n emits('update:contentType', { value: v.id })\n },\n})\n\nfunction handleFileUpload(callback: (file: File) => void) {\n const { open } = useFileDialog({\n onChange: (files) => {\n const file = files?.[0]\n if (file) {\n callback(file)\n }\n },\n multiple: false,\n accept: '*/*',\n })\n open()\n}\n\n/** Dereferenced example */\nconst example = computed(\n () =>\n requestBody &&\n getExampleFromBody(\n requestBody,\n selectedContentType.value,\n exampleKey,\n requestBodyCompositionSelection,\n ),\n)\n\n/** Convert the example value to a string for the code editor */\nconst bodyValue = computed(() => {\n if (!example.value) {\n return ''\n }\n\n const value = example.value.value\n if (typeof value === 'string') {\n return value\n }\n\n return JSON.stringify(value, null, 2)\n})\n\n/** Resolved schema for the request body */\nconst bodySchema = computed<SchemaObject | undefined>(() => {\n return resolve.schema(\n requestBody?.content?.[selectedContentType.value]?.schema,\n )\n})\n\n/** Codec for structured (JSON/YAML) bodies, undefined for everything else */\nconst structuredCodec = computed(() =>\n selectedContentType.value === 'none'\n ? undefined\n : getStructuredBodyCodec(selectedContentType.value),\n)\n\n/** Parsed body value for the form view — `ok: false` when the raw text is not parseable */\nconst parsedBody = computed<{ ok: boolean; value?: unknown }>(() => {\n const codec = structuredCodec.value\n if (!codec) {\n return { ok: false }\n }\n\n const raw = example.value?.value\n // An empty body is still form-editable: rows come from the schema.\n if (raw === undefined || raw === null || raw === '') {\n return { ok: true, value: {} }\n }\n if (typeof raw === 'string') {\n try {\n return { ok: true, value: codec.parse(raw) }\n } catch {\n return { ok: false }\n }\n }\n // Spec-provided examples can be stored as objects directly.\n return { ok: true, value: raw }\n})\n\n/**\n * An edited example normally takes precedence over schema-generated data. When a different\n * composition branch is selected, however, keeping that example leaves the editor showing the\n * previous branch. Track the selection itself instead of inspecting discriminator fields so this\n * also works for compositions whose members are distinguished only by their shape.\n */\nconst compositionSelectionKey = computed(() =>\n JSON.stringify(requestBodyCompositionSelection ?? {}),\n)\n\n// Switching operations changes the body (and often the selection) at once, which is not a branch\n// change, so we only regenerate the body when the selection changes while the operation and example\n// stay the same. Watching all three together and comparing against the watcher's own previous values\n// keeps this correct regardless of the order in which props update or watchers flush.\nwatch(\n [() => requestBody, () => exampleKey, compositionSelectionKey],\n (\n [, , selection],\n [previousRequestBody, previousExampleKey, previousSelection],\n ) => {\n const operationChanged =\n requestBody !== previousRequestBody || exampleKey !== previousExampleKey\n const selectionChanged = selection !== previousSelection\n\n // Going from no selection to a populated one is the modal applying the reference's selection as\n // the panel opens, not the user switching branches. Resetting here would discard the body's named\n // example on the very first open (issue #10075), so only a change between two populated selections\n // counts as a real branch switch.\n const hadNoPreviousSelection = previousSelection === '{}'\n\n // Only a genuine branch switch within the same operation should reset the edited body. An empty\n // selection means there is no composition to switch between (or the selection was cleared on an\n // operation change), so there is nothing to reset.\n if (\n operationChanged ||\n !selectionChanged ||\n hadNoPreviousSelection ||\n Object.keys(requestBodyCompositionSelection ?? {}).length === 0\n ) {\n return\n }\n\n const codec = structuredCodec.value\n if (!requestBody || !codec) {\n return\n }\n\n // Regenerate through the same helper the initial example uses so a reset produces exactly the\n // value a fresh render of this branch would, rather than a hand-copied second code path.\n const selectedValue = getSchemaExampleFromBody(\n requestBody,\n selectedContentType.value,\n requestBodyCompositionSelection,\n )\n\n emits('update:value', {\n // A branch with no writable content generates `null`/`undefined`; clear the editor rather than\n // writing the literal text `null` or leaving the previously selected branch's body behind.\n payload: selectedValue == null ? '' : codec.stringify(selectedValue),\n contentType: selectedContentType.value,\n })\n },\n)\n\n/** The form view only works on an object-shaped body root */\nconst isFormViewAvailable = computed(\n () => parsedBody.value.ok && isObject(parsedBody.value.value),\n)\n\n/**\n * Show the Form/Raw toggle for structured bodies that are (or per schema should be)\n * an object at the root. Non-object roots (arrays, primitives) stay raw-only.\n */\nconst showBodyViewToggle = computed(\n () =>\n Boolean(structuredCodec.value) &&\n (isFormViewAvailable.value ||\n Boolean(bodySchema.value && isObjectSchema(bodySchema.value))),\n)\n\n/** Selected body view, seeded from the document default (raw unless configured) */\nconst bodyView = ref<'form' | 'raw'>(defaultView)\n\n// Fall back to raw when the form view stops being available (e.g. the content type\n// changed to a non-structured one, or an external edit made the body unparseable).\nwatch(isFormViewAvailable, (ok) => {\n if (!ok) {\n bodyView.value = 'raw'\n }\n})\n\n/**\n * Whether we can offer to generate a fresh example from the schema.\n *\n * Only structured (JSON/YAML) bodies qualify: they have a schema to generate from and a text\n * representation we can seed the new example with. Binary and form bodies have their own editors,\n * so the button would have nothing meaningful to write.\n */\nconst canGenerateExample = computed(() =>\n Boolean(structuredCodec.value && bodySchema.value),\n)\n</script>\n<template>\n <CollapsibleSection>\n <template #title>{{ title }}</template>\n <DataTable\n :columns=\"['']\"\n presentational>\n <DataTableHeader\n class=\"relative col-span-full flex h-8 cursor-pointer items-center justify-between border-r-0 !p-0\">\n <ScalarListbox\n v-model=\"selectedContentTypeModel\"\n :options=\"contentTypeOptions\"\n teleport>\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-3 font-normal\"\n fullWidth\n variant=\"ghost\">\n <span>{{ selectedContentTypeModel.label }}</span>\n <ScalarIcon\n icon=\"ChevronDown\"\n size=\"md\" />\n </ScalarButton>\n </ScalarListbox>\n <div class=\"flex items-center gap-1\">\n <!--\n Generates a new example from the schema so the auto-generated fields stay reachable\n even once the document ships custom examples.\n -->\n <ScalarIconButton\n v-if=\"canGenerateExample\"\n aria-label=\"Generate example from schema\"\n :icon=\"ScalarIconMagicWand\"\n label=\"Generate example from schema\"\n size=\"sm\"\n tooltip\n @click.stop=\"\n emits('generate:example', { contentType: selectedContentType })\n \" />\n <RequestBodyViewToggle\n v-if=\"showBodyViewToggle\"\n :disabled=\"!isFormViewAvailable\"\n :modelValue=\"bodyView\"\n @update:modelValue=\"(v) => (bodyView = v)\" />\n </div>\n </DataTableHeader>\n <DataTableRow>\n <!-- No Body -->\n <template v-if=\"selectedContentType === 'none'\">\n <div\n class=\"text-c-3 flex min-h-10 w-full items-center justify-center border-t p-2 text-sm\">\n <span>No Body</span>\n </div>\n </template>\n\n <!-- Binary File -->\n <template\n v-else-if=\"selectedContentType === 'application/octet-stream'\">\n <div\n class=\"flex items-center justify-center overflow-hidden border-t p-1.5\">\n <template\n v-if=\"\n getFileName(unpackProxyObject(example?.value)) !== undefined\n \">\n <span\n class=\"text-c-2 w-full max-w-full overflow-hidden rounded border px-1.5 py-1 text-xs whitespace-nowrap\">\n {{ getFileName(unpackProxyObject(example?.value)) }}\n </span>\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 ml-1 border-0 shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n emits('update:value', {\n payload: undefined,\n contentType: selectedContentType,\n })\n \">\n Delete\n </ScalarButton>\n </template>\n <template v-else>\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 border-0 shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n () =>\n handleFileUpload((file) =>\n emits('update:value', {\n payload: file,\n contentType: selectedContentType,\n }),\n )\n \">\n <span>Select File</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </template>\n </div>\n </template>\n\n <!-- Form Data / URL Encoded -->\n <template\n v-else-if=\"\n selectedContentType === 'multipart/form-data' ||\n selectedContentType === 'application/x-www-form-urlencoded'\n \">\n <RequestBodyForm\n :bodySchema\n :environment\n :example\n :selectedContentType\n @update:formValue=\"\n (payload) =>\n emits('update:formValue', {\n payload,\n contentType: selectedContentType,\n })\n \" />\n </template>\n\n <!-- Code/Other -->\n <template v-else>\n <!-- Schema-driven form view for structured (JSON/YAML) bodies -->\n <RequestBodyStructured\n v-if=\"bodyView === 'form' && isFormViewAvailable\"\n :bodySchema\n :contentType=\"selectedContentType\"\n :environment\n :parsedValue=\"parsedBody.value\"\n @update:value=\"\n (value) =>\n emits('update:value', {\n payload: value,\n contentType: selectedContentType,\n })\n \" />\n <CodeInput\n v-else\n class=\"border-t px-3\"\n content=\"\"\n :environment=\"environment\"\n :language=\"\n contentTypeToLanguageMap[\n selectedContentType as keyof typeof contentTypeToLanguageMap\n ] ?? 'plaintext'\n \"\n lineNumbers\n lint\n :modelValue=\"bodyValue\"\n withFakeData\n @update:modelValue=\"\n (value) =>\n emits('update:value', {\n payload: value,\n contentType: selectedContentType,\n })\n \" />\n </template>\n </DataTableRow>\n </DataTable>\n </CollapsibleSection>\n</template>\n<style scoped>\n:deep(.cm-content) {\n font-size: var(--scalar-small);\n}\n</style>\n"],"mappings":""}
@@ -9,28 +9,31 @@ import { getStructuredBodyCodec } from "../helpers/structured-body-codec.js";
9
9
  import RequestBodyStructured_default from "./RequestBodyStructured.vue.js";
10
10
  import RequestBodyViewToggle_default from "./RequestBodyViewToggle.vue.js";
11
11
  import CollapsibleSection_default from "../../../components/layout/CollapsibleSection.vue.js";
12
- import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, openBlock, ref, toDisplayString, unref, watch, withCtx } from "vue";
12
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, openBlock, ref, toDisplayString, unref, watch, withCtx, withModifiers } from "vue";
13
13
  import { ScalarButton } from "@scalar/components/button";
14
14
  import { ScalarListbox } from "@scalar/components/listbox";
15
+ import { ScalarIconMagicWand } from "@scalar/icons";
15
16
  import { objectEntries } from "@scalar/helpers/object/object-entries";
16
17
  import { ScalarIcon } from "@scalar/components/icon";
18
+ import { ScalarIconButton } from "@scalar/components/icon-button";
17
19
  import { getExampleFromBody, getSchemaExampleFromBody, getSelectedBodyContentType } from "@scalar/workspace-store/request-example";
18
20
  import { parseMimeType } from "@scalar/helpers/http/mime-type";
19
21
  import { unpackProxyObject } from "@scalar/workspace-store/helpers/unpack-proxy";
20
22
  import { CONTENT_TYPES } from "@scalar/helpers/http/content-types";
21
23
  import { isObject } from "@scalar/helpers/object/is-object";
22
24
  import { resolve } from "@scalar/workspace-store/resolve";
23
- import { isObjectSchema } from "@scalar/workspace-store/schemas/v3.1/strict/type-guards";
25
+ import { isObjectSchema } from "@scalar/workspace-store/schemas/v3.2/strict/type-guards";
24
26
  //#region src/v2/blocks/request-block/components/RequestBody.vue?vue&type=script&setup=true&lang.ts
25
- var _hoisted_1 = {
27
+ var _hoisted_1 = { class: "flex items-center gap-1" };
28
+ var _hoisted_2 = {
26
29
  key: 0,
27
30
  class: "text-c-3 flex min-h-10 w-full items-center justify-center border-t p-2 text-sm"
28
31
  };
29
- var _hoisted_2 = {
32
+ var _hoisted_3 = {
30
33
  key: 1,
31
34
  class: "flex items-center justify-center overflow-hidden border-t p-1.5"
32
35
  };
33
- var _hoisted_3 = { class: "text-c-2 w-full max-w-full overflow-hidden rounded border px-1.5 py-1 text-xs whitespace-nowrap" };
36
+ var _hoisted_4 = { class: "text-c-2 w-full max-w-full overflow-hidden rounded border px-1.5 py-1 text-xs whitespace-nowrap" };
34
37
  var RequestBody_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
35
38
  __name: "RequestBody",
36
39
  props: {
@@ -44,7 +47,8 @@ var RequestBody_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
44
47
  emits: [
45
48
  "update:contentType",
46
49
  "update:value",
47
- "update:formValue"
50
+ "update:formValue",
51
+ "generate:example"
48
52
  ],
49
53
  setup(__props, { emit: __emit }) {
50
54
  const emits = __emit;
@@ -153,7 +157,7 @@ var RequestBody_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
153
157
  () => __props.exampleKey,
154
158
  computed(() => JSON.stringify(__props.requestBodyCompositionSelection ?? {}))
155
159
  ], ([, , selection], [previousRequestBody, previousExampleKey, previousSelection]) => {
156
- if (__props.requestBody !== previousRequestBody || __props.exampleKey !== previousExampleKey || !(selection !== previousSelection) || Object.keys(__props.requestBodyCompositionSelection ?? {}).length === 0) return;
160
+ if (__props.requestBody !== previousRequestBody || __props.exampleKey !== previousExampleKey || !(selection !== previousSelection) || previousSelection === "{}" || Object.keys(__props.requestBodyCompositionSelection ?? {}).length === 0) return;
157
161
  const codec = structuredCodec.value;
158
162
  if (!__props.requestBody || !codec) return;
159
163
  const selectedValue = getSchemaExampleFromBody(__props.requestBody, selectedContentType.value, __props.requestBodyCompositionSelection);
@@ -174,6 +178,14 @@ var RequestBody_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
174
178
  watch(isFormViewAvailable, (ok) => {
175
179
  if (!ok) bodyView.value = "raw";
176
180
  });
181
+ /**
182
+ * Whether we can offer to generate a fresh example from the schema.
183
+ *
184
+ * Only structured (JSON/YAML) bodies qualify: they have a schema to generate from and a text
185
+ * representation we can seed the new example with. Binary and form bodies have their own editors,
186
+ * so the button would have nothing meaningful to write.
187
+ */
188
+ const canGenerateExample = computed(() => Boolean(structuredCodec.value && bodySchema.value));
177
189
  return (_ctx, _cache) => {
178
190
  return openBlock(), createBlock(unref(CollapsibleSection_default), null, {
179
191
  title: withCtx(() => [createTextVNode(toDisplayString(__props.title), 1)]),
@@ -200,36 +212,44 @@ var RequestBody_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
200
212
  _: 1
201
213
  })]),
202
214
  _: 1
203
- }, 8, ["modelValue", "options"]), showBodyViewToggle.value ? (openBlock(), createBlock(RequestBodyViewToggle_default, {
215
+ }, 8, ["modelValue", "options"]), createElementVNode("div", _hoisted_1, [canGenerateExample.value ? (openBlock(), createBlock(unref(ScalarIconButton), {
204
216
  key: 0,
217
+ "aria-label": "Generate example from schema",
218
+ icon: unref(ScalarIconMagicWand),
219
+ label: "Generate example from schema",
220
+ size: "sm",
221
+ tooltip: "",
222
+ onClick: _cache[1] || (_cache[1] = withModifiers(($event) => emits("generate:example", { contentType: selectedContentType.value }), ["stop"]))
223
+ }, null, 8, ["icon"])) : createCommentVNode("", true), showBodyViewToggle.value ? (openBlock(), createBlock(RequestBodyViewToggle_default, {
224
+ key: 1,
205
225
  disabled: !isFormViewAvailable.value,
206
226
  modelValue: bodyView.value,
207
- "onUpdate:modelValue": _cache[1] || (_cache[1] = (v) => bodyView.value = v)
208
- }, null, 8, ["disabled", "modelValue"])) : createCommentVNode("", true)]),
227
+ "onUpdate:modelValue": _cache[2] || (_cache[2] = (v) => bodyView.value = v)
228
+ }, null, 8, ["disabled", "modelValue"])) : createCommentVNode("", true)])]),
209
229
  _: 1
210
230
  }), createVNode(unref(DataTableRow_default), null, {
211
- default: withCtx(() => [selectedContentType.value === "none" ? (openBlock(), createElementBlock("div", _hoisted_1, [..._cache[7] || (_cache[7] = [createElementVNode("span", null, "No Body", -1)])])) : selectedContentType.value === "application/octet-stream" ? (openBlock(), createElementBlock("div", _hoisted_2, [unref(getFileName)(unref(unpackProxyObject)(example.value?.value)) !== void 0 ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createElementVNode("span", _hoisted_3, toDisplayString(unref(getFileName)(unref(unpackProxyObject)(example.value?.value))), 1), createVNode(unref(ScalarButton), {
231
+ default: withCtx(() => [selectedContentType.value === "none" ? (openBlock(), createElementBlock("div", _hoisted_2, [..._cache[8] || (_cache[8] = [createElementVNode("span", null, "No Body", -1)])])) : selectedContentType.value === "application/octet-stream" ? (openBlock(), createElementBlock("div", _hoisted_3, [unref(getFileName)(unref(unpackProxyObject)(example.value?.value)) !== void 0 ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createElementVNode("span", _hoisted_4, toDisplayString(unref(getFileName)(unref(unpackProxyObject)(example.value?.value))), 1), createVNode(unref(ScalarButton), {
212
232
  class: "bg-b-2 hover:bg-b-3 text-c-2 ml-1 border-0 shadow-none",
213
233
  size: "sm",
214
234
  variant: "outlined",
215
- onClick: _cache[2] || (_cache[2] = ($event) => emits("update:value", {
235
+ onClick: _cache[3] || (_cache[3] = ($event) => emits("update:value", {
216
236
  payload: void 0,
217
237
  contentType: selectedContentType.value
218
238
  }))
219
239
  }, {
220
- default: withCtx(() => [..._cache[8] || (_cache[8] = [createTextVNode(" Delete ", -1)])]),
240
+ default: withCtx(() => [..._cache[9] || (_cache[9] = [createTextVNode(" Delete ", -1)])]),
221
241
  _: 1
222
242
  })], 64)) : (openBlock(), createBlock(unref(ScalarButton), {
223
243
  key: 1,
224
244
  class: "bg-b-2 hover:bg-b-3 text-c-2 border-0 shadow-none",
225
245
  size: "sm",
226
246
  variant: "outlined",
227
- onClick: _cache[3] || (_cache[3] = () => handleFileUpload((file) => emits("update:value", {
247
+ onClick: _cache[4] || (_cache[4] = () => handleFileUpload((file) => emits("update:value", {
228
248
  payload: file,
229
249
  contentType: selectedContentType.value
230
250
  })))
231
251
  }, {
232
- default: withCtx(() => [_cache[9] || (_cache[9] = createElementVNode("span", null, "Select File", -1)), createVNode(unref(ScalarIcon), {
252
+ default: withCtx(() => [_cache[10] || (_cache[10] = createElementVNode("span", null, "Select File", -1)), createVNode(unref(ScalarIcon), {
233
253
  class: "ml-1",
234
254
  icon: "Upload",
235
255
  size: "xs",
@@ -242,7 +262,7 @@ var RequestBody_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
242
262
  environment: __props.environment,
243
263
  example: example.value,
244
264
  selectedContentType: selectedContentType.value,
245
- "onUpdate:formValue": _cache[4] || (_cache[4] = (payload) => emits("update:formValue", {
265
+ "onUpdate:formValue": _cache[5] || (_cache[5] = (payload) => emits("update:formValue", {
246
266
  payload,
247
267
  contentType: selectedContentType.value
248
268
  }))
@@ -257,7 +277,7 @@ var RequestBody_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
257
277
  contentType: selectedContentType.value,
258
278
  environment: __props.environment,
259
279
  parsedValue: parsedBody.value.value,
260
- "onUpdate:value": _cache[5] || (_cache[5] = (value) => emits("update:value", {
280
+ "onUpdate:value": _cache[6] || (_cache[6] = (value) => emits("update:value", {
261
281
  payload: value,
262
282
  contentType: selectedContentType.value
263
283
  }))
@@ -276,7 +296,7 @@ var RequestBody_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
276
296
  lint: "",
277
297
  modelValue: bodyValue.value,
278
298
  withFakeData: "",
279
- "onUpdate:modelValue": _cache[6] || (_cache[6] = (value) => emits("update:value", {
299
+ "onUpdate:modelValue": _cache[7] || (_cache[7] = (value) => emits("update:value", {
280
300
  payload: value,
281
301
  contentType: selectedContentType.value
282
302
  }))
@@ -1 +1 @@
1
- {"version":3,"file":"RequestBody.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestBody.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarIcon } from '@scalar/components/icon'\nimport { ScalarListbox } from '@scalar/components/listbox'\nimport { CONTENT_TYPES } from '@scalar/helpers/http/content-types'\nimport { parseMimeType } from '@scalar/helpers/http/mime-type'\nimport { isObject } from '@scalar/helpers/object/is-object'\nimport { objectEntries } from '@scalar/helpers/object/object-entries'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n getExampleFromBody,\n getSchemaExampleFromBody,\n getSelectedBodyContentType,\n} from '@scalar/workspace-store/request-example'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n RequestBodyObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { isObjectSchema } from '@scalar/workspace-store/schemas/v3.1/strict/type-guards'\nimport { computed, ref, watch } from 'vue'\n\nimport { useFileDialog } from '@/hooks/use-file-dialog'\nimport RequestBodyForm from '@/v2/blocks/request-block/components/RequestBodyForm.vue'\nimport RequestBodyStructured from '@/v2/blocks/request-block/components/RequestBodyStructured.vue'\nimport RequestBodyViewToggle from '@/v2/blocks/request-block/components/RequestBodyViewToggle.vue'\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { getStructuredBodyCodec } from '@/v2/blocks/request-block/helpers/structured-body-codec'\nimport { CodeInput } from '@/v2/components/code-input'\nimport {\n DataTable,\n DataTableHeader,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { CollapsibleSection } from '@/v2/components/layout'\n\nconst {\n requestBody,\n exampleKey,\n environment,\n requestBodyCompositionSelection,\n title,\n defaultView = 'raw',\n} = defineProps<{\n /** Request body */\n requestBody?: RequestBodyObject\n /** Currently selected example key for the current operation */\n exampleKey: string\n /** Display title */\n title: string\n /** Selected environment */\n environment: XScalarEnvironment\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n /**\n * Initial view for structured (JSON/YAML) bodies. Comes from the\n * `x-scalar-default-request-body-view` document extension and falls back to `raw`\n * whenever the body cannot be shown as a form.\n */\n defaultView?: 'form' | 'raw'\n}>()\n\nconst emits = defineEmits<{\n (e: 'update:contentType', payload: { value: string }): void\n /** We use this event to update raw values */\n (\n e: 'update:value',\n payload: Pick<\n ApiReferenceEvents['operation:update:requestBody:value'],\n 'payload' | 'contentType'\n >,\n ): void\n /** We use this event when updating form data only */\n (\n e: 'update:formValue',\n payload: Pick<\n ApiReferenceEvents['operation:update:requestBody:formValue'],\n 'payload' | 'contentType'\n >,\n ): void\n}>()\n\n// Map a content type to a language for the code editor\nconst contentTypeToLanguageMap = {\n 'application/json': 'json',\n 'application/xml': 'xml',\n 'application/yaml': 'yaml',\n} as const\n\n/** Selected content type with default */\nconst selectedContentType = computed(\n () => getSelectedBodyContentType(requestBody, exampleKey) ?? 'none',\n)\n\n/**\n * Strips MIME parameters (such as `charset=utf-8`) for dropdown labels, aligned with how we treat\n * media types elsewhere (see api-reference `normalizeMimeType` / WHATWG essence).\n */\nconst contentTypeLabel = (raw: string): string => parseMimeType(raw).essence\n\n/**\n * Build the dropdown options for the content type selector.\n *\n * The list is composed of two groups:\n * 1. The built-in content types we ship friendly labels for (JSON, XML, Multipart Form, etc.).\n * 2. Any additional content types defined on the OpenAPI request body that are not in the built-in list\n * (for example `text/csv`, `application/pdf`, vendor types like `application/vnd.api+json`, ...).\n *\n * The OpenAPI-defined extras are appended at the bottom so the well-known options stay on top, and\n * users can always pick the exact content type the operation actually accepts.\n */\nconst contentTypeOptions = computed<{ id: string; label: string }[]>(() => {\n const builtIn = objectEntries(CONTENT_TYPES).map(([id, label]) => ({\n id,\n label,\n }))\n\n const extras = Object.keys(requestBody?.content ?? {})\n .filter((type) => {\n if (type in CONTENT_TYPES) {\n return false\n }\n // Same essence as a built-in (e.g. `application/json; charset=utf-8`) — do not duplicate the row.\n return !(contentTypeLabel(type) in CONTENT_TYPES)\n })\n .map((type) => ({ id: type, label: contentTypeLabel(type) }))\n\n return [...builtIn, ...extras]\n})\n\nconst selectedContentTypeModel = computed<{ id: string; label: string }>({\n get: () => {\n const found = contentTypeOptions.value.find(\n (it) => it.id === selectedContentType.value,\n )\n if (found) {\n return found\n }\n\n const essence = contentTypeLabel(selectedContentType.value)\n const friendly =\n CONTENT_TYPES[essence as keyof typeof CONTENT_TYPES] ?? essence\n\n return {\n id: selectedContentType.value,\n label: friendly,\n }\n },\n set: (v) => {\n emits('update:contentType', { value: v.id })\n },\n})\n\nfunction handleFileUpload(callback: (file: File) => void) {\n const { open } = useFileDialog({\n onChange: (files) => {\n const file = files?.[0]\n if (file) {\n callback(file)\n }\n },\n multiple: false,\n accept: '*/*',\n })\n open()\n}\n\n/** Dereferenced example */\nconst example = computed(\n () =>\n requestBody &&\n getExampleFromBody(\n requestBody,\n selectedContentType.value,\n exampleKey,\n requestBodyCompositionSelection,\n ),\n)\n\n/** Convert the example value to a string for the code editor */\nconst bodyValue = computed(() => {\n if (!example.value) {\n return ''\n }\n\n const value = example.value.value\n if (typeof value === 'string') {\n return value\n }\n\n return JSON.stringify(value, null, 2)\n})\n\n/** Resolved schema for the request body */\nconst bodySchema = computed<SchemaObject | undefined>(() => {\n return resolve.schema(\n requestBody?.content?.[selectedContentType.value]?.schema,\n )\n})\n\n/** Codec for structured (JSON/YAML) bodies, undefined for everything else */\nconst structuredCodec = computed(() =>\n selectedContentType.value === 'none'\n ? undefined\n : getStructuredBodyCodec(selectedContentType.value),\n)\n\n/** Parsed body value for the form view — `ok: false` when the raw text is not parseable */\nconst parsedBody = computed<{ ok: boolean; value?: unknown }>(() => {\n const codec = structuredCodec.value\n if (!codec) {\n return { ok: false }\n }\n\n const raw = example.value?.value\n // An empty body is still form-editable: rows come from the schema.\n if (raw === undefined || raw === null || raw === '') {\n return { ok: true, value: {} }\n }\n if (typeof raw === 'string') {\n try {\n return { ok: true, value: codec.parse(raw) }\n } catch {\n return { ok: false }\n }\n }\n // Spec-provided examples can be stored as objects directly.\n return { ok: true, value: raw }\n})\n\n/**\n * An edited example normally takes precedence over schema-generated data. When a different\n * composition branch is selected, however, keeping that example leaves the editor showing the\n * previous branch. Track the selection itself instead of inspecting discriminator fields so this\n * also works for compositions whose members are distinguished only by their shape.\n */\nconst compositionSelectionKey = computed(() =>\n JSON.stringify(requestBodyCompositionSelection ?? {}),\n)\n\n// Switching operations changes the body (and often the selection) at once, which is not a branch\n// change, so we only regenerate the body when the selection changes while the operation and example\n// stay the same. Watching all three together and comparing against the watcher's own previous values\n// keeps this correct regardless of the order in which props update or watchers flush.\nwatch(\n [() => requestBody, () => exampleKey, compositionSelectionKey],\n (\n [, , selection],\n [previousRequestBody, previousExampleKey, previousSelection],\n ) => {\n const operationChanged =\n requestBody !== previousRequestBody || exampleKey !== previousExampleKey\n const selectionChanged = selection !== previousSelection\n\n // Only a genuine branch switch within the same operation should reset the edited body. An empty\n // selection means there is no composition to switch between (or the selection was cleared on an\n // operation change), so there is nothing to reset.\n if (\n operationChanged ||\n !selectionChanged ||\n Object.keys(requestBodyCompositionSelection ?? {}).length === 0\n ) {\n return\n }\n\n const codec = structuredCodec.value\n if (!requestBody || !codec) {\n return\n }\n\n // Regenerate through the same helper the initial example uses so a reset produces exactly the\n // value a fresh render of this branch would, rather than a hand-copied second code path.\n const selectedValue = getSchemaExampleFromBody(\n requestBody,\n selectedContentType.value,\n requestBodyCompositionSelection,\n )\n\n emits('update:value', {\n // A branch with no writable content generates `null`/`undefined`; clear the editor rather than\n // writing the literal text `null` or leaving the previously selected branch's body behind.\n payload: selectedValue == null ? '' : codec.stringify(selectedValue),\n contentType: selectedContentType.value,\n })\n },\n)\n\n/** The form view only works on an object-shaped body root */\nconst isFormViewAvailable = computed(\n () => parsedBody.value.ok && isObject(parsedBody.value.value),\n)\n\n/**\n * Show the Form/Raw toggle for structured bodies that are (or per schema should be)\n * an object at the root. Non-object roots (arrays, primitives) stay raw-only.\n */\nconst showBodyViewToggle = computed(\n () =>\n Boolean(structuredCodec.value) &&\n (isFormViewAvailable.value ||\n Boolean(bodySchema.value && isObjectSchema(bodySchema.value))),\n)\n\n/** Selected body view, seeded from the document default (raw unless configured) */\nconst bodyView = ref<'form' | 'raw'>(defaultView)\n\n// Fall back to raw when the form view stops being available (e.g. the content type\n// changed to a non-structured one, or an external edit made the body unparseable).\nwatch(isFormViewAvailable, (ok) => {\n if (!ok) {\n bodyView.value = 'raw'\n }\n})\n</script>\n<template>\n <CollapsibleSection>\n <template #title>{{ title }}</template>\n <DataTable\n :columns=\"['']\"\n presentational>\n <DataTableHeader\n class=\"relative col-span-full flex h-8 cursor-pointer items-center justify-between border-r-0 !p-0\">\n <ScalarListbox\n v-model=\"selectedContentTypeModel\"\n :options=\"contentTypeOptions\"\n teleport>\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-3 font-normal\"\n fullWidth\n variant=\"ghost\">\n <span>{{ selectedContentTypeModel.label }}</span>\n <ScalarIcon\n icon=\"ChevronDown\"\n size=\"md\" />\n </ScalarButton>\n </ScalarListbox>\n <RequestBodyViewToggle\n v-if=\"showBodyViewToggle\"\n :disabled=\"!isFormViewAvailable\"\n :modelValue=\"bodyView\"\n @update:modelValue=\"(v) => (bodyView = v)\" />\n </DataTableHeader>\n <DataTableRow>\n <!-- No Body -->\n <template v-if=\"selectedContentType === 'none'\">\n <div\n class=\"text-c-3 flex min-h-10 w-full items-center justify-center border-t p-2 text-sm\">\n <span>No Body</span>\n </div>\n </template>\n\n <!-- Binary File -->\n <template\n v-else-if=\"selectedContentType === 'application/octet-stream'\">\n <div\n class=\"flex items-center justify-center overflow-hidden border-t p-1.5\">\n <template\n v-if=\"\n getFileName(unpackProxyObject(example?.value)) !== undefined\n \">\n <span\n class=\"text-c-2 w-full max-w-full overflow-hidden rounded border px-1.5 py-1 text-xs whitespace-nowrap\">\n {{ getFileName(unpackProxyObject(example?.value)) }}\n </span>\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 ml-1 border-0 shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n emits('update:value', {\n payload: undefined,\n contentType: selectedContentType,\n })\n \">\n Delete\n </ScalarButton>\n </template>\n <template v-else>\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 border-0 shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n () =>\n handleFileUpload((file) =>\n emits('update:value', {\n payload: file,\n contentType: selectedContentType,\n }),\n )\n \">\n <span>Select File</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </template>\n </div>\n </template>\n\n <!-- Form Data / URL Encoded -->\n <template\n v-else-if=\"\n selectedContentType === 'multipart/form-data' ||\n selectedContentType === 'application/x-www-form-urlencoded'\n \">\n <RequestBodyForm\n :bodySchema\n :environment\n :example\n :selectedContentType\n @update:formValue=\"\n (payload) =>\n emits('update:formValue', {\n payload,\n contentType: selectedContentType,\n })\n \" />\n </template>\n\n <!-- Code/Other -->\n <template v-else>\n <!-- Schema-driven form view for structured (JSON/YAML) bodies -->\n <RequestBodyStructured\n v-if=\"bodyView === 'form' && isFormViewAvailable\"\n :bodySchema\n :contentType=\"selectedContentType\"\n :environment\n :parsedValue=\"parsedBody.value\"\n @update:value=\"\n (value) =>\n emits('update:value', {\n payload: value,\n contentType: selectedContentType,\n })\n \" />\n <CodeInput\n v-else\n class=\"border-t px-3\"\n content=\"\"\n :environment=\"environment\"\n :language=\"\n contentTypeToLanguageMap[\n selectedContentType as keyof typeof contentTypeToLanguageMap\n ] ?? 'plaintext'\n \"\n lineNumbers\n lint\n :modelValue=\"bodyValue\"\n withFakeData\n @update:modelValue=\"\n (value) =>\n emits('update:value', {\n payload: value,\n contentType: selectedContentType,\n })\n \" />\n </template>\n </DataTableRow>\n </DataTable>\n </CollapsibleSection>\n</template>\n<style scoped>\n:deep(.cm-content) {\n font-size: var(--scalar-small);\n}\n</style>\n"],"mappings":"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"}
1
+ {"version":3,"file":"RequestBody.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestBody.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarIcon } from '@scalar/components/icon'\nimport { ScalarIconButton } from '@scalar/components/icon-button'\nimport { ScalarListbox } from '@scalar/components/listbox'\nimport { CONTENT_TYPES } from '@scalar/helpers/http/content-types'\nimport { parseMimeType } from '@scalar/helpers/http/mime-type'\nimport { isObject } from '@scalar/helpers/object/is-object'\nimport { objectEntries } from '@scalar/helpers/object/object-entries'\nimport { ScalarIconMagicWand } from '@scalar/icons'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n getExampleFromBody,\n getSchemaExampleFromBody,\n getSelectedBodyContentType,\n} from '@scalar/workspace-store/request-example'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n RequestBodyObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { isObjectSchema } from '@scalar/workspace-store/schemas/v3.2/strict/type-guards'\nimport { computed, ref, watch } from 'vue'\n\nimport { useFileDialog } from '@/hooks/use-file-dialog'\nimport RequestBodyForm from '@/v2/blocks/request-block/components/RequestBodyForm.vue'\nimport RequestBodyStructured from '@/v2/blocks/request-block/components/RequestBodyStructured.vue'\nimport RequestBodyViewToggle from '@/v2/blocks/request-block/components/RequestBodyViewToggle.vue'\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { getStructuredBodyCodec } from '@/v2/blocks/request-block/helpers/structured-body-codec'\nimport { CodeInput } from '@/v2/components/code-input'\nimport {\n DataTable,\n DataTableHeader,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { CollapsibleSection } from '@/v2/components/layout'\n\nconst {\n requestBody,\n exampleKey,\n environment,\n requestBodyCompositionSelection,\n title,\n defaultView = 'raw',\n} = defineProps<{\n /** Request body */\n requestBody?: RequestBodyObject\n /** Currently selected example key for the current operation */\n exampleKey: string\n /** Display title */\n title: string\n /** Selected environment */\n environment: XScalarEnvironment\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n /**\n * Initial view for structured (JSON/YAML) bodies. Comes from the\n * `x-scalar-default-request-body-view` document extension and falls back to `raw`\n * whenever the body cannot be shown as a form.\n */\n defaultView?: 'form' | 'raw'\n}>()\n\nconst emits = defineEmits<{\n (e: 'update:contentType', payload: { value: string }): void\n /** We use this event to update raw values */\n (\n e: 'update:value',\n payload: Pick<\n ApiReferenceEvents['operation:update:requestBody:value'],\n 'payload' | 'contentType'\n >,\n ): void\n /** We use this event when updating form data only */\n (\n e: 'update:formValue',\n payload: Pick<\n ApiReferenceEvents['operation:update:requestBody:formValue'],\n 'payload' | 'contentType'\n >,\n ): void\n /**\n * Create a new example seeded with values generated from the request body schema.\n *\n * The block itself owns the document and operation identity needed to create an example, so we\n * only report the content type the user is currently looking at.\n */\n (e: 'generate:example', payload: { contentType: string }): void\n}>()\n\n// Map a content type to a language for the code editor\nconst contentTypeToLanguageMap = {\n 'application/json': 'json',\n 'application/xml': 'xml',\n 'application/yaml': 'yaml',\n} as const\n\n/** Selected content type with default */\nconst selectedContentType = computed(\n () => getSelectedBodyContentType(requestBody, exampleKey) ?? 'none',\n)\n\n/**\n * Strips MIME parameters (such as `charset=utf-8`) for dropdown labels, aligned with how we treat\n * media types elsewhere (see api-reference `normalizeMimeType` / WHATWG essence).\n */\nconst contentTypeLabel = (raw: string): string => parseMimeType(raw).essence\n\n/**\n * Build the dropdown options for the content type selector.\n *\n * The list is composed of two groups:\n * 1. The built-in content types we ship friendly labels for (JSON, XML, Multipart Form, etc.).\n * 2. Any additional content types defined on the OpenAPI request body that are not in the built-in list\n * (for example `text/csv`, `application/pdf`, vendor types like `application/vnd.api+json`, ...).\n *\n * The OpenAPI-defined extras are appended at the bottom so the well-known options stay on top, and\n * users can always pick the exact content type the operation actually accepts.\n */\nconst contentTypeOptions = computed<{ id: string; label: string }[]>(() => {\n const builtIn = objectEntries(CONTENT_TYPES).map(([id, label]) => ({\n id,\n label,\n }))\n\n const extras = Object.keys(requestBody?.content ?? {})\n .filter((type) => {\n if (type in CONTENT_TYPES) {\n return false\n }\n // Same essence as a built-in (e.g. `application/json; charset=utf-8`) — do not duplicate the row.\n return !(contentTypeLabel(type) in CONTENT_TYPES)\n })\n .map((type) => ({ id: type, label: contentTypeLabel(type) }))\n\n return [...builtIn, ...extras]\n})\n\nconst selectedContentTypeModel = computed<{ id: string; label: string }>({\n get: () => {\n const found = contentTypeOptions.value.find(\n (it) => it.id === selectedContentType.value,\n )\n if (found) {\n return found\n }\n\n const essence = contentTypeLabel(selectedContentType.value)\n const friendly =\n CONTENT_TYPES[essence as keyof typeof CONTENT_TYPES] ?? essence\n\n return {\n id: selectedContentType.value,\n label: friendly,\n }\n },\n set: (v) => {\n emits('update:contentType', { value: v.id })\n },\n})\n\nfunction handleFileUpload(callback: (file: File) => void) {\n const { open } = useFileDialog({\n onChange: (files) => {\n const file = files?.[0]\n if (file) {\n callback(file)\n }\n },\n multiple: false,\n accept: '*/*',\n })\n open()\n}\n\n/** Dereferenced example */\nconst example = computed(\n () =>\n requestBody &&\n getExampleFromBody(\n requestBody,\n selectedContentType.value,\n exampleKey,\n requestBodyCompositionSelection,\n ),\n)\n\n/** Convert the example value to a string for the code editor */\nconst bodyValue = computed(() => {\n if (!example.value) {\n return ''\n }\n\n const value = example.value.value\n if (typeof value === 'string') {\n return value\n }\n\n return JSON.stringify(value, null, 2)\n})\n\n/** Resolved schema for the request body */\nconst bodySchema = computed<SchemaObject | undefined>(() => {\n return resolve.schema(\n requestBody?.content?.[selectedContentType.value]?.schema,\n )\n})\n\n/** Codec for structured (JSON/YAML) bodies, undefined for everything else */\nconst structuredCodec = computed(() =>\n selectedContentType.value === 'none'\n ? undefined\n : getStructuredBodyCodec(selectedContentType.value),\n)\n\n/** Parsed body value for the form view — `ok: false` when the raw text is not parseable */\nconst parsedBody = computed<{ ok: boolean; value?: unknown }>(() => {\n const codec = structuredCodec.value\n if (!codec) {\n return { ok: false }\n }\n\n const raw = example.value?.value\n // An empty body is still form-editable: rows come from the schema.\n if (raw === undefined || raw === null || raw === '') {\n return { ok: true, value: {} }\n }\n if (typeof raw === 'string') {\n try {\n return { ok: true, value: codec.parse(raw) }\n } catch {\n return { ok: false }\n }\n }\n // Spec-provided examples can be stored as objects directly.\n return { ok: true, value: raw }\n})\n\n/**\n * An edited example normally takes precedence over schema-generated data. When a different\n * composition branch is selected, however, keeping that example leaves the editor showing the\n * previous branch. Track the selection itself instead of inspecting discriminator fields so this\n * also works for compositions whose members are distinguished only by their shape.\n */\nconst compositionSelectionKey = computed(() =>\n JSON.stringify(requestBodyCompositionSelection ?? {}),\n)\n\n// Switching operations changes the body (and often the selection) at once, which is not a branch\n// change, so we only regenerate the body when the selection changes while the operation and example\n// stay the same. Watching all three together and comparing against the watcher's own previous values\n// keeps this correct regardless of the order in which props update or watchers flush.\nwatch(\n [() => requestBody, () => exampleKey, compositionSelectionKey],\n (\n [, , selection],\n [previousRequestBody, previousExampleKey, previousSelection],\n ) => {\n const operationChanged =\n requestBody !== previousRequestBody || exampleKey !== previousExampleKey\n const selectionChanged = selection !== previousSelection\n\n // Going from no selection to a populated one is the modal applying the reference's selection as\n // the panel opens, not the user switching branches. Resetting here would discard the body's named\n // example on the very first open (issue #10075), so only a change between two populated selections\n // counts as a real branch switch.\n const hadNoPreviousSelection = previousSelection === '{}'\n\n // Only a genuine branch switch within the same operation should reset the edited body. An empty\n // selection means there is no composition to switch between (or the selection was cleared on an\n // operation change), so there is nothing to reset.\n if (\n operationChanged ||\n !selectionChanged ||\n hadNoPreviousSelection ||\n Object.keys(requestBodyCompositionSelection ?? {}).length === 0\n ) {\n return\n }\n\n const codec = structuredCodec.value\n if (!requestBody || !codec) {\n return\n }\n\n // Regenerate through the same helper the initial example uses so a reset produces exactly the\n // value a fresh render of this branch would, rather than a hand-copied second code path.\n const selectedValue = getSchemaExampleFromBody(\n requestBody,\n selectedContentType.value,\n requestBodyCompositionSelection,\n )\n\n emits('update:value', {\n // A branch with no writable content generates `null`/`undefined`; clear the editor rather than\n // writing the literal text `null` or leaving the previously selected branch's body behind.\n payload: selectedValue == null ? '' : codec.stringify(selectedValue),\n contentType: selectedContentType.value,\n })\n },\n)\n\n/** The form view only works on an object-shaped body root */\nconst isFormViewAvailable = computed(\n () => parsedBody.value.ok && isObject(parsedBody.value.value),\n)\n\n/**\n * Show the Form/Raw toggle for structured bodies that are (or per schema should be)\n * an object at the root. Non-object roots (arrays, primitives) stay raw-only.\n */\nconst showBodyViewToggle = computed(\n () =>\n Boolean(structuredCodec.value) &&\n (isFormViewAvailable.value ||\n Boolean(bodySchema.value && isObjectSchema(bodySchema.value))),\n)\n\n/** Selected body view, seeded from the document default (raw unless configured) */\nconst bodyView = ref<'form' | 'raw'>(defaultView)\n\n// Fall back to raw when the form view stops being available (e.g. the content type\n// changed to a non-structured one, or an external edit made the body unparseable).\nwatch(isFormViewAvailable, (ok) => {\n if (!ok) {\n bodyView.value = 'raw'\n }\n})\n\n/**\n * Whether we can offer to generate a fresh example from the schema.\n *\n * Only structured (JSON/YAML) bodies qualify: they have a schema to generate from and a text\n * representation we can seed the new example with. Binary and form bodies have their own editors,\n * so the button would have nothing meaningful to write.\n */\nconst canGenerateExample = computed(() =>\n Boolean(structuredCodec.value && bodySchema.value),\n)\n</script>\n<template>\n <CollapsibleSection>\n <template #title>{{ title }}</template>\n <DataTable\n :columns=\"['']\"\n presentational>\n <DataTableHeader\n class=\"relative col-span-full flex h-8 cursor-pointer items-center justify-between border-r-0 !p-0\">\n <ScalarListbox\n v-model=\"selectedContentTypeModel\"\n :options=\"contentTypeOptions\"\n teleport>\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-3 font-normal\"\n fullWidth\n variant=\"ghost\">\n <span>{{ selectedContentTypeModel.label }}</span>\n <ScalarIcon\n icon=\"ChevronDown\"\n size=\"md\" />\n </ScalarButton>\n </ScalarListbox>\n <div class=\"flex items-center gap-1\">\n <!--\n Generates a new example from the schema so the auto-generated fields stay reachable\n even once the document ships custom examples.\n -->\n <ScalarIconButton\n v-if=\"canGenerateExample\"\n aria-label=\"Generate example from schema\"\n :icon=\"ScalarIconMagicWand\"\n label=\"Generate example from schema\"\n size=\"sm\"\n tooltip\n @click.stop=\"\n emits('generate:example', { contentType: selectedContentType })\n \" />\n <RequestBodyViewToggle\n v-if=\"showBodyViewToggle\"\n :disabled=\"!isFormViewAvailable\"\n :modelValue=\"bodyView\"\n @update:modelValue=\"(v) => (bodyView = v)\" />\n </div>\n </DataTableHeader>\n <DataTableRow>\n <!-- No Body -->\n <template v-if=\"selectedContentType === 'none'\">\n <div\n class=\"text-c-3 flex min-h-10 w-full items-center justify-center border-t p-2 text-sm\">\n <span>No Body</span>\n </div>\n </template>\n\n <!-- Binary File -->\n <template\n v-else-if=\"selectedContentType === 'application/octet-stream'\">\n <div\n class=\"flex items-center justify-center overflow-hidden border-t p-1.5\">\n <template\n v-if=\"\n getFileName(unpackProxyObject(example?.value)) !== undefined\n \">\n <span\n class=\"text-c-2 w-full max-w-full overflow-hidden rounded border px-1.5 py-1 text-xs whitespace-nowrap\">\n {{ getFileName(unpackProxyObject(example?.value)) }}\n </span>\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 ml-1 border-0 shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n emits('update:value', {\n payload: undefined,\n contentType: selectedContentType,\n })\n \">\n Delete\n </ScalarButton>\n </template>\n <template v-else>\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 border-0 shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n () =>\n handleFileUpload((file) =>\n emits('update:value', {\n payload: file,\n contentType: selectedContentType,\n }),\n )\n \">\n <span>Select File</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </template>\n </div>\n </template>\n\n <!-- Form Data / URL Encoded -->\n <template\n v-else-if=\"\n selectedContentType === 'multipart/form-data' ||\n selectedContentType === 'application/x-www-form-urlencoded'\n \">\n <RequestBodyForm\n :bodySchema\n :environment\n :example\n :selectedContentType\n @update:formValue=\"\n (payload) =>\n emits('update:formValue', {\n payload,\n contentType: selectedContentType,\n })\n \" />\n </template>\n\n <!-- Code/Other -->\n <template v-else>\n <!-- Schema-driven form view for structured (JSON/YAML) bodies -->\n <RequestBodyStructured\n v-if=\"bodyView === 'form' && isFormViewAvailable\"\n :bodySchema\n :contentType=\"selectedContentType\"\n :environment\n :parsedValue=\"parsedBody.value\"\n @update:value=\"\n (value) =>\n emits('update:value', {\n payload: value,\n contentType: selectedContentType,\n })\n \" />\n <CodeInput\n v-else\n class=\"border-t px-3\"\n content=\"\"\n :environment=\"environment\"\n :language=\"\n contentTypeToLanguageMap[\n selectedContentType as keyof typeof contentTypeToLanguageMap\n ] ?? 'plaintext'\n \"\n lineNumbers\n lint\n :modelValue=\"bodyValue\"\n withFakeData\n @update:modelValue=\"\n (value) =>\n emits('update:value', {\n payload: value,\n contentType: selectedContentType,\n })\n \" />\n </template>\n </DataTableRow>\n </DataTable>\n </CollapsibleSection>\n</template>\n<style scoped>\n:deep(.cm-content) {\n font-size: var(--scalar-small);\n}\n</style>\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments';
2
- import type { ExampleObject, SchemaObject } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document';
2
+ import type { ExampleObject, SchemaObject } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document';
3
3
  type __VLS_Props = {
4
4
  example: ExampleObject | undefined | null;
5
5
  /** Resolved schema for the form body so the table can show enums and validation per field */
@@ -10,14 +10,16 @@ type __VLS_Props = {
10
10
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
11
11
  "update:formValue": (payload: {
12
12
  name: string;
13
- value: string | File;
13
+ value: string | File | unknown[] | undefined;
14
14
  isDisabled: boolean;
15
+ isArray?: boolean;
15
16
  }[]) => any;
16
17
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
17
18
  "onUpdate:formValue"?: ((payload: {
18
19
  name: string;
19
- value: string | File;
20
+ value: string | File | unknown[] | undefined;
20
21
  isDisabled: boolean;
22
+ isArray?: boolean;
21
23
  }[]) => any) | undefined;
22
24
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
23
25
  declare const _default: typeof __VLS_export;
@@ -1 +1 @@
1
- {"version":3,"file":"RequestBodyForm.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestBodyForm.vue"],"names":[],"mappings":"AAoIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AACnH,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACb,MAAM,8DAA8D,CAAA;AAQrE,KAAK,WAAW,GAAG;IACjB,OAAO,EAAE,aAAa,GAAG,SAAS,GAAG,IAAI,CAAA;IACzC,6FAA6F;IAC7F,UAAU,CAAC,EAAE,YAAY,CAAA;IACzB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,WAAW,EAAE,kBAAkB,CAAA;CAChC,CAAC;AAyLF,QAAA,MAAM,YAAY;;;;;;;;;;;;kFAGhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
1
+ {"version":3,"file":"RequestBodyForm.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestBodyForm.vue"],"names":[],"mappings":"AA+IA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AACnH,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACb,MAAM,8DAA8D,CAAA;AAWrE,KAAK,WAAW,GAAG;IACjB,OAAO,EAAE,aAAa,GAAG,SAAS,GAAG,IAAI,CAAA;IACzC,6FAA6F;IAC7F,UAAU,CAAC,EAAE,YAAY,CAAA;IACzB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,WAAW,EAAE,kBAAkB,CAAA;CAChC,CAAC;AAmMF,QAAA,MAAM,YAAY;;;;;;;;;;;;;;kFAGhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
@@ -1 +1 @@
1
- {"version":3,"file":"RequestBodyForm.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestBodyForm.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n ExampleObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { ref, watch } from 'vue'\n\nimport { useFileDialog } from '@/hooks/use-file-dialog'\nimport RequestTable from '@/v2/blocks/request-block/components/RequestTable.vue'\nimport type { TableRow } from '@/v2/blocks/request-block/components/RequestTableRow.vue'\nimport { getFormBodyRows } from '@/v2/blocks/request-block/helpers/get-form-body-rows'\n\nconst { example, bodySchema, selectedContentType, environment } = defineProps<{\n example: ExampleObject | undefined | null\n /** Resolved schema for the form body so the table can show enums and validation per field */\n bodySchema?: SchemaObject\n selectedContentType: string\n environment: XScalarEnvironment\n}>()\n\nconst emit = defineEmits<{\n (\n e: 'update:formValue',\n payload: ApiReferenceEvents['operation:update:requestBody:formValue']['payload'],\n ): void\n}>()\n\n/** Local state for form body rows */\nconst localFormBodyRows = ref<TableRow[]>([])\n\n/** Sync the local form body rows with the example and schema */\nwatch(\n () => [example, bodySchema, selectedContentType] as const,\n ([newExample, schema, contentType]) => {\n localFormBodyRows.value = getFormBodyRows(newExample, contentType, schema)\n },\n { immediate: true },\n)\n\nconst handleUpdateFormValue = (rows: TableRow[]) => {\n emit(\n 'update:formValue',\n rows.map((row) => ({\n name: row.name,\n value: row.value as string | File,\n isDisabled: row.isDisabled ?? false,\n })),\n )\n}\n\n/** Update a row in the table, combines with the previous data so we emit a whole row */\nconst handleUpsertRow = (\n index: number,\n payload: Partial<{\n name: string\n value: string | File | undefined\n isDisabled: boolean\n }>,\n) => {\n // Add new row\n if (index >= localFormBodyRows.value.length) {\n localFormBodyRows.value = [\n ...localFormBodyRows.value,\n { name: '', value: '', ...payload, isDisabled: false },\n ]\n handleUpdateFormValue(localFormBodyRows.value)\n return\n }\n\n localFormBodyRows.value = localFormBodyRows.value.map((row, i) =>\n i === index ? { ...row, ...payload } : row,\n )\n handleUpdateFormValue(localFormBodyRows.value)\n}\n\n/** Delete a row from the table */\nconst handleDeleteRow = (index: number) => {\n localFormBodyRows.value = localFormBodyRows.value.filter(\n (_, i) => i !== index,\n )\n handleUpdateFormValue(localFormBodyRows.value)\n}\n\n/** Handle file upload for a specific row index */\nconst handleFileUpload = (index: number) => {\n const { open } = useFileDialog({\n onChange: (files) => {\n const file = files?.[0]\n\n if (file) {\n const currentRow = localFormBodyRows.value[index]\n handleUpsertRow(index, {\n name: currentRow?.name || file.name,\n value: file,\n })\n }\n },\n multiple: false,\n accept: '*/*',\n })\n open()\n}\n</script>\n\n<template>\n <!-- Form Data -->\n <template v-if=\"selectedContentType === 'multipart/form-data'\">\n <RequestTable\n :data=\"localFormBodyRows\"\n :environment=\"environment\"\n showUploadButton\n @deleteRow=\"handleDeleteRow\"\n @removeFile=\"(index) => handleUpsertRow(index, { value: undefined })\"\n @uploadFile=\"handleFileUpload\"\n @upsertRow=\"handleUpsertRow\" />\n </template>\n\n <!-- Form URL Encoded -->\n <template v-else>\n <RequestTable\n :data=\"localFormBodyRows\"\n :environment=\"environment\"\n @deleteRow=\"handleDeleteRow\"\n @upsertRow=\"handleUpsertRow\" />\n </template>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"RequestBodyForm.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestBodyForm.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n ExampleObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { ref, watch } from 'vue'\n\nimport { useFileDialog } from '@/hooks/use-file-dialog'\nimport RequestTable from '@/v2/blocks/request-block/components/RequestTable.vue'\nimport type { TableRow } from '@/v2/blocks/request-block/components/RequestTableRow.vue'\nimport {\n getFormBodyRows,\n getFormBodyValue,\n} from '@/v2/blocks/request-block/helpers/get-form-body-rows'\n\nconst { example, bodySchema, selectedContentType, environment } = defineProps<{\n example: ExampleObject | undefined | null\n /** Resolved schema for the form body so the table can show enums and validation per field */\n bodySchema?: SchemaObject\n selectedContentType: string\n environment: XScalarEnvironment\n}>()\n\nconst emit = defineEmits<{\n (\n e: 'update:formValue',\n payload: ApiReferenceEvents['operation:update:requestBody:formValue']['payload'],\n ): void\n}>()\n\n/** Local state for form body rows */\nconst localFormBodyRows = ref<TableRow[]>([])\n\n/** Sync the local form body rows with the example and schema */\nwatch(\n () => [example, bodySchema, selectedContentType] as const,\n ([newExample, schema, contentType]) => {\n localFormBodyRows.value = getFormBodyRows(newExample, contentType, schema)\n },\n { immediate: true },\n)\n\nconst handleUpdateFormValue = (rows: TableRow[]) => {\n emit(\n 'update:formValue',\n rows.map((row) => ({\n name: row.name,\n value:\n selectedContentType === 'multipart/form-data'\n ? getFormBodyValue(row)\n : (row.value as string | File),\n isDisabled: row.isDisabled ?? false,\n ...(selectedContentType === 'multipart/form-data' && row.isArray\n ? { isArray: true }\n : {}),\n })),\n )\n}\n\n/** Update a row in the table, combines with the previous data so we emit a whole row */\nconst handleUpsertRow = (\n index: number,\n payload: Partial<{\n name: string\n value: string | File | undefined\n isDisabled: boolean\n }>,\n) => {\n // Add new row\n if (index >= localFormBodyRows.value.length) {\n localFormBodyRows.value = [\n ...localFormBodyRows.value,\n { name: '', value: '', ...payload, isDisabled: false },\n ]\n handleUpdateFormValue(localFormBodyRows.value)\n return\n }\n\n localFormBodyRows.value = localFormBodyRows.value.map((row, i) =>\n i === index ? { ...row, ...payload } : row,\n )\n handleUpdateFormValue(localFormBodyRows.value)\n}\n\n/** Delete a row from the table */\nconst handleDeleteRow = (index: number) => {\n localFormBodyRows.value = localFormBodyRows.value.filter(\n (_, i) => i !== index,\n )\n handleUpdateFormValue(localFormBodyRows.value)\n}\n\n/** Handle file upload for a specific row index */\nconst handleFileUpload = (index: number) => {\n const { open } = useFileDialog({\n onChange: (files) => {\n const file = files?.[0]\n\n if (file) {\n const currentRow = localFormBodyRows.value[index]\n handleUpsertRow(index, {\n name: currentRow?.name || file.name,\n value: file,\n })\n }\n },\n multiple: false,\n accept: '*/*',\n })\n open()\n}\n</script>\n\n<template>\n <!-- Form Data -->\n <template v-if=\"selectedContentType === 'multipart/form-data'\">\n <RequestTable\n :data=\"localFormBodyRows\"\n deferKeyUpdates\n :environment=\"environment\"\n showUploadButton\n @deleteRow=\"handleDeleteRow\"\n @removeFile=\"(index) => handleUpsertRow(index, { value: undefined })\"\n @uploadFile=\"handleFileUpload\"\n @upsertRow=\"handleUpsertRow\" />\n </template>\n\n <!-- Form URL Encoded -->\n <template v-else>\n <RequestTable\n :data=\"localFormBodyRows\"\n deferKeyUpdates\n :environment=\"environment\"\n @deleteRow=\"handleDeleteRow\"\n @upsertRow=\"handleUpsertRow\" />\n </template>\n</template>\n"],"mappings":""}
@@ -1,6 +1,6 @@
1
1
  import { useFileDialog } from "../../../../hooks/use-file-dialog.js";
2
2
  import RequestTable_default from "./RequestTable.vue.js";
3
- import { getFormBodyRows } from "../helpers/get-form-body-rows.js";
3
+ import { getFormBodyRows, getFormBodyValue } from "../helpers/get-form-body-rows.js";
4
4
  import { createBlock, defineComponent, openBlock, ref, watch } from "vue";
5
5
  //#region src/v2/blocks/request-block/components/RequestBodyForm.vue?vue&type=script&setup=true&lang.ts
6
6
  var RequestBodyForm_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
@@ -27,8 +27,9 @@ var RequestBodyForm_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
27
27
  const handleUpdateFormValue = (rows) => {
28
28
  emit("update:formValue", rows.map((row) => ({
29
29
  name: row.name,
30
- value: row.value,
31
- isDisabled: row.isDisabled ?? false
30
+ value: __props.selectedContentType === "multipart/form-data" ? getFormBodyValue(row) : row.value,
31
+ isDisabled: row.isDisabled ?? false,
32
+ ...__props.selectedContentType === "multipart/form-data" && row.isArray ? { isArray: true } : {}
32
33
  })));
33
34
  };
34
35
  /** Update a row in the table, combines with the previous data so we emit a whole row */
@@ -76,6 +77,7 @@ var RequestBodyForm_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
76
77
  return __props.selectedContentType === "multipart/form-data" ? (openBlock(), createBlock(RequestTable_default, {
77
78
  key: 0,
78
79
  data: localFormBodyRows.value,
80
+ deferKeyUpdates: "",
79
81
  environment: __props.environment,
80
82
  showUploadButton: "",
81
83
  onDeleteRow: handleDeleteRow,
@@ -85,6 +87,7 @@ var RequestBodyForm_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
85
87
  }, null, 8, ["data", "environment"])) : (openBlock(), createBlock(RequestTable_default, {
86
88
  key: 1,
87
89
  data: localFormBodyRows.value,
90
+ deferKeyUpdates: "",
88
91
  environment: __props.environment,
89
92
  onDeleteRow: handleDeleteRow,
90
93
  onUpsertRow: handleUpsertRow
@@ -1 +1 @@
1
- {"version":3,"file":"RequestBodyForm.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestBodyForm.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n ExampleObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { ref, watch } from 'vue'\n\nimport { useFileDialog } from '@/hooks/use-file-dialog'\nimport RequestTable from '@/v2/blocks/request-block/components/RequestTable.vue'\nimport type { TableRow } from '@/v2/blocks/request-block/components/RequestTableRow.vue'\nimport { getFormBodyRows } from '@/v2/blocks/request-block/helpers/get-form-body-rows'\n\nconst { example, bodySchema, selectedContentType, environment } = defineProps<{\n example: ExampleObject | undefined | null\n /** Resolved schema for the form body so the table can show enums and validation per field */\n bodySchema?: SchemaObject\n selectedContentType: string\n environment: XScalarEnvironment\n}>()\n\nconst emit = defineEmits<{\n (\n e: 'update:formValue',\n payload: ApiReferenceEvents['operation:update:requestBody:formValue']['payload'],\n ): void\n}>()\n\n/** Local state for form body rows */\nconst localFormBodyRows = ref<TableRow[]>([])\n\n/** Sync the local form body rows with the example and schema */\nwatch(\n () => [example, bodySchema, selectedContentType] as const,\n ([newExample, schema, contentType]) => {\n localFormBodyRows.value = getFormBodyRows(newExample, contentType, schema)\n },\n { immediate: true },\n)\n\nconst handleUpdateFormValue = (rows: TableRow[]) => {\n emit(\n 'update:formValue',\n rows.map((row) => ({\n name: row.name,\n value: row.value as string | File,\n isDisabled: row.isDisabled ?? false,\n })),\n )\n}\n\n/** Update a row in the table, combines with the previous data so we emit a whole row */\nconst handleUpsertRow = (\n index: number,\n payload: Partial<{\n name: string\n value: string | File | undefined\n isDisabled: boolean\n }>,\n) => {\n // Add new row\n if (index >= localFormBodyRows.value.length) {\n localFormBodyRows.value = [\n ...localFormBodyRows.value,\n { name: '', value: '', ...payload, isDisabled: false },\n ]\n handleUpdateFormValue(localFormBodyRows.value)\n return\n }\n\n localFormBodyRows.value = localFormBodyRows.value.map((row, i) =>\n i === index ? { ...row, ...payload } : row,\n )\n handleUpdateFormValue(localFormBodyRows.value)\n}\n\n/** Delete a row from the table */\nconst handleDeleteRow = (index: number) => {\n localFormBodyRows.value = localFormBodyRows.value.filter(\n (_, i) => i !== index,\n )\n handleUpdateFormValue(localFormBodyRows.value)\n}\n\n/** Handle file upload for a specific row index */\nconst handleFileUpload = (index: number) => {\n const { open } = useFileDialog({\n onChange: (files) => {\n const file = files?.[0]\n\n if (file) {\n const currentRow = localFormBodyRows.value[index]\n handleUpsertRow(index, {\n name: currentRow?.name || file.name,\n value: file,\n })\n }\n },\n multiple: false,\n accept: '*/*',\n })\n open()\n}\n</script>\n\n<template>\n <!-- Form Data -->\n <template v-if=\"selectedContentType === 'multipart/form-data'\">\n <RequestTable\n :data=\"localFormBodyRows\"\n :environment=\"environment\"\n showUploadButton\n @deleteRow=\"handleDeleteRow\"\n @removeFile=\"(index) => handleUpsertRow(index, { value: undefined })\"\n @uploadFile=\"handleFileUpload\"\n @upsertRow=\"handleUpsertRow\" />\n </template>\n\n <!-- Form URL Encoded -->\n <template v-else>\n <RequestTable\n :data=\"localFormBodyRows\"\n :environment=\"environment\"\n @deleteRow=\"handleDeleteRow\"\n @upsertRow=\"handleUpsertRow\" />\n </template>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;EAsBA,MAAM,OAAO;;EAQb,MAAM,oBAAoB,IAAgB,CAAC,CAAC;;EAG5C,YACQ;GAAC,QAAA;GAAS,QAAA;GAAY,QAAA;EAAmB,IAC9C,CAAC,YAAY,QAAQ,iBAAiB;GACrC,kBAAkB,QAAQ,gBAAgB,YAAY,aAAa,MAAM;EAC3E,GACA,EAAE,WAAW,KAAK,CACpB;EAEA,MAAM,yBAAyB,SAAqB;GAClD,KACE,oBACA,KAAK,KAAK,SAAS;IACjB,MAAM,IAAI;IACV,OAAO,IAAI;IACX,YAAY,IAAI,cAAc;GAChC,EAAE,CACJ;EACF;;EAGA,MAAM,mBACJ,OACA,YAKG;GAEH,IAAI,SAAS,kBAAkB,MAAM,QAAQ;IAC3C,kBAAkB,QAAQ,CACxB,GAAG,kBAAkB,OACrB;KAAE,MAAM;KAAI,OAAO;KAAI,GAAG;KAAS,YAAY;IAAM,CACvD;IACA,sBAAsB,kBAAkB,KAAK;IAC7C;GACF;GAEA,kBAAkB,QAAQ,kBAAkB,MAAM,KAAK,KAAK,MAC1D,MAAM,QAAQ;IAAE,GAAG;IAAK,GAAG;GAAQ,IAAI,GACzC;GACA,sBAAsB,kBAAkB,KAAK;EAC/C;;EAGA,MAAM,mBAAmB,UAAkB;GACzC,kBAAkB,QAAQ,kBAAkB,MAAM,QAC/C,GAAG,MAAM,MAAM,KAClB;GACA,sBAAsB,kBAAkB,KAAK;EAC/C;;EAGA,MAAM,oBAAoB,UAAkB;GAC1C,MAAM,EAAE,SAAS,cAAc;IAC7B,WAAW,UAAU;KACnB,MAAM,OAAO,QAAQ;KAErB,IAAI,MAAM;MACR,MAAM,aAAa,kBAAkB,MAAM;MAC3C,gBAAgB,OAAO;OACrB,MAAM,YAAY,QAAQ,KAAK;OAC/B,OAAO;MACT,CAAC;KACH;IACF;IACA,UAAU;IACV,QAAQ;GACV,CAAC;GACD,KAAK;EACP;;UAKkB,QAAA,wBAAmB,yBAAA,UAAA,GACjC,YAOiC,sBAAA;;IAN9B,MAAM,kBAAA;IACN,aAAa,QAAA;IACd,kBAAA;IACC,aAAW;IACX,cAAU,OAAA,OAAA,OAAA,MAAG,UAAU,gBAAgB,OAAK,EAAA,OAAW,KAAA,EAAS,CAAA;IAChE,cAAY;IACZ,aAAW;yDAKd,YAIiC,sBAAA;;IAH9B,MAAM,kBAAA;IACN,aAAa,QAAA;IACb,aAAW;IACX,aAAW"}
1
+ {"version":3,"file":"RequestBodyForm.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestBodyForm.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n ExampleObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { ref, watch } from 'vue'\n\nimport { useFileDialog } from '@/hooks/use-file-dialog'\nimport RequestTable from '@/v2/blocks/request-block/components/RequestTable.vue'\nimport type { TableRow } from '@/v2/blocks/request-block/components/RequestTableRow.vue'\nimport {\n getFormBodyRows,\n getFormBodyValue,\n} from '@/v2/blocks/request-block/helpers/get-form-body-rows'\n\nconst { example, bodySchema, selectedContentType, environment } = defineProps<{\n example: ExampleObject | undefined | null\n /** Resolved schema for the form body so the table can show enums and validation per field */\n bodySchema?: SchemaObject\n selectedContentType: string\n environment: XScalarEnvironment\n}>()\n\nconst emit = defineEmits<{\n (\n e: 'update:formValue',\n payload: ApiReferenceEvents['operation:update:requestBody:formValue']['payload'],\n ): void\n}>()\n\n/** Local state for form body rows */\nconst localFormBodyRows = ref<TableRow[]>([])\n\n/** Sync the local form body rows with the example and schema */\nwatch(\n () => [example, bodySchema, selectedContentType] as const,\n ([newExample, schema, contentType]) => {\n localFormBodyRows.value = getFormBodyRows(newExample, contentType, schema)\n },\n { immediate: true },\n)\n\nconst handleUpdateFormValue = (rows: TableRow[]) => {\n emit(\n 'update:formValue',\n rows.map((row) => ({\n name: row.name,\n value:\n selectedContentType === 'multipart/form-data'\n ? getFormBodyValue(row)\n : (row.value as string | File),\n isDisabled: row.isDisabled ?? false,\n ...(selectedContentType === 'multipart/form-data' && row.isArray\n ? { isArray: true }\n : {}),\n })),\n )\n}\n\n/** Update a row in the table, combines with the previous data so we emit a whole row */\nconst handleUpsertRow = (\n index: number,\n payload: Partial<{\n name: string\n value: string | File | undefined\n isDisabled: boolean\n }>,\n) => {\n // Add new row\n if (index >= localFormBodyRows.value.length) {\n localFormBodyRows.value = [\n ...localFormBodyRows.value,\n { name: '', value: '', ...payload, isDisabled: false },\n ]\n handleUpdateFormValue(localFormBodyRows.value)\n return\n }\n\n localFormBodyRows.value = localFormBodyRows.value.map((row, i) =>\n i === index ? { ...row, ...payload } : row,\n )\n handleUpdateFormValue(localFormBodyRows.value)\n}\n\n/** Delete a row from the table */\nconst handleDeleteRow = (index: number) => {\n localFormBodyRows.value = localFormBodyRows.value.filter(\n (_, i) => i !== index,\n )\n handleUpdateFormValue(localFormBodyRows.value)\n}\n\n/** Handle file upload for a specific row index */\nconst handleFileUpload = (index: number) => {\n const { open } = useFileDialog({\n onChange: (files) => {\n const file = files?.[0]\n\n if (file) {\n const currentRow = localFormBodyRows.value[index]\n handleUpsertRow(index, {\n name: currentRow?.name || file.name,\n value: file,\n })\n }\n },\n multiple: false,\n accept: '*/*',\n })\n open()\n}\n</script>\n\n<template>\n <!-- Form Data -->\n <template v-if=\"selectedContentType === 'multipart/form-data'\">\n <RequestTable\n :data=\"localFormBodyRows\"\n deferKeyUpdates\n :environment=\"environment\"\n showUploadButton\n @deleteRow=\"handleDeleteRow\"\n @removeFile=\"(index) => handleUpsertRow(index, { value: undefined })\"\n @uploadFile=\"handleFileUpload\"\n @upsertRow=\"handleUpsertRow\" />\n </template>\n\n <!-- Form URL Encoded -->\n <template v-else>\n <RequestTable\n :data=\"localFormBodyRows\"\n deferKeyUpdates\n :environment=\"environment\"\n @deleteRow=\"handleDeleteRow\"\n @upsertRow=\"handleUpsertRow\" />\n </template>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;EAyBA,MAAM,OAAO;;EAQb,MAAM,oBAAoB,IAAgB,CAAC,CAAC;;EAG5C,YACQ;GAAC,QAAA;GAAS,QAAA;GAAY,QAAA;EAAmB,IAC9C,CAAC,YAAY,QAAQ,iBAAiB;GACrC,kBAAkB,QAAQ,gBAAgB,YAAY,aAAa,MAAM;EAC3E,GACA,EAAE,WAAW,KAAK,CACpB;EAEA,MAAM,yBAAyB,SAAqB;GAClD,KACE,oBACA,KAAK,KAAK,SAAS;IACjB,MAAM,IAAI;IACV,OACE,QAAA,wBAAwB,wBACpB,iBAAiB,GAAG,IACnB,IAAI;IACX,YAAY,IAAI,cAAc;IAC9B,GAAI,QAAA,wBAAwB,yBAAyB,IAAI,UACrD,EAAE,SAAS,KAAK,IAChB,CAAC;GACP,EAAE,CACJ;EACF;;EAGA,MAAM,mBACJ,OACA,YAKG;GAEH,IAAI,SAAS,kBAAkB,MAAM,QAAQ;IAC3C,kBAAkB,QAAQ,CACxB,GAAG,kBAAkB,OACrB;KAAE,MAAM;KAAI,OAAO;KAAI,GAAG;KAAS,YAAY;IAAM,CACvD;IACA,sBAAsB,kBAAkB,KAAK;IAC7C;GACF;GAEA,kBAAkB,QAAQ,kBAAkB,MAAM,KAAK,KAAK,MAC1D,MAAM,QAAQ;IAAE,GAAG;IAAK,GAAG;GAAQ,IAAI,GACzC;GACA,sBAAsB,kBAAkB,KAAK;EAC/C;;EAGA,MAAM,mBAAmB,UAAkB;GACzC,kBAAkB,QAAQ,kBAAkB,MAAM,QAC/C,GAAG,MAAM,MAAM,KAClB;GACA,sBAAsB,kBAAkB,KAAK;EAC/C;;EAGA,MAAM,oBAAoB,UAAkB;GAC1C,MAAM,EAAE,SAAS,cAAc;IAC7B,WAAW,UAAU;KACnB,MAAM,OAAO,QAAQ;KAErB,IAAI,MAAM;MACR,MAAM,aAAa,kBAAkB,MAAM;MAC3C,gBAAgB,OAAO;OACrB,MAAM,YAAY,QAAQ,KAAK;OAC/B,OAAO;MACT,CAAC;KACH;IACF;IACA,UAAU;IACV,QAAQ;GACV,CAAC;GACD,KAAK;EACP;;UAKkB,QAAA,wBAAmB,yBAAA,UAAA,GACjC,YAQiC,sBAAA;;IAP9B,MAAM,kBAAA;IACP,iBAAA;IACC,aAAa,QAAA;IACd,kBAAA;IACC,aAAW;IACX,cAAU,OAAA,OAAA,OAAA,MAAG,UAAU,gBAAgB,OAAK,EAAA,OAAW,KAAA,EAAS,CAAA;IAChE,cAAY;IACZ,aAAW;yDAKd,YAKiC,sBAAA;;IAJ9B,MAAM,kBAAA;IACP,iBAAA;IACC,aAAa,QAAA;IACb,aAAW;IACX,aAAW"}
@@ -1,5 +1,5 @@
1
1
  import type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments';
2
- import type { SchemaObject } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document';
2
+ import type { SchemaObject } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document';
3
3
  type __VLS_Props = {
4
4
  /** The parsed (object) value of the structured body */
5
5
  parsedValue: unknown;
@@ -1 +1 @@
1
- {"version":3,"file":"RequestBodyStructured.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestBodyStructured.vue"],"names":[],"mappings":"AA8GA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AACnH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8DAA8D,CAAA;AAShG,KAAK,WAAW,GAAG;IACjB,uDAAuD;IACvD,WAAW,EAAE,OAAO,CAAA;IACpB,wFAAwF;IACxF,UAAU,CAAC,EAAE,YAAY,CAAA;IACzB,uFAAuF;IACvF,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,kBAAkB,CAAA;CAChC,CAAC;AAuIF,QAAA,MAAM,YAAY;;;;kFAGhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
1
+ {"version":3,"file":"RequestBodyStructured.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestBodyStructured.vue"],"names":[],"mappings":"AA+GA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AACnH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8DAA8D,CAAA;AAShG,KAAK,WAAW,GAAG;IACjB,uDAAuD;IACvD,WAAW,EAAE,OAAO,CAAA;IACpB,wFAAwF;IACxF,UAAU,CAAC,EAAE,YAAY,CAAA;IACzB,uFAAuF;IACvF,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,kBAAkB,CAAA;CAChC,CAAC;AAyIF,QAAA,MAAM,YAAY;;;;kFAGhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
@@ -1 +1 @@
1
- {"version":3,"file":"RequestBodyStructured.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestBodyStructured.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { SchemaObject } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport RequestTable from '@/v2/blocks/request-block/components/RequestTable.vue'\nimport type { TableRow } from '@/v2/blocks/request-block/components/RequestTableRow.vue'\nimport { foldStructuredBodyRows } from '@/v2/blocks/request-block/helpers/fold-structured-body-rows'\nimport { getStructuredBodyRows } from '@/v2/blocks/request-block/helpers/get-structured-body-rows'\nimport { getStructuredBodyCodec } from '@/v2/blocks/request-block/helpers/structured-body-codec'\n\nconst { parsedValue, bodySchema, contentType, environment } = defineProps<{\n /** The parsed (object) value of the structured body */\n parsedValue: unknown\n /** Resolved schema for the body so the table can show enums and validation per field */\n bodySchema?: SchemaObject\n /** The selected content type, decides how the folded body is serialized (JSON/YAML) */\n contentType: string\n environment: XScalarEnvironment\n}>()\n\nconst emit = defineEmits<{\n /** Serialized body text for the current content type */\n (e: 'update:value', payload: string): void\n}>()\n\nconst codec = computed(() => getStructuredBodyCodec(contentType))\n\n/** Local state for the body rows */\nconst localRows = ref<TableRow[]>([])\n\n/**\n * The serialized string we last emitted. Store updates triggered by our own emit come\n * back through the `parsedValue` prop — skip the row rebuild for those so typing does\n * not churn focus and a just-cleared row does not vanish mid-edit.\n */\nlet lastEmitted: string | undefined\n\nwatch(\n () => [parsedValue, bodySchema, contentType] as const,\n ([newValue, schema]) => {\n if (lastEmitted !== undefined && codec.value) {\n try {\n if (codec.value.stringify(newValue) === lastEmitted) {\n return\n }\n } catch {\n // Not serializable — treat as an external change and rebuild.\n }\n }\n lastEmitted = undefined\n localRows.value = getStructuredBodyRows(newValue, schema)\n },\n { immediate: true },\n)\n\nconst emitRows = () => {\n if (!codec.value) {\n return\n }\n const serialized = codec.value.stringify(\n foldStructuredBodyRows(localRows.value, bodySchema),\n )\n lastEmitted = serialized\n emit('update:value', serialized)\n}\n\n/** Update a row in the table, combines with the previous data so we emit the whole body */\nconst handleUpsertRow = (\n index: number,\n payload: Partial<{\n name: string\n value: string | File | undefined\n isDisabled: boolean\n }>,\n) => {\n // Add new row\n if (index >= localRows.value.length) {\n localRows.value = [\n ...localRows.value,\n { name: '', value: '', ...payload, isDisabled: false },\n ]\n emitRows()\n return\n }\n\n localRows.value = localRows.value.map((row, i) =>\n i === index ? { ...row, ...payload } : row,\n )\n emitRows()\n}\n\n/** Delete a row from the table */\nconst handleDeleteRow = (index: number) => {\n localRows.value = localRows.value.filter((_, i) => i !== index)\n emitRows()\n}\n</script>\n\n<template>\n <RequestTable\n :data=\"localRows\"\n :environment=\"environment\"\n label=\"Body\"\n @deleteRow=\"handleDeleteRow\"\n @upsertRow=\"handleUpsertRow\" />\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"RequestBodyStructured.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestBodyStructured.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { SchemaObject } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport RequestTable from '@/v2/blocks/request-block/components/RequestTable.vue'\nimport type { TableRow } from '@/v2/blocks/request-block/components/RequestTableRow.vue'\nimport { foldStructuredBodyRows } from '@/v2/blocks/request-block/helpers/fold-structured-body-rows'\nimport { getStructuredBodyRows } from '@/v2/blocks/request-block/helpers/get-structured-body-rows'\nimport { getStructuredBodyCodec } from '@/v2/blocks/request-block/helpers/structured-body-codec'\n\nconst { parsedValue, bodySchema, contentType, environment } = defineProps<{\n /** The parsed (object) value of the structured body */\n parsedValue: unknown\n /** Resolved schema for the body so the table can show enums and validation per field */\n bodySchema?: SchemaObject\n /** The selected content type, decides how the folded body is serialized (JSON/YAML) */\n contentType: string\n environment: XScalarEnvironment\n}>()\n\nconst emit = defineEmits<{\n /** Serialized body text for the current content type */\n (e: 'update:value', payload: string): void\n}>()\n\nconst codec = computed(() => getStructuredBodyCodec(contentType))\n\n/** Local state for the body rows */\nconst localRows = ref<TableRow[]>([])\n\n/**\n * The serialized string we last emitted. Store updates triggered by our own emit come\n * back through the `parsedValue` prop — skip the row rebuild for those so typing does\n * not churn focus and a just-cleared row does not vanish mid-edit.\n */\nlet lastEmitted: string | undefined\n\nwatch(\n () => [parsedValue, bodySchema, contentType] as const,\n ([newValue, schema]) => {\n if (lastEmitted !== undefined && codec.value) {\n try {\n if (codec.value.stringify(newValue) === lastEmitted) {\n return\n }\n } catch {\n // Not serializable — treat as an external change and rebuild.\n }\n }\n lastEmitted = undefined\n localRows.value = getStructuredBodyRows(newValue, schema)\n },\n { immediate: true },\n)\n\nconst emitRows = () => {\n if (!codec.value) {\n return\n }\n const serialized = codec.value.stringify(\n foldStructuredBodyRows(localRows.value, bodySchema),\n )\n lastEmitted = serialized\n emit('update:value', serialized)\n}\n\n/** Update a row in the table, combines with the previous data so we emit the whole body */\nconst handleUpsertRow = (\n index: number,\n payload: Partial<{\n name: string\n value: string | File | undefined\n isDisabled: boolean\n }>,\n) => {\n // Add new row\n if (index >= localRows.value.length) {\n localRows.value = [\n ...localRows.value,\n { name: '', value: '', ...payload, isDisabled: false },\n ]\n emitRows()\n return\n }\n\n localRows.value = localRows.value.map((row, i) =>\n i === index ? { ...row, ...payload } : row,\n )\n emitRows()\n}\n\n/** Delete a row from the table */\nconst handleDeleteRow = (index: number) => {\n localRows.value = localRows.value.filter((_, i) => i !== index)\n emitRows()\n}\n</script>\n\n<template>\n <RequestTable\n :data=\"localRows\"\n deferKeyUpdates\n :environment=\"environment\"\n label=\"Body\"\n @deleteRow=\"handleDeleteRow\"\n @upsertRow=\"handleUpsertRow\" />\n</template>\n"],"mappings":""}