@scalar/api-client 2.39.1 → 2.39.3

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 (34) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/hooks/useResponseBody.js +2 -2
  3. package/dist/hooks/useResponseBody.js.map +1 -1
  4. package/dist/libs/send-request/decode-buffer.js +2 -2
  5. package/dist/libs/send-request/decode-buffer.js.map +1 -1
  6. package/dist/style.css +20 -21
  7. package/dist/v2/blocks/operation-block/helpers/decode-buffer.js +2 -2
  8. package/dist/v2/blocks/operation-block/helpers/decode-buffer.js.map +1 -1
  9. package/dist/v2/blocks/request-block/components/RequestTableTooltip.vue.d.ts.map +1 -1
  10. package/dist/v2/blocks/request-block/components/RequestTableTooltip.vue.js +1 -3
  11. package/dist/v2/blocks/request-block/components/RequestTableTooltip.vue.js.map +1 -1
  12. package/dist/v2/blocks/request-block/components/RequestTableTooltip.vue.script.js +2 -3
  13. package/dist/v2/blocks/request-block/components/RequestTableTooltip.vue.script.js.map +1 -1
  14. package/dist/v2/blocks/request-block/helpers/get-form-body-rows.d.ts.map +1 -1
  15. package/dist/v2/blocks/request-block/helpers/get-form-body-rows.js +6 -1
  16. package/dist/v2/blocks/request-block/helpers/get-form-body-rows.js.map +1 -1
  17. package/dist/v2/blocks/response-block/helpers/process-response-body.js +2 -2
  18. package/dist/v2/blocks/response-block/helpers/process-response-body.js.map +1 -1
  19. package/dist/v2/constants.js +1 -1
  20. package/dist/v2/features/collection/components/Editor/Editor.vue.d.ts.map +1 -1
  21. package/dist/v2/features/collection/components/Editor/Editor.vue.js +1 -1
  22. package/dist/v2/features/collection/components/Editor/Editor.vue.js.map +1 -1
  23. package/dist/v2/features/collection/components/Editor/Editor.vue.script.js +2 -2
  24. package/dist/v2/features/collection/components/Editor/Editor.vue.script.js.map +1 -1
  25. package/dist/v2/features/editor/helpers/theme/apply-scalar-theme.js.map +1 -1
  26. package/dist/v2/features/editor/helpers/theme/load-css-variables.d.ts +25 -3
  27. package/dist/v2/features/editor/helpers/theme/load-css-variables.d.ts.map +1 -1
  28. package/dist/v2/features/editor/helpers/theme/load-css-variables.js +92 -16
  29. package/dist/v2/features/editor/helpers/theme/load-css-variables.js.map +1 -1
  30. package/dist/v2/posthog.d.ts.map +1 -1
  31. package/dist/v2/posthog.js +1 -0
  32. package/dist/v2/posthog.js.map +1 -1
  33. package/dist/views/Request/ResponseSection/ResponseEmpty.vue.script.js +1 -1
  34. package/package.json +11 -11
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @scalar/api-client
2
2
 
3
+ ## 2.39.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [#8610](https://github.com/scalar/scalar/pull/8610): fix(api-client): improve editor background color handling
8
+
9
+ ## 2.39.2
10
+
11
+ ### Patch Changes
12
+
13
+ - [#8599](https://github.com/scalar/scalar/pull/8599): fix(api-client): truncate long table tooltip content
14
+ - [#8590](https://github.com/scalar/scalar/pull/8590): Group analytic events by api-client product
15
+ - [#8601](https://github.com/scalar/scalar/pull/8601): fix: stringify nested form body example values for table rows
16
+
3
17
  ## 2.39.1
4
18
 
5
19
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  import { extractFilename } from "../libs/extractAttachmentFilename.js";
2
2
  import { computed, isRef } from "vue";
3
- import MimeType from "whatwg-mimetype";
3
+ import MimeTypeParser from "whatwg-mimetype";
4
4
  //#region src/hooks/useResponseBody.ts
5
5
  /**
6
6
  * Processes the response body of an HTTP request.
@@ -11,7 +11,7 @@ function useResponseBody(props) {
11
11
  const dataRef = computed(() => isRef(props.data) ? props.data.value : props.data);
12
12
  const headersRef = computed(() => isRef(props.headers) ? props.headers.value : props.headers);
13
13
  const mimeType = computed(() => {
14
- return new MimeType(headersRef.value.find((header) => header.name.toLowerCase() === "content-type")?.value ?? "");
14
+ return new MimeTypeParser(headersRef.value.find((header) => header.name.toLowerCase() === "content-type")?.value ?? "");
15
15
  });
16
16
  return {
17
17
  mimeType,
@@ -1 +1 @@
1
- {"version":3,"file":"useResponseBody.js","names":[],"sources":["../../src/hooks/useResponseBody.ts"],"sourcesContent":["import type { Ref } from 'vue'\nimport { computed, isRef } from 'vue'\nimport MimeType from 'whatwg-mimetype'\n\nimport { extractFilename } from '@/libs/extractAttachmentFilename'\n\n/**\n * Processes the response body of an HTTP request.\n * Extracts MIME type, attachment filename, and generates a data URL.\n */\nexport function useResponseBody(props: {\n data: Ref<unknown>\n headers: Ref<{ name: string; value: string; required: boolean }[]>\n}) {\n const isBlob = (b: any): b is Blob => b instanceof Blob\n\n // Handle both Ref and direct values\n const dataRef = computed(() => (isRef(props.data) ? props.data.value : props.data))\n const headersRef = computed(() => (isRef(props.headers) ? props.headers.value : props.headers))\n\n const mimeType = computed(() => {\n const contentType = headersRef.value.find((header) => header.name.toLowerCase() === 'content-type')?.value ?? ''\n return new MimeType(contentType)\n })\n\n const attachmentFilename = computed(() => {\n const value = headersRef.value.find((header) => header.name.toLowerCase() === 'content-disposition')?.value ?? ''\n return extractFilename(value)\n })\n\n const dataUrl = computed<string>(() => {\n if (isBlob(dataRef.value)) {\n return URL.createObjectURL(dataRef.value)\n }\n if (typeof dataRef.value === 'string') {\n return URL.createObjectURL(new Blob([dataRef.value], { type: mimeType.value.toString() }))\n }\n if (dataRef.value instanceof Object && Object.keys(dataRef.value).length) {\n return URL.createObjectURL(\n new Blob([JSON.stringify(dataRef.value)], {\n type: mimeType.value.toString(),\n }),\n )\n }\n return ''\n })\n\n return { mimeType, attachmentFilename, dataUrl }\n}\n"],"mappings":";;;;;;;;AAUA,SAAgB,gBAAgB,OAG7B;CACD,MAAM,UAAU,MAAsB,aAAa;CAGnD,MAAM,UAAU,eAAgB,MAAM,MAAM,KAAK,GAAG,MAAM,KAAK,QAAQ,MAAM,KAAM;CACnF,MAAM,aAAa,eAAgB,MAAM,MAAM,QAAQ,GAAG,MAAM,QAAQ,QAAQ,MAAM,QAAS;CAE/F,MAAM,WAAW,eAAe;AAE9B,SAAO,IAAI,SADS,WAAW,MAAM,MAAM,WAAW,OAAO,KAAK,aAAa,KAAK,eAAe,EAAE,SAAS,GAC9E;GAChC;AAwBF,QAAO;EAAE;EAAU,oBAtBQ,eAAe;AAExC,UAAO,gBADO,WAAW,MAAM,MAAM,WAAW,OAAO,KAAK,aAAa,KAAK,sBAAsB,EAAE,SAAS,GAClF;IAC7B;EAmBqC,SAjBvB,eAAuB;AACrC,OAAI,OAAO,QAAQ,MAAM,CACvB,QAAO,IAAI,gBAAgB,QAAQ,MAAM;AAE3C,OAAI,OAAO,QAAQ,UAAU,SAC3B,QAAO,IAAI,gBAAgB,IAAI,KAAK,CAAC,QAAQ,MAAM,EAAE,EAAE,MAAM,SAAS,MAAM,UAAU,EAAE,CAAC,CAAC;AAE5F,OAAI,QAAQ,iBAAiB,UAAU,OAAO,KAAK,QAAQ,MAAM,CAAC,OAChE,QAAO,IAAI,gBACT,IAAI,KAAK,CAAC,KAAK,UAAU,QAAQ,MAAM,CAAC,EAAE,EACxC,MAAM,SAAS,MAAM,UAAU,EAChC,CAAC,CACH;AAEH,UAAO;IACP;EAE8C"}
1
+ {"version":3,"file":"useResponseBody.js","names":[],"sources":["../../src/hooks/useResponseBody.ts"],"sourcesContent":["import type { Ref } from 'vue'\nimport { computed, isRef } from 'vue'\nimport MimeType from 'whatwg-mimetype'\n\nimport { extractFilename } from '@/libs/extractAttachmentFilename'\n\n/**\n * Processes the response body of an HTTP request.\n * Extracts MIME type, attachment filename, and generates a data URL.\n */\nexport function useResponseBody(props: {\n data: Ref<unknown>\n headers: Ref<{ name: string; value: string; required: boolean }[]>\n}) {\n const isBlob = (b: any): b is Blob => b instanceof Blob\n\n // Handle both Ref and direct values\n const dataRef = computed(() => (isRef(props.data) ? props.data.value : props.data))\n const headersRef = computed(() => (isRef(props.headers) ? props.headers.value : props.headers))\n\n const mimeType = computed(() => {\n const contentType = headersRef.value.find((header) => header.name.toLowerCase() === 'content-type')?.value ?? ''\n return new MimeType(contentType)\n })\n\n const attachmentFilename = computed(() => {\n const value = headersRef.value.find((header) => header.name.toLowerCase() === 'content-disposition')?.value ?? ''\n return extractFilename(value)\n })\n\n const dataUrl = computed<string>(() => {\n if (isBlob(dataRef.value)) {\n return URL.createObjectURL(dataRef.value)\n }\n if (typeof dataRef.value === 'string') {\n return URL.createObjectURL(new Blob([dataRef.value], { type: mimeType.value.toString() }))\n }\n if (dataRef.value instanceof Object && Object.keys(dataRef.value).length) {\n return URL.createObjectURL(\n new Blob([JSON.stringify(dataRef.value)], {\n type: mimeType.value.toString(),\n }),\n )\n }\n return ''\n })\n\n return { mimeType, attachmentFilename, dataUrl }\n}\n"],"mappings":";;;;;;;;AAUA,SAAgB,gBAAgB,OAG7B;CACD,MAAM,UAAU,MAAsB,aAAa;CAGnD,MAAM,UAAU,eAAgB,MAAM,MAAM,KAAK,GAAG,MAAM,KAAK,QAAQ,MAAM,KAAM;CACnF,MAAM,aAAa,eAAgB,MAAM,MAAM,QAAQ,GAAG,MAAM,QAAQ,QAAQ,MAAM,QAAS;CAE/F,MAAM,WAAW,eAAe;AAE9B,SAAO,IAAI,eADS,WAAW,MAAM,MAAM,WAAW,OAAO,KAAK,aAAa,KAAK,eAAe,EAAE,SAAS,GAC9E;GAChC;AAwBF,QAAO;EAAE;EAAU,oBAtBQ,eAAe;AAExC,UAAO,gBADO,WAAW,MAAM,MAAM,WAAW,OAAO,KAAK,aAAa,KAAK,sBAAsB,EAAE,SAAS,GAClF;IAC7B;EAmBqC,SAjBvB,eAAuB;AACrC,OAAI,OAAO,QAAQ,MAAM,CACvB,QAAO,IAAI,gBAAgB,QAAQ,MAAM;AAE3C,OAAI,OAAO,QAAQ,UAAU,SAC3B,QAAO,IAAI,gBAAgB,IAAI,KAAK,CAAC,QAAQ,MAAM,EAAE,EAAE,MAAM,SAAS,MAAM,UAAU,EAAE,CAAC,CAAC;AAE5F,OAAI,QAAQ,iBAAiB,UAAU,OAAO,KAAK,QAAQ,MAAM,CAAC,OAChE,QAAO,IAAI,gBACT,IAAI,KAAK,CAAC,KAAK,UAAU,QAAQ,MAAM,CAAC,EAAE,EACxC,MAAM,SAAS,MAAM,UAAU,EAChC,CAAC,CACH;AAEH,UAAO;IACP;EAE8C"}
@@ -1,9 +1,9 @@
1
1
  import { isTextMediaType } from "../../views/Request/consts/mediaTypes.js";
2
- import MimeType from "whatwg-mimetype";
2
+ import MimeTypeParser from "whatwg-mimetype";
3
3
  //#region src/libs/send-request/decode-buffer.ts
4
4
  /** Decode the buffer according to its content-type */
5
5
  function decodeBuffer(buffer, contentType) {
6
- const mimeType = new MimeType(contentType);
6
+ const mimeType = new MimeTypeParser(contentType);
7
7
  if (isTextMediaType(mimeType.essence)) return new TextDecoder(mimeType.parameters.get("charset")).decode(buffer);
8
8
  return new Blob([buffer], { type: mimeType.essence });
9
9
  }
@@ -1 +1 @@
1
- {"version":3,"file":"decode-buffer.js","names":[],"sources":["../../../src/libs/send-request/decode-buffer.ts"],"sourcesContent":["import MimeTypeParser from 'whatwg-mimetype'\n\nimport { isTextMediaType } from '@/views/Request/consts'\n\n// TODO: This should return `unknown` to acknowledge we don't know type, shouldn't it?\n/** Decode the buffer according to its content-type */\nexport function decodeBuffer(buffer: ArrayBuffer, contentType: string) {\n const mimeType = new MimeTypeParser(contentType)\n\n if (isTextMediaType(mimeType.essence)) {\n const decoder = new TextDecoder(mimeType.parameters.get('charset'))\n const string = decoder.decode(buffer)\n\n // Text\n return string\n }\n\n // Binary\n return new Blob([buffer], { type: mimeType.essence })\n}\n"],"mappings":";;;;AAMA,SAAgB,aAAa,QAAqB,aAAqB;CACrE,MAAM,WAAW,IAAI,SAAe,YAAY;AAEhD,KAAI,gBAAgB,SAAS,QAAQ,CAKnC,QAJgB,IAAI,YAAY,SAAS,WAAW,IAAI,UAAU,CAAC,CAC5C,OAAO,OAAO;AAOvC,QAAO,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,MAAM,SAAS,SAAS,CAAC"}
1
+ {"version":3,"file":"decode-buffer.js","names":[],"sources":["../../../src/libs/send-request/decode-buffer.ts"],"sourcesContent":["import MimeTypeParser from 'whatwg-mimetype'\n\nimport { isTextMediaType } from '@/views/Request/consts'\n\n// TODO: This should return `unknown` to acknowledge we don't know type, shouldn't it?\n/** Decode the buffer according to its content-type */\nexport function decodeBuffer(buffer: ArrayBuffer, contentType: string) {\n const mimeType = new MimeTypeParser(contentType)\n\n if (isTextMediaType(mimeType.essence)) {\n const decoder = new TextDecoder(mimeType.parameters.get('charset'))\n const string = decoder.decode(buffer)\n\n // Text\n return string\n }\n\n // Binary\n return new Blob([buffer], { type: mimeType.essence })\n}\n"],"mappings":";;;;AAMA,SAAgB,aAAa,QAAqB,aAAqB;CACrE,MAAM,WAAW,IAAI,eAAe,YAAY;AAEhD,KAAI,gBAAgB,SAAS,QAAQ,CAKnC,QAJgB,IAAI,YAAY,SAAS,WAAW,IAAI,UAAU,CAAC,CAC5C,OAAO,OAAO;AAOvC,QAAO,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,MAAM,SAAS,SAAS,CAAC"}
package/dist/style.css CHANGED
@@ -5366,12 +5366,12 @@ input[data-v-c1a50a6e]::placeholder {
5366
5366
  height: 256px;
5367
5367
  }
5368
5368
 
5369
- .scalar-app .h-\[68px\] {
5370
- height: 68px;
5369
+ .scalar-app .h-125 {
5370
+ height: 500px;
5371
5371
  }
5372
5372
 
5373
- .scalar-app .h-\[500px\] {
5374
- height: 500px;
5373
+ .scalar-app .h-\[68px\] {
5374
+ height: 68px;
5375
5375
  }
5376
5376
 
5377
5377
  .scalar-app .h-\[calc\(100\%-273\.5px\)\] {
@@ -5666,10 +5666,6 @@ input[data-v-c1a50a6e]::placeholder {
5666
5666
  max-width: 14px;
5667
5667
  }
5668
5668
 
5669
- .scalar-app .max-w-\[16rem\] {
5670
- max-width: 16rem;
5671
- }
5672
-
5673
5669
  .scalar-app .max-w-\[37px\] {
5674
5670
  max-width: 37px;
5675
5671
  }
@@ -7383,6 +7379,10 @@ input[data-v-c1a50a6e]::placeholder {
7383
7379
  height: 32px;
7384
7380
  }
7385
7381
 
7382
+ :is(.scalar-app .\*\:max-w-64 > *) {
7383
+ max-width: 256px;
7384
+ }
7385
+
7386
7386
  :is(.scalar-app .\*\:cursor-pointer > *) {
7387
7387
  cursor: pointer;
7388
7388
  }
@@ -7661,6 +7661,11 @@ input[data-v-c1a50a6e]::placeholder {
7661
7661
  background-color: var(--scalar-border-color);
7662
7662
  }
7663
7663
 
7664
+ :is(.scalar-app .\*\:not-first\:before\:content-\[\'_·_\'\] > *):not(:first-child):before {
7665
+ --tw-content: " · ";
7666
+ content: var(--tw-content);
7667
+ }
7668
+
7664
7669
  .scalar-app .after\:content-\[\'\:\'\]:after {
7665
7670
  --tw-content: ":";
7666
7671
  content: var(--tw-content);
@@ -8399,6 +8404,10 @@ input[data-v-c1a50a6e]::placeholder {
8399
8404
  -webkit-app-region: drag;
8400
8405
  }
8401
8406
 
8407
+ .scalar-app .\[\&_\.monaco-editor\]\:rounded-lg .monaco-editor, .scalar-app .\[\&_\.overflow-guard\]\:rounded-lg .overflow-guard {
8408
+ border-radius: var(--scalar-radius-lg);
8409
+ }
8410
+
8402
8411
  .scalar-app .\[\&\>label\]\:bg-transparent > label {
8403
8412
  background-color: #0000;
8404
8413
  }
@@ -8857,16 +8866,6 @@ input[data-v-c1a50a6e]::placeholder {
8857
8866
  display: none;
8858
8867
  }
8859
8868
 
8860
- .schema > span[data-v-f2ab7aa3]:not(:first-child)::before {
8861
- content: '·';
8862
- display: block;
8863
- margin: 0 0.5ch;
8864
- }
8865
- .schema > span[data-v-f2ab7aa3] {
8866
- display: flex;
8867
- white-space: nowrap;
8868
- }
8869
-
8870
8869
  [data-v-36811e28] .cm-editor {
8871
8870
  padding: 0;
8872
8871
  }
@@ -9773,15 +9772,15 @@ to {
9773
9772
  text-overflow: ellipsis;
9774
9773
  }
9775
9774
 
9776
- .editor-container[data-v-850fff8f] {
9775
+ .editor-container[data-v-e99ee660] {
9777
9776
  width: 100%;
9778
9777
  height: 100%;
9779
9778
  }
9780
- [data-v-850fff8f] .json-path-highlight {
9779
+ [data-v-e99ee660] .json-path-highlight {
9781
9780
  background-color: rgba(255, 200, 0, 0.35);
9782
9781
  border-radius: 4px;
9783
9782
  }
9784
- [data-v-850fff8f] .json-focus-highlight {
9783
+ [data-v-e99ee660] .json-focus-highlight {
9785
9784
  background-color: color-mix(
9786
9785
  in srgb,
9787
9786
  var(--scalar-color-accent, #24b47e) 18%,
@@ -1,5 +1,5 @@
1
1
  import { isTextMediaType } from "../../../../views/Request/consts/mediaTypes.js";
2
- import MimeType from "whatwg-mimetype";
2
+ import MimeTypeParser from "whatwg-mimetype";
3
3
  //#region src/v2/blocks/operation-block/helpers/decode-buffer.ts
4
4
  /**
5
5
  * Decode the buffer according to its content-type
@@ -7,7 +7,7 @@ import MimeType from "whatwg-mimetype";
7
7
  * @returns The decoded string or Blob
8
8
  */
9
9
  var decodeBuffer = (buffer, contentType) => {
10
- const mimeType = new MimeType(contentType);
10
+ const mimeType = new MimeTypeParser(contentType);
11
11
  if (isTextMediaType(mimeType.essence)) return new TextDecoder(mimeType.parameters.get("charset")).decode(buffer);
12
12
  return new Blob([buffer], { type: mimeType.essence });
13
13
  };
@@ -1 +1 @@
1
- {"version":3,"file":"decode-buffer.js","names":[],"sources":["../../../../../src/v2/blocks/operation-block/helpers/decode-buffer.ts"],"sourcesContent":["import MimeTypeParser from 'whatwg-mimetype'\n\nimport { isTextMediaType } from '@/views/Request/consts'\n\n/**\n * Decode the buffer according to its content-type\n *\n * @returns The decoded string or Blob\n */\nexport const decodeBuffer = (buffer: ArrayBuffer, contentType: string): string | Blob => {\n const mimeType = new MimeTypeParser(contentType)\n\n // Text\n if (isTextMediaType(mimeType.essence)) {\n const decoder = new TextDecoder(mimeType.parameters.get('charset'))\n return decoder.decode(buffer)\n }\n\n // Binary\n return new Blob([buffer], { type: mimeType.essence })\n}\n"],"mappings":";;;;;;;;AASA,IAAa,gBAAgB,QAAqB,gBAAuC;CACvF,MAAM,WAAW,IAAI,SAAe,YAAY;AAGhD,KAAI,gBAAgB,SAAS,QAAQ,CAEnC,QADgB,IAAI,YAAY,SAAS,WAAW,IAAI,UAAU,CAAC,CACpD,OAAO,OAAO;AAI/B,QAAO,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,MAAM,SAAS,SAAS,CAAC"}
1
+ {"version":3,"file":"decode-buffer.js","names":[],"sources":["../../../../../src/v2/blocks/operation-block/helpers/decode-buffer.ts"],"sourcesContent":["import MimeTypeParser from 'whatwg-mimetype'\n\nimport { isTextMediaType } from '@/views/Request/consts'\n\n/**\n * Decode the buffer according to its content-type\n *\n * @returns The decoded string or Blob\n */\nexport const decodeBuffer = (buffer: ArrayBuffer, contentType: string): string | Blob => {\n const mimeType = new MimeTypeParser(contentType)\n\n // Text\n if (isTextMediaType(mimeType.essence)) {\n const decoder = new TextDecoder(mimeType.parameters.get('charset'))\n return decoder.decode(buffer)\n }\n\n // Binary\n return new Blob([buffer], { type: mimeType.essence })\n}\n"],"mappings":";;;;;;;;AASA,IAAa,gBAAgB,QAAqB,gBAAuC;CACvF,MAAM,WAAW,IAAI,eAAe,YAAY;AAGhD,KAAI,gBAAgB,SAAS,QAAQ,CAEnC,QADgB,IAAI,YAAY,SAAS,WAAW,IAAI,UAAU,CAAC,CACpD,OAAO,OAAO;AAI/B,QAAO,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,MAAM,SAAS,SAAS,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"RequestTableTooltip.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestTableTooltip.vue"],"names":[],"mappings":"AAmFA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8DAA8D,CAAA;AAKhG,KAAK,WAAW,GAAG;IACjB,MAAM,CAAC,EAAE,YAAY,CAAA;IACrB,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAA;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAC;AAmLF,QAAA,MAAM,YAAY,kSAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
1
+ {"version":3,"file":"RequestTableTooltip.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestTableTooltip.vue"],"names":[],"mappings":"AAsEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8DAA8D,CAAA;AAKhG,KAAK,WAAW,GAAG;IACjB,MAAM,CAAC,EAAE,YAAY,CAAA;IACrB,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAA;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAC;AA8KF,QAAA,MAAM,YAAY,kSAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
@@ -1,8 +1,6 @@
1
- import _plugin_vue_export_helper_default from "../../../../_virtual/_plugin-vue_export-helper.js";
2
1
  import RequestTableTooltip_vue_vue_type_script_setup_true_lang_default from "./RequestTableTooltip.vue.script.js";
3
- /* empty css */
4
2
  //#region src/v2/blocks/request-block/components/RequestTableTooltip.vue
5
- var RequestTableTooltip_default = /* @__PURE__ */ _plugin_vue_export_helper_default(RequestTableTooltip_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-f2ab7aa3"]]);
3
+ var RequestTableTooltip_default = RequestTableTooltip_vue_vue_type_script_setup_true_lang_default;
6
4
  //#endregion
7
5
  export { RequestTableTooltip_default as default };
8
6
 
@@ -1 +1 @@
1
- {"version":3,"file":"RequestTableTooltip.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTableTooltip.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarMarkdown, ScalarPopover } from '@scalar/components'\nimport { ScalarIconInfo, ScalarIconWarning } from '@scalar/icons'\nimport type { SchemaObject } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed } from 'vue'\n\nimport { validateParameter } from '@/v2/blocks/request-block/helpers/validate-parameter'\n\nconst { schema, value, description } = defineProps<{\n schema?: SchemaObject\n value: string | File | null\n description?: string\n}>()\n\nconst invalidParameterMessage = computed(() => validateParameter(schema, value))\nconst isInvalid = computed(() => invalidParameterMessage.value.ok === false)\n</script>\n<template>\n <ScalarPopover\n :offset=\"4\"\n placement=\"left\"\n teleport>\n <button\n :aria-label=\"isInvalid ? 'Input is invalid' : 'More Information'\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 rounded p-1\"\n :role=\"isInvalid ? 'alert' : 'none'\"\n type=\"button\">\n <ScalarIconWarning\n v-if=\"isInvalid\"\n class=\"text-orange size-3.5 brightness-90 hover:brightness-75\" />\n <ScalarIconInfo\n v-else\n class=\"text-c-2 hover:text-c-1 size-3.5\" />\n </button>\n <template #popover>\n <div\n class=\"w-content text-xxs text-c-1 grid min-w-48 gap-1.5 rounded px-1.5 pt-2 pb-1.5 leading-none\">\n <div\n v-if=\"invalidParameterMessage.ok === false\"\n class=\"text-error-1\">\n {{ invalidParameterMessage.message }}\n </div>\n <div\n v-else-if=\"\n schema &&\n ('type' in schema ||\n 'format' in schema ||\n 'minimum' in schema ||\n 'maximum' in schema ||\n 'default' in schema)\n \"\n class=\"schema text-c-2 flex items-center\">\n <span v-if=\"'type' in schema\">{{ schema.type }}</span>\n <span v-if=\"'format' in schema\">{{ schema.format }}</span>\n <span v-if=\"'minimum' in schema\">min: {{ schema.minimum }}</span>\n <span v-if=\"'maximum' in schema\">max: {{ schema.maximum }}</span>\n <span v-if=\"'default' in schema\">default: {{ schema.default }}</span>\n </div>\n <ScalarMarkdown\n v-if=\"description && !isInvalid\"\n class=\"max-w-[16rem]\"\n :value=\"description\" />\n </div>\n </template>\n </ScalarPopover>\n</template>\n<style scoped>\n.schema > span:not(:first-child)::before {\n content: '·';\n display: block;\n margin: 0 0.5ch;\n}\n\n.schema > span {\n display: flex;\n white-space: nowrap;\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"RequestTableTooltip.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTableTooltip.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarMarkdown, ScalarPopover } from '@scalar/components'\nimport { ScalarIconInfo, ScalarIconWarning } from '@scalar/icons'\nimport type { SchemaObject } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed } from 'vue'\n\nimport { validateParameter } from '@/v2/blocks/request-block/helpers/validate-parameter'\n\nconst { schema, value, description } = defineProps<{\n schema?: SchemaObject\n value: string | File | null\n description?: string\n}>()\n\nconst invalidParameterMessage = computed(() => validateParameter(schema, value))\nconst isInvalid = computed(() => invalidParameterMessage.value.ok === false)\n</script>\n<template>\n <ScalarPopover\n :offset=\"4\"\n placement=\"left\"\n teleport>\n <button\n :aria-label=\"isInvalid ? 'Input is invalid' : 'More Information'\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 rounded p-1\"\n :role=\"isInvalid ? 'alert' : 'none'\"\n type=\"button\">\n <ScalarIconWarning\n v-if=\"isInvalid\"\n class=\"text-orange size-3.5 brightness-90 hover:brightness-75\" />\n <ScalarIconInfo\n v-else\n class=\"text-c-2 hover:text-c-1 size-3.5\" />\n </button>\n <template #popover>\n <div\n class=\"w-content text-xxs text-c-1 grid min-w-48 gap-1.5 rounded px-1.5 pt-2 pb-1.5 leading-none *:max-w-64\">\n <div\n v-if=\"invalidParameterMessage.ok === false\"\n class=\"text-error-1\">\n {{ invalidParameterMessage.message }}\n </div>\n <div\n v-else-if=\"\n schema &&\n ('type' in schema ||\n 'format' in schema ||\n 'minimum' in schema ||\n 'maximum' in schema ||\n 'default' in schema)\n \"\n class=\"schema text-c-2 truncate *:not-first:before:content-['_·_']\">\n <span v-if=\"'type' in schema\">{{ schema.type }}</span>\n <span v-if=\"'format' in schema\">{{ schema.format }}</span>\n <span v-if=\"'minimum' in schema\">min: {{ schema.minimum }}</span>\n <span v-if=\"'maximum' in schema\">max: {{ schema.maximum }}</span>\n <span v-if=\"'default' in schema\">default: {{ schema.default }}</span>\n </div>\n <ScalarMarkdown\n v-if=\"description && !isInvalid\"\n :value=\"description\" />\n </div>\n </template>\n </ScalarPopover>\n</template>\n"],"mappings":""}
@@ -4,14 +4,14 @@ import { ScalarMarkdown, ScalarPopover } from "@scalar/components";
4
4
  import { ScalarIconInfo, ScalarIconWarning } from "@scalar/icons";
5
5
  //#region src/v2/blocks/request-block/components/RequestTableTooltip.vue?vue&type=script&setup=true&lang.ts
6
6
  var _hoisted_1 = ["aria-label", "role"];
7
- var _hoisted_2 = { class: "w-content text-xxs text-c-1 grid min-w-48 gap-1.5 rounded px-1.5 pt-2 pb-1.5 leading-none" };
7
+ var _hoisted_2 = { class: "w-content text-xxs text-c-1 grid min-w-48 gap-1.5 rounded px-1.5 pt-2 pb-1.5 leading-none *:max-w-64" };
8
8
  var _hoisted_3 = {
9
9
  key: 0,
10
10
  class: "text-error-1"
11
11
  };
12
12
  var _hoisted_4 = {
13
13
  key: 1,
14
- class: "schema text-c-2 flex items-center"
14
+ class: "schema text-c-2 truncate *:not-first:before:content-['_·_']"
15
15
  };
16
16
  var _hoisted_5 = { key: 0 };
17
17
  var _hoisted_6 = { key: 1 };
@@ -42,7 +42,6 @@ var RequestTableTooltip_vue_vue_type_script_setup_true_lang_default = /* @__PURE
42
42
  "default" in __props.schema ? (openBlock(), createElementBlock("span", _hoisted_9, "default: " + toDisplayString(__props.schema.default), 1)) : createCommentVNode("", true)
43
43
  ])) : createCommentVNode("", true), __props.description && !isInvalid.value ? (openBlock(), createBlock(unref(ScalarMarkdown), {
44
44
  key: 2,
45
- class: "max-w-[16rem]",
46
45
  value: __props.description
47
46
  }, null, 8, ["value"])) : createCommentVNode("", true)])]),
48
47
  default: withCtx(() => [createElementVNode("button", {
@@ -1 +1 @@
1
- {"version":3,"file":"RequestTableTooltip.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTableTooltip.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarMarkdown, ScalarPopover } from '@scalar/components'\nimport { ScalarIconInfo, ScalarIconWarning } from '@scalar/icons'\nimport type { SchemaObject } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed } from 'vue'\n\nimport { validateParameter } from '@/v2/blocks/request-block/helpers/validate-parameter'\n\nconst { schema, value, description } = defineProps<{\n schema?: SchemaObject\n value: string | File | null\n description?: string\n}>()\n\nconst invalidParameterMessage = computed(() => validateParameter(schema, value))\nconst isInvalid = computed(() => invalidParameterMessage.value.ok === false)\n</script>\n<template>\n <ScalarPopover\n :offset=\"4\"\n placement=\"left\"\n teleport>\n <button\n :aria-label=\"isInvalid ? 'Input is invalid' : 'More Information'\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 rounded p-1\"\n :role=\"isInvalid ? 'alert' : 'none'\"\n type=\"button\">\n <ScalarIconWarning\n v-if=\"isInvalid\"\n class=\"text-orange size-3.5 brightness-90 hover:brightness-75\" />\n <ScalarIconInfo\n v-else\n class=\"text-c-2 hover:text-c-1 size-3.5\" />\n </button>\n <template #popover>\n <div\n class=\"w-content text-xxs text-c-1 grid min-w-48 gap-1.5 rounded px-1.5 pt-2 pb-1.5 leading-none\">\n <div\n v-if=\"invalidParameterMessage.ok === false\"\n class=\"text-error-1\">\n {{ invalidParameterMessage.message }}\n </div>\n <div\n v-else-if=\"\n schema &&\n ('type' in schema ||\n 'format' in schema ||\n 'minimum' in schema ||\n 'maximum' in schema ||\n 'default' in schema)\n \"\n class=\"schema text-c-2 flex items-center\">\n <span v-if=\"'type' in schema\">{{ schema.type }}</span>\n <span v-if=\"'format' in schema\">{{ schema.format }}</span>\n <span v-if=\"'minimum' in schema\">min: {{ schema.minimum }}</span>\n <span v-if=\"'maximum' in schema\">max: {{ schema.maximum }}</span>\n <span v-if=\"'default' in schema\">default: {{ schema.default }}</span>\n </div>\n <ScalarMarkdown\n v-if=\"description && !isInvalid\"\n class=\"max-w-[16rem]\"\n :value=\"description\" />\n </div>\n </template>\n </ScalarPopover>\n</template>\n<style scoped>\n.schema > span:not(:first-child)::before {\n content: '·';\n display: block;\n margin: 0 0.5ch;\n}\n\n.schema > span {\n display: flex;\n white-space: nowrap;\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;EAcA,MAAM,0BAA0B,eAAe,kBAAkB,QAAA,QAAQ,QAAA,MAAM,CAAA;EAC/E,MAAM,YAAY,eAAe,wBAAwB,MAAM,OAAO,MAAK;;uBAGzE,YA8CgB,MAAA,cAAA,EAAA;IA7Cb,QAAQ;IACT,WAAU;IACV,UAAA;;IAaW,SAAO,cA4BV,CA3BN,mBA2BM,OA3BN,YA2BM,CAxBI,wBAAA,MAAwB,OAAE,SAAA,WAAA,EADlC,mBAIM,OAJN,YAIM,gBADD,wBAAA,MAAwB,QAAO,EAAA,EAAA,IAGV,QAAA,WAAA,UAAiC,QAAA,UAAA,YAAoC,QAAA,UAAA,aAAqC,QAAA,UAAA,aAAqC,QAAA,UAAA,aAAqC,QAAA,WAAA,WAAA,EAD9M,mBAeM,OAfN,YAeM;eALkB,QAAA,UAAA,WAAA,EAAtB,mBAAsD,QAAA,YAAA,gBAArB,QAAA,OAAO,KAAI,EAAA,EAAA,IAAA,mBAAA,IAAA,KAAA;iBACpB,QAAA,UAAA,WAAA,EAAxB,mBAA0D,QAAA,YAAA,gBAAvB,QAAA,OAAO,OAAM,EAAA,EAAA,IAAA,mBAAA,IAAA,KAAA;kBACvB,QAAA,UAAA,WAAA,EAAzB,mBAAiE,QAAA,YAAhC,UAAK,gBAAG,QAAA,OAAO,QAAO,EAAA,EAAA,IAAA,mBAAA,IAAA,KAAA;kBAC9B,QAAA,UAAA,WAAA,EAAzB,mBAAiE,QAAA,YAAhC,UAAK,gBAAG,QAAA,OAAO,QAAO,EAAA,EAAA,IAAA,mBAAA,IAAA,KAAA;kBAC9B,QAAA,UAAA,WAAA,EAAzB,mBAAqE,QAAA,YAApC,cAAS,gBAAG,QAAA,OAAO,QAAO,EAAA,EAAA,IAAA,mBAAA,IAAA,KAAA;wCAGrD,QAAA,eAAW,CAAK,UAAA,SAAA,WAAA,EADxB,YAGyB,MAAA,eAAA,EAAA;;KADvB,OAAM;KACL,OAAO,QAAA;;2BA5BL,CAXT,mBAWS,UAAA;KAVN,cAAY,UAAA,QAAS,qBAAA;KACtB,OAAM;KACL,MAAM,UAAA,QAAS,UAAA;KAChB,MAAK;QAEG,UAAA,SAAA,WAAA,EADR,YAEmE,MAAA,kBAAA,EAAA;;KAAjE,OAAM;wBACR,YAE6C,MAAA,eAAA,EAAA;;KAA3C,OAAM"}
1
+ {"version":3,"file":"RequestTableTooltip.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTableTooltip.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarMarkdown, ScalarPopover } from '@scalar/components'\nimport { ScalarIconInfo, ScalarIconWarning } from '@scalar/icons'\nimport type { SchemaObject } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed } from 'vue'\n\nimport { validateParameter } from '@/v2/blocks/request-block/helpers/validate-parameter'\n\nconst { schema, value, description } = defineProps<{\n schema?: SchemaObject\n value: string | File | null\n description?: string\n}>()\n\nconst invalidParameterMessage = computed(() => validateParameter(schema, value))\nconst isInvalid = computed(() => invalidParameterMessage.value.ok === false)\n</script>\n<template>\n <ScalarPopover\n :offset=\"4\"\n placement=\"left\"\n teleport>\n <button\n :aria-label=\"isInvalid ? 'Input is invalid' : 'More Information'\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 rounded p-1\"\n :role=\"isInvalid ? 'alert' : 'none'\"\n type=\"button\">\n <ScalarIconWarning\n v-if=\"isInvalid\"\n class=\"text-orange size-3.5 brightness-90 hover:brightness-75\" />\n <ScalarIconInfo\n v-else\n class=\"text-c-2 hover:text-c-1 size-3.5\" />\n </button>\n <template #popover>\n <div\n class=\"w-content text-xxs text-c-1 grid min-w-48 gap-1.5 rounded px-1.5 pt-2 pb-1.5 leading-none *:max-w-64\">\n <div\n v-if=\"invalidParameterMessage.ok === false\"\n class=\"text-error-1\">\n {{ invalidParameterMessage.message }}\n </div>\n <div\n v-else-if=\"\n schema &&\n ('type' in schema ||\n 'format' in schema ||\n 'minimum' in schema ||\n 'maximum' in schema ||\n 'default' in schema)\n \"\n class=\"schema text-c-2 truncate *:not-first:before:content-['_·_']\">\n <span v-if=\"'type' in schema\">{{ schema.type }}</span>\n <span v-if=\"'format' in schema\">{{ schema.format }}</span>\n <span v-if=\"'minimum' in schema\">min: {{ schema.minimum }}</span>\n <span v-if=\"'maximum' in schema\">max: {{ schema.maximum }}</span>\n <span v-if=\"'default' in schema\">default: {{ schema.default }}</span>\n </div>\n <ScalarMarkdown\n v-if=\"description && !isInvalid\"\n :value=\"description\" />\n </div>\n </template>\n </ScalarPopover>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;EAcA,MAAM,0BAA0B,eAAe,kBAAkB,QAAA,QAAQ,QAAA,MAAM,CAAA;EAC/E,MAAM,YAAY,eAAe,wBAAwB,MAAM,OAAO,MAAK;;uBAGzE,YA6CgB,MAAA,cAAA,EAAA;IA5Cb,QAAQ;IACT,WAAU;IACV,UAAA;;IAaW,SAAO,cA2BV,CA1BN,mBA0BM,OA1BN,YA0BM,CAvBI,wBAAA,MAAwB,OAAE,SAAA,WAAA,EADlC,mBAIM,OAJN,YAIM,gBADD,wBAAA,MAAwB,QAAO,EAAA,EAAA,IAGV,QAAA,WAAA,UAAiC,QAAA,UAAA,YAAoC,QAAA,UAAA,aAAqC,QAAA,UAAA,aAAqC,QAAA,UAAA,aAAqC,QAAA,WAAA,WAAA,EAD9M,mBAeM,OAfN,YAeM;eALkB,QAAA,UAAA,WAAA,EAAtB,mBAAsD,QAAA,YAAA,gBAArB,QAAA,OAAO,KAAI,EAAA,EAAA,IAAA,mBAAA,IAAA,KAAA;iBACpB,QAAA,UAAA,WAAA,EAAxB,mBAA0D,QAAA,YAAA,gBAAvB,QAAA,OAAO,OAAM,EAAA,EAAA,IAAA,mBAAA,IAAA,KAAA;kBACvB,QAAA,UAAA,WAAA,EAAzB,mBAAiE,QAAA,YAAhC,UAAK,gBAAG,QAAA,OAAO,QAAO,EAAA,EAAA,IAAA,mBAAA,IAAA,KAAA;kBAC9B,QAAA,UAAA,WAAA,EAAzB,mBAAiE,QAAA,YAAhC,UAAK,gBAAG,QAAA,OAAO,QAAO,EAAA,EAAA,IAAA,mBAAA,IAAA,KAAA;kBAC9B,QAAA,UAAA,WAAA,EAAzB,mBAAqE,QAAA,YAApC,cAAS,gBAAG,QAAA,OAAO,QAAO,EAAA,EAAA,IAAA,mBAAA,IAAA,KAAA;wCAGrD,QAAA,eAAW,CAAK,UAAA,SAAA,WAAA,EADxB,YAEyB,MAAA,eAAA,EAAA;;KAAtB,OAAO,QAAA;;2BA3BL,CAXT,mBAWS,UAAA;KAVN,cAAY,UAAA,QAAS,qBAAA;KACtB,OAAM;KACL,MAAM,UAAA,QAAS,UAAA;KAChB,MAAK;QAEG,UAAA,SAAA,WAAA,EADR,YAEmE,MAAA,kBAAA,EAAA;;KAAjE,OAAM;wBACR,YAE6C,MAAA,eAAA,EAAA;;KAA3C,OAAM"}
@@ -1 +1 @@
1
- {"version":3,"file":"get-form-body-rows.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/helpers/get-form-body-rows.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,8DAA8D,CAAA;AAG/G,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0DAA0D,CAAA;AAExF,uGAAuG;AACvG,eAAO,MAAM,eAAe,GAC1B,SAAS,aAAa,GAAG,SAAS,GAAG,IAAI,EACzC,aAAa,MAAM,EACnB,iBAAiB,YAAY,KAC5B,QAAQ,EAqDV,CAAA"}
1
+ {"version":3,"file":"get-form-body-rows.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/helpers/get-form-body-rows.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,8DAA8D,CAAA;AAG/G,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0DAA0D,CAAA;AAYxF,uGAAuG;AACvG,eAAO,MAAM,eAAe,GAC1B,SAAS,aAAa,GAAG,SAAS,GAAG,IAAI,EACzC,aAAa,MAAM,EACnB,iBAAiB,YAAY,KAC5B,QAAQ,EAuDV,CAAA"}
@@ -3,6 +3,11 @@ import { resolve } from "@scalar/workspace-store/resolve";
3
3
  import { objectEntries } from "@scalar/helpers/object/object-entries";
4
4
  import { isObjectSchema } from "@scalar/workspace-store/schemas/v3.1/strict/type-guards";
5
5
  //#region src/v2/blocks/request-block/helpers/get-form-body-rows.ts
6
+ var stringifyValue = (value) => {
7
+ if (value instanceof File) return value.name;
8
+ if (typeof value === "object" && value !== null) return JSON.stringify(value);
9
+ return String(value);
10
+ };
6
11
  /** Build the table rows for the form data, optionally enriched with schema (e.g. enum) per property */
7
12
  var getFormBodyRows = (example, contentType, formBodySchema) => {
8
13
  if (!example?.value || contentType !== "multipart/form-data" && contentType !== "application/x-www-form-urlencoded") return [];
@@ -36,7 +41,7 @@ var getFormBodyRows = (example, contentType, formBodySchema) => {
36
41
  });
37
42
  if (typeof example.value === "object" && example.value) return objectEntries(example.value).map(([key, value]) => mapRow({
38
43
  name: String(key),
39
- value
44
+ value: stringifyValue(value)
40
45
  }));
41
46
  return [];
42
47
  };
@@ -1 +1 @@
1
- {"version":3,"file":"get-form-body-rows.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/helpers/get-form-body-rows.ts"],"sourcesContent":["import { isObject } from '@scalar/helpers/object/is-object'\nimport { objectEntries } from '@scalar/helpers/object/object-entries'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { ExampleObject, SchemaObject } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { isObjectSchema } from '@scalar/workspace-store/schemas/v3.1/strict/type-guards'\n\nimport type { TableRow } from '@/v2/blocks/request-block/components/RequestTableRow.vue'\n\n/** Build the table rows for the form data, optionally enriched with schema (e.g. enum) per property */\nexport const getFormBodyRows = (\n example: ExampleObject | undefined | null,\n contentType: string,\n formBodySchema?: SchemaObject,\n): TableRow[] => {\n // We only need the rows for formData\n if (\n !example?.value ||\n (contentType !== 'multipart/form-data' && contentType !== 'application/x-www-form-urlencoded')\n ) {\n return []\n }\n\n // Get all the schema properties if the schema is an object schema\n const schemaWithProperties = formBodySchema && isObjectSchema(formBodySchema) ? formBodySchema : undefined\n const requiredSet = schemaWithProperties ? new Set(schemaWithProperties.required ?? []) : undefined\n\n const mapRow = ({\n name,\n value,\n isDisabled = false,\n }: {\n name: string\n value: string | File\n isDisabled?: boolean\n }): TableRow => {\n const row: TableRow = { name, value, isDisabled }\n if (!schemaWithProperties || !name) {\n return row\n }\n const propSchema = resolve.schema(schemaWithProperties.properties?.[name])\n row.schema = propSchema\n row.description = propSchema?.description\n row.isRequired = requiredSet?.has(name)\n row.isDisabled = isDisabled\n return row\n }\n\n // We have form data stored as an array\n if (Array.isArray(example.value)) {\n return example.value.map((exampleValue) => {\n if (isObject(exampleValue)) {\n const name = String(exampleValue.name)\n const value = exampleValue.value instanceof File ? exampleValue.value : String(exampleValue.value)\n const isDisabled = Boolean(exampleValue.isDisabled)\n return mapRow({ name, value, isDisabled })\n }\n return { name: '', value: exampleValue, isDisabled: false }\n })\n }\n\n // We got an object try to convert it to an array of rows\n if (typeof example.value === 'object' && example.value) {\n return objectEntries(example.value).map(([key, value]) => mapRow({ name: String(key), value }))\n }\n\n return []\n}\n"],"mappings":";;;;;;AASA,IAAa,mBACX,SACA,aACA,mBACe;AAEf,KACE,CAAC,SAAS,SACT,gBAAgB,yBAAyB,gBAAgB,oCAE1D,QAAO,EAAE;CAIX,MAAM,uBAAuB,kBAAkB,eAAe,eAAe,GAAG,iBAAiB,KAAA;CACjG,MAAM,cAAc,uBAAuB,IAAI,IAAI,qBAAqB,YAAY,EAAE,CAAC,GAAG,KAAA;CAE1F,MAAM,UAAU,EACd,MACA,OACA,aAAa,YAKC;EACd,MAAM,MAAgB;GAAE;GAAM;GAAO;GAAY;AACjD,MAAI,CAAC,wBAAwB,CAAC,KAC5B,QAAO;EAET,MAAM,aAAa,QAAQ,OAAO,qBAAqB,aAAa,MAAM;AAC1E,MAAI,SAAS;AACb,MAAI,cAAc,YAAY;AAC9B,MAAI,aAAa,aAAa,IAAI,KAAK;AACvC,MAAI,aAAa;AACjB,SAAO;;AAIT,KAAI,MAAM,QAAQ,QAAQ,MAAM,CAC9B,QAAO,QAAQ,MAAM,KAAK,iBAAiB;AACzC,MAAI,SAAS,aAAa,CAIxB,QAAO,OAAO;GAAE,MAHH,OAAO,aAAa,KAAK;GAGhB,OAFR,aAAa,iBAAiB,OAAO,aAAa,QAAQ,OAAO,aAAa,MAAM;GAErE,YADV,QAAQ,aAAa,WAAW;GACV,CAAC;AAE5C,SAAO;GAAE,MAAM;GAAI,OAAO;GAAc,YAAY;GAAO;GAC3D;AAIJ,KAAI,OAAO,QAAQ,UAAU,YAAY,QAAQ,MAC/C,QAAO,cAAc,QAAQ,MAAM,CAAC,KAAK,CAAC,KAAK,WAAW,OAAO;EAAE,MAAM,OAAO,IAAI;EAAE;EAAO,CAAC,CAAC;AAGjG,QAAO,EAAE"}
1
+ {"version":3,"file":"get-form-body-rows.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/helpers/get-form-body-rows.ts"],"sourcesContent":["import { isObject } from '@scalar/helpers/object/is-object'\nimport { objectEntries } from '@scalar/helpers/object/object-entries'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { ExampleObject, SchemaObject } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { isObjectSchema } from '@scalar/workspace-store/schemas/v3.1/strict/type-guards'\n\nimport type { TableRow } from '@/v2/blocks/request-block/components/RequestTableRow.vue'\n\nconst stringifyValue = (value: unknown) => {\n if (value instanceof File) {\n return value.name\n }\n if (typeof value === 'object' && value !== null) {\n return JSON.stringify(value)\n }\n return String(value)\n}\n\n/** Build the table rows for the form data, optionally enriched with schema (e.g. enum) per property */\nexport const getFormBodyRows = (\n example: ExampleObject | undefined | null,\n contentType: string,\n formBodySchema?: SchemaObject,\n): TableRow[] => {\n // We only need the rows for formData\n if (\n !example?.value ||\n (contentType !== 'multipart/form-data' && contentType !== 'application/x-www-form-urlencoded')\n ) {\n return []\n }\n\n // Get all the schema properties if the schema is an object schema\n const schemaWithProperties = formBodySchema && isObjectSchema(formBodySchema) ? formBodySchema : undefined\n const requiredSet = schemaWithProperties ? new Set(schemaWithProperties.required ?? []) : undefined\n\n const mapRow = ({\n name,\n value,\n isDisabled = false,\n }: {\n name: string\n value: string | File\n isDisabled?: boolean\n }): TableRow => {\n const row: TableRow = { name, value, isDisabled }\n if (!schemaWithProperties || !name) {\n return row\n }\n const propSchema = resolve.schema(schemaWithProperties.properties?.[name])\n row.schema = propSchema\n row.description = propSchema?.description\n row.isRequired = requiredSet?.has(name)\n row.isDisabled = isDisabled\n return row\n }\n\n // We have form data stored as an array\n if (Array.isArray(example.value)) {\n return example.value.map((exampleValue) => {\n if (isObject(exampleValue)) {\n const name = String(exampleValue.name)\n const value = exampleValue.value instanceof File ? exampleValue.value : String(exampleValue.value)\n const isDisabled = Boolean(exampleValue.isDisabled)\n return mapRow({ name, value, isDisabled })\n }\n return { name: '', value: exampleValue, isDisabled: false }\n })\n }\n\n // We got an object try to convert it to an array of rows\n if (typeof example.value === 'object' && example.value) {\n return objectEntries(example.value).map(([key, value]) =>\n mapRow({ name: String(key), value: stringifyValue(value) }),\n )\n }\n\n return []\n}\n"],"mappings":";;;;;AAQA,IAAM,kBAAkB,UAAmB;AACzC,KAAI,iBAAiB,KACnB,QAAO,MAAM;AAEf,KAAI,OAAO,UAAU,YAAY,UAAU,KACzC,QAAO,KAAK,UAAU,MAAM;AAE9B,QAAO,OAAO,MAAM;;;AAItB,IAAa,mBACX,SACA,aACA,mBACe;AAEf,KACE,CAAC,SAAS,SACT,gBAAgB,yBAAyB,gBAAgB,oCAE1D,QAAO,EAAE;CAIX,MAAM,uBAAuB,kBAAkB,eAAe,eAAe,GAAG,iBAAiB,KAAA;CACjG,MAAM,cAAc,uBAAuB,IAAI,IAAI,qBAAqB,YAAY,EAAE,CAAC,GAAG,KAAA;CAE1F,MAAM,UAAU,EACd,MACA,OACA,aAAa,YAKC;EACd,MAAM,MAAgB;GAAE;GAAM;GAAO;GAAY;AACjD,MAAI,CAAC,wBAAwB,CAAC,KAC5B,QAAO;EAET,MAAM,aAAa,QAAQ,OAAO,qBAAqB,aAAa,MAAM;AAC1E,MAAI,SAAS;AACb,MAAI,cAAc,YAAY;AAC9B,MAAI,aAAa,aAAa,IAAI,KAAK;AACvC,MAAI,aAAa;AACjB,SAAO;;AAIT,KAAI,MAAM,QAAQ,QAAQ,MAAM,CAC9B,QAAO,QAAQ,MAAM,KAAK,iBAAiB;AACzC,MAAI,SAAS,aAAa,CAIxB,QAAO,OAAO;GAAE,MAHH,OAAO,aAAa,KAAK;GAGhB,OAFR,aAAa,iBAAiB,OAAO,aAAa,QAAQ,OAAO,aAAa,MAAM;GAErE,YADV,QAAQ,aAAa,WAAW;GACV,CAAC;AAE5C,SAAO;GAAE,MAAM;GAAI,OAAO;GAAc,YAAY;GAAO;GAC3D;AAIJ,KAAI,OAAO,QAAQ,UAAU,YAAY,QAAQ,MAC/C,QAAO,cAAc,QAAQ,MAAM,CAAC,KAAK,CAAC,KAAK,WAC7C,OAAO;EAAE,MAAM,OAAO,IAAI;EAAE,OAAO,eAAe,MAAM;EAAE,CAAC,CAC5D;AAGH,QAAO,EAAE"}
@@ -1,5 +1,5 @@
1
1
  import { extractFilename } from "./extract-filename.js";
2
- import MimeType from "whatwg-mimetype";
2
+ import MimeTypeParser from "whatwg-mimetype";
3
3
  //#region src/v2/blocks/response-block/helpers/process-response-body.ts
4
4
  var isBlob = (b) => b instanceof Blob;
5
5
  /**
@@ -8,7 +8,7 @@ var isBlob = (b) => b instanceof Blob;
8
8
  */
9
9
  function processResponseBody({ data, headers }) {
10
10
  const contentType = headers.find((header) => header.name.toLowerCase() === "content-type");
11
- const mimeType = contentType?.value ? new MimeType(contentType.value) : void 0;
11
+ const mimeType = contentType?.value ? new MimeTypeParser(contentType.value) : void 0;
12
12
  return {
13
13
  mimeType,
14
14
  attachmentFilename: extractFilename(headers.find((header) => header.name.toLowerCase() === "content-disposition")?.value ?? ""),
@@ -1 +1 @@
1
- {"version":3,"file":"process-response-body.js","names":[],"sources":["../../../../../src/v2/blocks/response-block/helpers/process-response-body.ts"],"sourcesContent":["import MimeType from 'whatwg-mimetype'\n\nimport { extractFilename } from './../helpers/extract-filename'\n\nconst isBlob = (b: any): b is Blob => b instanceof Blob\n\n/**\n * Processes the response body of an HTTP request.\n * Extracts MIME type, attachment filename, and generates a data URL.\n */\nexport function processResponseBody({ data, headers }: { data: unknown; headers: { name: string; value: string }[] }) {\n const contentType = headers.find((header) => header.name.toLowerCase() === 'content-type')\n const mimeType = contentType?.value ? new MimeType(contentType.value) : undefined\n const attachmentFilename = extractFilename(\n headers.find((header) => header.name.toLowerCase() === 'content-disposition')?.value ?? '',\n )\n\n const dataUrl = (() => {\n if (isBlob(data)) {\n return URL.createObjectURL(data)\n }\n if (typeof data === 'string') {\n return URL.createObjectURL(new Blob([data], { type: mimeType ? mimeType.toString() : undefined }))\n }\n if (data instanceof Object && Object.keys(data).length) {\n return URL.createObjectURL(\n new Blob([JSON.stringify(data)], {\n type: mimeType ? mimeType.toString() : undefined,\n }),\n )\n }\n return ''\n })()\n\n return { mimeType, attachmentFilename, dataUrl }\n}\n"],"mappings":";;;AAIA,IAAM,UAAU,MAAsB,aAAa;;;;;AAMnD,SAAgB,oBAAoB,EAAE,MAAM,WAA0E;CACpH,MAAM,cAAc,QAAQ,MAAM,WAAW,OAAO,KAAK,aAAa,KAAK,eAAe;CAC1F,MAAM,WAAW,aAAa,QAAQ,IAAI,SAAS,YAAY,MAAM,GAAG,KAAA;AAsBxE,QAAO;EAAE;EAAU,oBArBQ,gBACzB,QAAQ,MAAM,WAAW,OAAO,KAAK,aAAa,KAAK,sBAAsB,EAAE,SAAS,GACzF;EAmBsC,gBAjBhB;AACrB,OAAI,OAAO,KAAK,CACd,QAAO,IAAI,gBAAgB,KAAK;AAElC,OAAI,OAAO,SAAS,SAClB,QAAO,IAAI,gBAAgB,IAAI,KAAK,CAAC,KAAK,EAAE,EAAE,MAAM,WAAW,SAAS,UAAU,GAAG,KAAA,GAAW,CAAC,CAAC;AAEpG,OAAI,gBAAgB,UAAU,OAAO,KAAK,KAAK,CAAC,OAC9C,QAAO,IAAI,gBACT,IAAI,KAAK,CAAC,KAAK,UAAU,KAAK,CAAC,EAAE,EAC/B,MAAM,WAAW,SAAS,UAAU,GAAG,KAAA,GACxC,CAAC,CACH;AAEH,UAAO;MACL;EAE4C"}
1
+ {"version":3,"file":"process-response-body.js","names":[],"sources":["../../../../../src/v2/blocks/response-block/helpers/process-response-body.ts"],"sourcesContent":["import MimeType from 'whatwg-mimetype'\n\nimport { extractFilename } from './../helpers/extract-filename'\n\nconst isBlob = (b: any): b is Blob => b instanceof Blob\n\n/**\n * Processes the response body of an HTTP request.\n * Extracts MIME type, attachment filename, and generates a data URL.\n */\nexport function processResponseBody({ data, headers }: { data: unknown; headers: { name: string; value: string }[] }) {\n const contentType = headers.find((header) => header.name.toLowerCase() === 'content-type')\n const mimeType = contentType?.value ? new MimeType(contentType.value) : undefined\n const attachmentFilename = extractFilename(\n headers.find((header) => header.name.toLowerCase() === 'content-disposition')?.value ?? '',\n )\n\n const dataUrl = (() => {\n if (isBlob(data)) {\n return URL.createObjectURL(data)\n }\n if (typeof data === 'string') {\n return URL.createObjectURL(new Blob([data], { type: mimeType ? mimeType.toString() : undefined }))\n }\n if (data instanceof Object && Object.keys(data).length) {\n return URL.createObjectURL(\n new Blob([JSON.stringify(data)], {\n type: mimeType ? mimeType.toString() : undefined,\n }),\n )\n }\n return ''\n })()\n\n return { mimeType, attachmentFilename, dataUrl }\n}\n"],"mappings":";;;AAIA,IAAM,UAAU,MAAsB,aAAa;;;;;AAMnD,SAAgB,oBAAoB,EAAE,MAAM,WAA0E;CACpH,MAAM,cAAc,QAAQ,MAAM,WAAW,OAAO,KAAK,aAAa,KAAK,eAAe;CAC1F,MAAM,WAAW,aAAa,QAAQ,IAAI,eAAS,YAAY,MAAM,GAAG,KAAA;AAsBxE,QAAO;EAAE;EAAU,oBArBQ,gBACzB,QAAQ,MAAM,WAAW,OAAO,KAAK,aAAa,KAAK,sBAAsB,EAAE,SAAS,GACzF;EAmBsC,gBAjBhB;AACrB,OAAI,OAAO,KAAK,CACd,QAAO,IAAI,gBAAgB,KAAK;AAElC,OAAI,OAAO,SAAS,SAClB,QAAO,IAAI,gBAAgB,IAAI,KAAK,CAAC,KAAK,EAAE,EAAE,MAAM,WAAW,SAAS,UAAU,GAAG,KAAA,GAAW,CAAC,CAAC;AAEpG,OAAI,gBAAgB,UAAU,OAAO,KAAK,KAAK,CAAC,OAC9C,QAAO,IAAI,gBACT,IAAI,KAAK,CAAC,KAAK,UAAU,KAAK,CAAC,EAAE,EAC/B,MAAM,WAAW,SAAS,UAAU,GAAG,KAAA,GACxC,CAAC,CACH;AAEH,UAAO;MACL;EAE4C"}
@@ -1,6 +1,6 @@
1
1
  //#region src/v2/constants.ts
2
2
  /** The version number taken from the package.json. Consumers can override at build time via define (e.g. OVERRIDE_PACKAGE_VERSION: JSON.stringify('1.2.3')). */
3
- var APP_VERSION = typeof OVERRIDE_PACKAGE_VERSION !== "undefined" ? OVERRIDE_PACKAGE_VERSION : "2.39.1";
3
+ var APP_VERSION = typeof OVERRIDE_PACKAGE_VERSION !== "undefined" ? OVERRIDE_PACKAGE_VERSION : "2.39.3";
4
4
  //#endregion
5
5
  export { APP_VERSION };
6
6
 
@@ -1 +1 @@
1
- {"version":3,"file":"Editor.vue.d.ts","sourceRoot":"","sources":["../../../../../../src/v2/features/collection/components/Editor/Editor.vue"],"names":[],"mappings":"AA0xCA,QAAA,MAAM,YAAY;;;;;;;;;;;;kGAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
1
+ {"version":3,"file":"Editor.vue.d.ts","sourceRoot":"","sources":["../../../../../../src/v2/features/collection/components/Editor/Editor.vue"],"names":[],"mappings":"AA4xCA,QAAA,MAAM,YAAY;;;;;;;;;;;;kGAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
@@ -2,7 +2,7 @@ import _plugin_vue_export_helper_default from "../../../../../_virtual/_plugin-v
2
2
  import Editor_vue_vue_type_script_setup_true_lang_default from "./Editor.vue.script.js";
3
3
  /* empty css */
4
4
  //#region src/v2/features/collection/components/Editor/Editor.vue
5
- var Editor_default = /* @__PURE__ */ _plugin_vue_export_helper_default(Editor_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-850fff8f"]]);
5
+ var Editor_default = /* @__PURE__ */ _plugin_vue_export_helper_default(Editor_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-e99ee660"]]);
6
6
  //#endregion
7
7
  export { Editor_default as default };
8
8
 
@@ -1 +1 @@
1
- {"version":3,"file":"Editor.vue.js","names":[],"sources":["../../../../../../src/v2/features/collection/components/Editor/Editor.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton, ScalarHotkey, useLoadingState } from '@scalar/components'\nimport { debounce } from '@scalar/helpers/general/debounce'\nimport { isObject } from '@scalar/helpers/object/is-object'\nimport { ScalarIconArrowsIn, ScalarIconArrowsOut } from '@scalar/icons'\nimport * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js'\nimport {\n computed,\n nextTick,\n onBeforeUnmount,\n onMounted,\n ref,\n shallowRef,\n watch,\n} from 'vue'\n\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport { useEditor, useJsonPointerLinkSupport } from '@/v2/features/editor'\nimport { createJsonModel } from '@/v2/features/editor/helpers/json/create-json-model'\nimport { createYamlModel } from '@/v2/features/editor/helpers/yaml/create-yaml-model'\nimport { useEditorMarkers } from '@/v2/features/editor/hooks/use-editor-markers'\n\nimport EditorDiagnosticsPanel from './components/EditorDiagnosticsPanel.vue'\nimport EditorSavePanel from './components/EditorSavePanel.vue'\nimport { getDiagnosticCounts } from './helpers/get-diagnostic-counts'\nimport { getOperationContext } from './helpers/get-operation-context'\nimport { getVisibleDiagnostics } from './helpers/get-visible-diagnostics'\nimport { parseEditorObject } from './helpers/parse-editor-object'\nimport { stringifyDocument } from './helpers/stringify-document'\nimport { useEditorState } from './hooks/use-editor-state'\n\nconst { collectionType, documentSlug, method, path, workspaceStore } =\n defineProps<CollectionProps>()\n\nconst MAX_VISIBLE_DIAGNOSTICS = 6\nconst EDITOR_PERSIST_DEBOUNCE_KEY = 'editor:replace-document'\n\nconst monacoEditorRef = ref<HTMLElement>()\nconst editorApi = shallowRef<ReturnType<typeof useEditor>>()\n\nconst saveLoader = useLoadingState()\nconst {\n isAutoSaveEnabled,\n isDirty,\n editorLanguage,\n isDiagnosticsPaneExpanded,\n isEditorMaximized,\n isYamlMode,\n editorBottomPadding,\n editorRootClass,\n getLanguageToggleClass,\n toggleEditorMaximized,\n} = useEditorState()\n\nconst jsonModel = createJsonModel()\nconst yamlModel = createYamlModel()\n\nconst selectedLanguage = ref<'json' | 'yaml'>('json')\n\nconst currentModel = computed(() => {\n return selectedLanguage.value === 'json' ? jsonModel : yamlModel\n})\n\nconst monacoEditorInstance = computed(() => editorApi.value?.editor)\nconst { markers: diagnostics } = useEditorMarkers(monacoEditorInstance)\n\nconst syncEditorBottomPadding = () => {\n editorApi.value?.editor.updateOptions({\n padding: {\n top: 0,\n bottom: editorBottomPadding.value,\n },\n })\n}\n\nconst diagnosticCounts = computed(() => getDiagnosticCounts(diagnostics.value))\nconst visibleDiagnostics = computed(() =>\n getVisibleDiagnostics(diagnostics.value, MAX_VISIBLE_DIAGNOSTICS),\n)\n\nconst focusDiagnostic = (marker: monaco.editor.IMarker) => {\n const editor = editorApi.value?.editor\n if (!editor) {\n return\n }\n editor.setSelection({\n startLineNumber: marker.startLineNumber,\n startColumn: marker.startColumn,\n endLineNumber: marker.endLineNumber,\n endColumn: marker.endColumn,\n })\n editor.revealPositionInCenter({\n lineNumber: marker.startLineNumber,\n column: marker.startColumn,\n })\n}\n\nconst getEditorValue = (): string | null => currentModel.value.model.getValue()\n\n/** Value from the editor for a specific language (use when switching to avoid reading the wrong model). */\nconst getEditorValueForLanguage = (language: 'json' | 'yaml'): string | null =>\n (language === 'json' ? jsonModel : yamlModel).model.getValue()\n\nconst getDocumentValue = async (\n language?: 'json' | 'yaml',\n): Promise<string> => {\n const document = await workspaceStore.getEditableDocument(documentSlug)\n return stringifyDocument(document, language ?? selectedLanguage.value)\n}\n\nconst debouncedPersist = debounce({ delay: 1500 })\n\nconst applyProgrammaticEditorValue = (value: string): void => {\n // Cancel pending auto-save work so synthetic model updates do not persist stale data.\n debouncedPersist.cleanup()\n editorApi.value?.setValue(value, true)\n}\n\nconst loadDocumentIntoEditor = async () => {\n applyProgrammaticEditorValue(await getDocumentValue())\n isDirty.value = false\n await focusOperation()\n}\n\nconst formatDocument = async () => {\n await editorApi.value?.formatDocument()\n}\n\nconst focusOperation = async () => {\n const operationContext = getOperationContext(path, method)\n if (!operationContext) {\n return\n }\n\n await editorApi.value?.focusPath([\n 'paths',\n operationContext.path,\n operationContext.method,\n ])\n}\n\nconst persistEditorToWorkspace = async (value: string) => {\n const parsed = parseEditorObject(value, editorLanguage.value)\n if (!parsed) {\n const firstError = diagnostics.value.find(\n (m) => m.severity === monaco.MarkerSeverity.Error,\n )\n if (firstError) {\n focusDiagnostic(firstError)\n }\n await saveLoader.invalidate()\n return\n }\n\n saveLoader.start()\n await workspaceStore.replaceDocument(documentSlug, parsed)\n isDirty.value = false\n await saveLoader.validate({ duration: 900 })\n}\n\nconst saveNow = async () => {\n const value = getEditorValue()\n if (!value) {\n return\n }\n await persistEditorToWorkspace(value)\n}\n\nconst handleEditorChange = (value: string) => {\n isDirty.value = true\n\n if (!isAutoSaveEnabled.value) {\n return\n }\n\n debouncedPersist.execute(EDITOR_PERSIST_DEBOUNCE_KEY, () =>\n persistEditorToWorkspace(value),\n )\n}\n\nconst focusOperationServers = async () => {\n const operationContext = getOperationContext(path, method)\n if (!operationContext) {\n return\n }\n\n const value = getEditorValue()\n if (!value) {\n return\n }\n\n const parsed = parseEditorObject(value, editorLanguage.value)\n\n if (!parsed || !isObject(parsed.paths)) {\n return\n }\n\n const pathsObject = parsed.paths as Record<string, unknown>\n const operationPathItem = pathsObject[operationContext.path]\n if (!isObject(operationPathItem)) {\n return\n }\n\n const operation = operationPathItem[operationContext.method]\n if (!isObject(operation)) {\n return\n }\n\n // Add default servers if not present\n operation.servers ??= []\n\n // Update the editor value\n editorApi.value?.setValue(stringifyDocument(parsed, editorLanguage.value))\n await editorApi.value?.focusPath([\n 'paths',\n operationContext.path,\n operationContext.method,\n 'servers',\n ])\n}\n\nuseJsonPointerLinkSupport(editorApi, currentModel)\n\nonMounted(() => {\n editorApi.value = useEditor({\n element: monacoEditorRef.value ?? document.createElement('div'),\n onChange: handleEditorChange,\n model: currentModel,\n actions: [\n {\n id: 'scalar.editor.focusOperation',\n label: 'Focus Operation',\n keybindings: [monaco.KeyMod.Alt | monaco.KeyCode.KeyO],\n run: async () => {\n await focusOperation()\n },\n },\n {\n id: 'scalar.editor.focusOperationServers',\n label: 'Focus Operation Servers',\n keybindings: [monaco.KeyMod.Alt | monaco.KeyCode.KeyS],\n run: async () => {\n await focusOperationServers()\n },\n },\n {\n id: 'scalar.editor.formatDocument',\n label: 'Format Document',\n keybindings: [\n monaco.KeyMod.Alt | monaco.KeyMod.Shift | monaco.KeyCode.KeyF,\n ],\n run: async () => {\n await formatDocument()\n },\n },\n ],\n })\n\n syncEditorBottomPadding()\n void loadDocumentIntoEditor()\n})\n\nonBeforeUnmount(() => {\n debouncedPersist.cleanup()\n\n // Persist if there is a pending save\n if (isDirty.value && isAutoSaveEnabled.value) {\n void saveNow()\n }\n editorApi.value?.dispose?.()\n // Dispose models created at setup; useEditor only disposes the editor widget, not external models.\n jsonModel.model.dispose()\n yamlModel.model.dispose()\n})\n\nwatch(() => documentSlug, loadDocumentIntoEditor)\n\nwatch(\n () => [path, method] as const,\n async () => {\n await focusOperation()\n },\n)\n\nwatch(isDiagnosticsPaneExpanded, () => {\n syncEditorBottomPadding()\n})\n\nwatch(editorLanguage, async (nextLanguage, previousLanguage) => {\n const wasDirty = isDirty.value\n // Read from the previous model before switching; getEditorValue() would use currentModel\n // which changes with selectedLanguage, so we would read the (empty) new model otherwise.\n const value = getEditorValueForLanguage(previousLanguage ?? 'json')\n if (!value) {\n selectedLanguage.value = nextLanguage\n await nextTick()\n await focusOperation()\n return\n }\n\n const parsed = parseEditorObject(value, previousLanguage ?? 'json')\n selectedLanguage.value = nextLanguage\n await nextTick()\n if (parsed) {\n applyProgrammaticEditorValue(stringifyDocument(parsed, nextLanguage))\n isDirty.value = wasDirty\n }\n await focusOperation()\n})\n\nwatch(\n isAutoSaveEnabled,\n (isEnabled) => {\n if (!isEnabled) {\n debouncedPersist.cleanup()\n return\n }\n\n if (isDirty.value) {\n const value = getEditorValue()\n if (!value) {\n return\n }\n debouncedPersist.execute(EDITOR_PERSIST_DEBOUNCE_KEY, () =>\n persistEditorToWorkspace(value),\n )\n }\n },\n { flush: 'post' },\n)\n</script>\n\n<template>\n <div\n v-if=\"\n collectionType === 'operation' &&\n getOperationContext(path, method) !== null\n \"\n class=\"flex w-full min-w-0 flex-1 flex-col gap-2\"\n :class=\"editorRootClass\">\n <div\n class=\"grid grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] items-center gap-3\">\n <div\n class=\"flex min-w-0 items-center gap-1 overflow-x-auto whitespace-nowrap\">\n <span class=\"text-c-2 text-xs font-medium whitespace-nowrap\">\n Shortcuts\n </span>\n\n <ScalarButton\n class=\"whitespace-nowrap\"\n size=\"xs\"\n variant=\"ghost\"\n @click=\"focusOperation\">\n <span>Operation</span>\n <span class=\"text-c-3 ml-2 text-[11px]\">\n <ScalarHotkey\n hotkey=\"O\"\n :modifier=\"['Alt']\" />\n </span>\n </ScalarButton>\n\n <ScalarButton\n class=\"whitespace-nowrap\"\n size=\"xs\"\n variant=\"ghost\"\n @click=\"focusOperationServers\">\n <span>Servers</span>\n <span class=\"text-c-3 ml-2 text-[11px]\">\n <ScalarHotkey\n hotkey=\"S\"\n :modifier=\"['Alt']\" />\n </span>\n </ScalarButton>\n </div>\n\n <div\n aria-label=\"Editor language\"\n class=\"bg-b-1 shadow-border flex items-center justify-self-center overflow-hidden rounded-lg p-0.5\"\n role=\"tablist\">\n <ScalarButton\n :aria-selected=\"!isYamlMode\"\n :class=\"getLanguageToggleClass(!isYamlMode)\"\n role=\"tab\"\n size=\"xs\"\n type=\"button\"\n variant=\"ghost\"\n @click=\"editorLanguage = 'json'\">\n JSON\n </ScalarButton>\n <ScalarButton\n :aria-selected=\"isYamlMode\"\n :class=\"getLanguageToggleClass(isYamlMode)\"\n role=\"tab\"\n size=\"xs\"\n type=\"button\"\n variant=\"ghost\"\n @click=\"editorLanguage = 'yaml'\">\n YAML\n </ScalarButton>\n </div>\n\n <div class=\"flex min-w-0 shrink-0 items-center gap-2 justify-self-end\">\n <ScalarButton\n size=\"xs\"\n variant=\"ghost\"\n @click=\"formatDocument\">\n <span>Format {{ isYamlMode ? 'YAML' : 'JSON' }}</span>\n <span class=\"text-c-3 ml-2 text-[11px]\">\n <ScalarHotkey\n hotkey=\"F\"\n :modifier=\"['Alt', 'Shift']\" />\n </span>\n </ScalarButton>\n <ScalarButton\n :aria-label=\"\n isEditorMaximized ? 'Restore editor size' : 'Maximize editor'\n \"\n size=\"xs\"\n variant=\"ghost\"\n @click=\"toggleEditorMaximized\">\n <span>{{ isEditorMaximized ? 'Restore' : 'Maximize' }}</span>\n <span class=\"text-c-3 ml-2 text-[11px]\">\n <ScalarIconArrowsIn\n v-if=\"isEditorMaximized\"\n class=\"size-3.5\" />\n <ScalarIconArrowsOut\n v-else\n class=\"size-3.5\" />\n </span>\n </ScalarButton>\n </div>\n </div>\n\n <div class=\"flex min-h-0 w-full min-w-0 flex-1 rounded-lg border\">\n <div\n class=\"relative w-full min-w-0 flex-1\"\n :class=\"isEditorMaximized ? 'h-full min-h-0' : 'h-[500px]'\">\n <div class=\"pointer-events-none absolute top-2 right-2 z-10\">\n <EditorSavePanel\n :isAutoSaveEnabled=\"isAutoSaveEnabled\"\n :isDirty=\"isDirty\"\n :saveLoader=\"saveLoader\"\n @saveNow=\"saveNow\"\n @update:isAutoSaveEnabled=\"isAutoSaveEnabled = $event\" />\n </div>\n\n <EditorDiagnosticsPanel\n :diagnosticCounts=\"diagnosticCounts\"\n :expanded=\"isDiagnosticsPaneExpanded\"\n :visibleDiagnostics=\"visibleDiagnostics\"\n @focusDiagnostic=\"focusDiagnostic\"\n @toggle=\"isDiagnosticsPaneExpanded = !isDiagnosticsPaneExpanded\" />\n\n <div\n ref=\"monacoEditorRef\"\n class=\"h-full w-full min-w-0 flex-1\" />\n </div>\n </div>\n </div>\n <div v-else>No operation context found</div>\n</template>\n<style scoped>\n.editor-container {\n width: 100%;\n height: 100%;\n}\n\n:deep(.json-path-highlight) {\n background-color: rgba(255, 200, 0, 0.35);\n border-radius: 4px;\n}\n\n:deep(.json-focus-highlight) {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-accent, #24b47e) 18%,\n transparent\n );\n border-radius: 4px;\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"Editor.vue.js","names":[],"sources":["../../../../../../src/v2/features/collection/components/Editor/Editor.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton, ScalarHotkey, useLoadingState } from '@scalar/components'\nimport { debounce } from '@scalar/helpers/general/debounce'\nimport { isObject } from '@scalar/helpers/object/is-object'\nimport { ScalarIconArrowsIn, ScalarIconArrowsOut } from '@scalar/icons'\nimport * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js'\nimport {\n computed,\n nextTick,\n onBeforeUnmount,\n onMounted,\n ref,\n shallowRef,\n watch,\n} from 'vue'\n\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport { useEditor, useJsonPointerLinkSupport } from '@/v2/features/editor'\nimport { createJsonModel } from '@/v2/features/editor/helpers/json/create-json-model'\nimport { createYamlModel } from '@/v2/features/editor/helpers/yaml/create-yaml-model'\nimport { useEditorMarkers } from '@/v2/features/editor/hooks/use-editor-markers'\n\nimport EditorDiagnosticsPanel from './components/EditorDiagnosticsPanel.vue'\nimport EditorSavePanel from './components/EditorSavePanel.vue'\nimport { getDiagnosticCounts } from './helpers/get-diagnostic-counts'\nimport { getOperationContext } from './helpers/get-operation-context'\nimport { getVisibleDiagnostics } from './helpers/get-visible-diagnostics'\nimport { parseEditorObject } from './helpers/parse-editor-object'\nimport { stringifyDocument } from './helpers/stringify-document'\nimport { useEditorState } from './hooks/use-editor-state'\n\nconst { collectionType, documentSlug, method, path, workspaceStore } =\n defineProps<CollectionProps>()\n\nconst MAX_VISIBLE_DIAGNOSTICS = 6\nconst EDITOR_PERSIST_DEBOUNCE_KEY = 'editor:replace-document'\n\nconst monacoEditorRef = ref<HTMLElement>()\nconst editorApi = shallowRef<ReturnType<typeof useEditor>>()\n\nconst saveLoader = useLoadingState()\nconst {\n isAutoSaveEnabled,\n isDirty,\n editorLanguage,\n isDiagnosticsPaneExpanded,\n isEditorMaximized,\n isYamlMode,\n editorBottomPadding,\n editorRootClass,\n getLanguageToggleClass,\n toggleEditorMaximized,\n} = useEditorState()\n\nconst jsonModel = createJsonModel()\nconst yamlModel = createYamlModel()\n\nconst selectedLanguage = ref<'json' | 'yaml'>('json')\n\nconst currentModel = computed(() => {\n return selectedLanguage.value === 'json' ? jsonModel : yamlModel\n})\n\nconst monacoEditorInstance = computed(() => editorApi.value?.editor)\nconst { markers: diagnostics } = useEditorMarkers(monacoEditorInstance)\n\nconst syncEditorBottomPadding = () => {\n editorApi.value?.editor.updateOptions({\n padding: {\n top: 0,\n bottom: editorBottomPadding.value,\n },\n })\n}\n\nconst diagnosticCounts = computed(() => getDiagnosticCounts(diagnostics.value))\nconst visibleDiagnostics = computed(() =>\n getVisibleDiagnostics(diagnostics.value, MAX_VISIBLE_DIAGNOSTICS),\n)\n\nconst focusDiagnostic = (marker: monaco.editor.IMarker) => {\n const editor = editorApi.value?.editor\n if (!editor) {\n return\n }\n editor.setSelection({\n startLineNumber: marker.startLineNumber,\n startColumn: marker.startColumn,\n endLineNumber: marker.endLineNumber,\n endColumn: marker.endColumn,\n })\n editor.revealPositionInCenter({\n lineNumber: marker.startLineNumber,\n column: marker.startColumn,\n })\n}\n\nconst getEditorValue = (): string | null => currentModel.value.model.getValue()\n\n/** Value from the editor for a specific language (use when switching to avoid reading the wrong model). */\nconst getEditorValueForLanguage = (language: 'json' | 'yaml'): string | null =>\n (language === 'json' ? jsonModel : yamlModel).model.getValue()\n\nconst getDocumentValue = async (\n language?: 'json' | 'yaml',\n): Promise<string> => {\n const document = await workspaceStore.getEditableDocument(documentSlug)\n return stringifyDocument(document, language ?? selectedLanguage.value)\n}\n\nconst debouncedPersist = debounce({ delay: 1500 })\n\nconst applyProgrammaticEditorValue = (value: string): void => {\n // Cancel pending auto-save work so synthetic model updates do not persist stale data.\n debouncedPersist.cleanup()\n editorApi.value?.setValue(value, true)\n}\n\nconst loadDocumentIntoEditor = async () => {\n applyProgrammaticEditorValue(await getDocumentValue())\n isDirty.value = false\n await focusOperation()\n}\n\nconst formatDocument = async () => {\n await editorApi.value?.formatDocument()\n}\n\nconst focusOperation = async () => {\n const operationContext = getOperationContext(path, method)\n if (!operationContext) {\n return\n }\n\n await editorApi.value?.focusPath([\n 'paths',\n operationContext.path,\n operationContext.method,\n ])\n}\n\nconst persistEditorToWorkspace = async (value: string) => {\n const parsed = parseEditorObject(value, editorLanguage.value)\n if (!parsed) {\n const firstError = diagnostics.value.find(\n (m) => m.severity === monaco.MarkerSeverity.Error,\n )\n if (firstError) {\n focusDiagnostic(firstError)\n }\n await saveLoader.invalidate()\n return\n }\n\n saveLoader.start()\n await workspaceStore.replaceDocument(documentSlug, parsed)\n isDirty.value = false\n await saveLoader.validate({ duration: 900 })\n}\n\nconst saveNow = async () => {\n const value = getEditorValue()\n if (!value) {\n return\n }\n await persistEditorToWorkspace(value)\n}\n\nconst handleEditorChange = (value: string) => {\n isDirty.value = true\n\n if (!isAutoSaveEnabled.value) {\n return\n }\n\n debouncedPersist.execute(EDITOR_PERSIST_DEBOUNCE_KEY, () =>\n persistEditorToWorkspace(value),\n )\n}\n\nconst focusOperationServers = async () => {\n const operationContext = getOperationContext(path, method)\n if (!operationContext) {\n return\n }\n\n const value = getEditorValue()\n if (!value) {\n return\n }\n\n const parsed = parseEditorObject(value, editorLanguage.value)\n\n if (!parsed || !isObject(parsed.paths)) {\n return\n }\n\n const pathsObject = parsed.paths as Record<string, unknown>\n const operationPathItem = pathsObject[operationContext.path]\n if (!isObject(operationPathItem)) {\n return\n }\n\n const operation = operationPathItem[operationContext.method]\n if (!isObject(operation)) {\n return\n }\n\n // Add default servers if not present\n operation.servers ??= []\n\n // Update the editor value\n editorApi.value?.setValue(stringifyDocument(parsed, editorLanguage.value))\n await editorApi.value?.focusPath([\n 'paths',\n operationContext.path,\n operationContext.method,\n 'servers',\n ])\n}\n\nuseJsonPointerLinkSupport(editorApi, currentModel)\n\nonMounted(() => {\n editorApi.value = useEditor({\n element: monacoEditorRef.value ?? document.createElement('div'),\n onChange: handleEditorChange,\n model: currentModel,\n actions: [\n {\n id: 'scalar.editor.focusOperation',\n label: 'Focus Operation',\n keybindings: [monaco.KeyMod.Alt | monaco.KeyCode.KeyO],\n run: async () => {\n await focusOperation()\n },\n },\n {\n id: 'scalar.editor.focusOperationServers',\n label: 'Focus Operation Servers',\n keybindings: [monaco.KeyMod.Alt | monaco.KeyCode.KeyS],\n run: async () => {\n await focusOperationServers()\n },\n },\n {\n id: 'scalar.editor.formatDocument',\n label: 'Format Document',\n keybindings: [\n monaco.KeyMod.Alt | monaco.KeyMod.Shift | monaco.KeyCode.KeyF,\n ],\n run: async () => {\n await formatDocument()\n },\n },\n ],\n })\n\n syncEditorBottomPadding()\n void loadDocumentIntoEditor()\n})\n\nonBeforeUnmount(() => {\n debouncedPersist.cleanup()\n\n // Persist if there is a pending save\n if (isDirty.value && isAutoSaveEnabled.value) {\n void saveNow()\n }\n editorApi.value?.dispose?.()\n // Dispose models created at setup; useEditor only disposes the editor widget, not external models.\n jsonModel.model.dispose()\n yamlModel.model.dispose()\n})\n\nwatch(() => documentSlug, loadDocumentIntoEditor)\n\nwatch(\n () => [path, method] as const,\n async () => {\n await focusOperation()\n },\n)\n\nwatch(isDiagnosticsPaneExpanded, () => {\n syncEditorBottomPadding()\n})\n\nwatch(editorLanguage, async (nextLanguage, previousLanguage) => {\n const wasDirty = isDirty.value\n // Read from the previous model before switching; getEditorValue() would use currentModel\n // which changes with selectedLanguage, so we would read the (empty) new model otherwise.\n const value = getEditorValueForLanguage(previousLanguage ?? 'json')\n if (!value) {\n selectedLanguage.value = nextLanguage\n await nextTick()\n await focusOperation()\n return\n }\n\n const parsed = parseEditorObject(value, previousLanguage ?? 'json')\n selectedLanguage.value = nextLanguage\n await nextTick()\n if (parsed) {\n applyProgrammaticEditorValue(stringifyDocument(parsed, nextLanguage))\n isDirty.value = wasDirty\n }\n await focusOperation()\n})\n\nwatch(\n isAutoSaveEnabled,\n (isEnabled) => {\n if (!isEnabled) {\n debouncedPersist.cleanup()\n return\n }\n\n if (isDirty.value) {\n const value = getEditorValue()\n if (!value) {\n return\n }\n debouncedPersist.execute(EDITOR_PERSIST_DEBOUNCE_KEY, () =>\n persistEditorToWorkspace(value),\n )\n }\n },\n { flush: 'post' },\n)\n</script>\n\n<template>\n <div\n v-if=\"\n collectionType === 'operation' &&\n getOperationContext(path, method) !== null\n \"\n class=\"flex w-full min-w-0 flex-1 flex-col gap-2\"\n :class=\"editorRootClass\">\n <div\n class=\"grid grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] items-center gap-3\">\n <div\n class=\"flex min-w-0 items-center gap-1 overflow-x-auto whitespace-nowrap\">\n <span class=\"text-c-2 text-xs font-medium whitespace-nowrap\">\n Shortcuts\n </span>\n\n <ScalarButton\n class=\"whitespace-nowrap\"\n size=\"xs\"\n variant=\"ghost\"\n @click=\"focusOperation\">\n <span>Operation</span>\n <span class=\"text-c-3 ml-2 text-[11px]\">\n <ScalarHotkey\n hotkey=\"O\"\n :modifier=\"['Alt']\" />\n </span>\n </ScalarButton>\n\n <ScalarButton\n class=\"whitespace-nowrap\"\n size=\"xs\"\n variant=\"ghost\"\n @click=\"focusOperationServers\">\n <span>Servers</span>\n <span class=\"text-c-3 ml-2 text-[11px]\">\n <ScalarHotkey\n hotkey=\"S\"\n :modifier=\"['Alt']\" />\n </span>\n </ScalarButton>\n </div>\n\n <div\n aria-label=\"Editor language\"\n class=\"bg-b-1 shadow-border flex items-center justify-self-center overflow-hidden rounded-lg p-0.5\"\n role=\"tablist\">\n <ScalarButton\n :aria-selected=\"!isYamlMode\"\n :class=\"getLanguageToggleClass(!isYamlMode)\"\n role=\"tab\"\n size=\"xs\"\n type=\"button\"\n variant=\"ghost\"\n @click=\"editorLanguage = 'json'\">\n JSON\n </ScalarButton>\n <ScalarButton\n :aria-selected=\"isYamlMode\"\n :class=\"getLanguageToggleClass(isYamlMode)\"\n role=\"tab\"\n size=\"xs\"\n type=\"button\"\n variant=\"ghost\"\n @click=\"editorLanguage = 'yaml'\">\n YAML\n </ScalarButton>\n </div>\n\n <div class=\"flex min-w-0 shrink-0 items-center gap-2 justify-self-end\">\n <ScalarButton\n size=\"xs\"\n variant=\"ghost\"\n @click=\"formatDocument\">\n <span>Format {{ isYamlMode ? 'YAML' : 'JSON' }}</span>\n <span class=\"text-c-3 ml-2 text-[11px]\">\n <ScalarHotkey\n hotkey=\"F\"\n :modifier=\"['Alt', 'Shift']\" />\n </span>\n </ScalarButton>\n <ScalarButton\n :aria-label=\"\n isEditorMaximized ? 'Restore editor size' : 'Maximize editor'\n \"\n size=\"xs\"\n variant=\"ghost\"\n @click=\"toggleEditorMaximized\">\n <span>{{ isEditorMaximized ? 'Restore' : 'Maximize' }}</span>\n <span class=\"text-c-3 ml-2 text-[11px]\">\n <ScalarIconArrowsIn\n v-if=\"isEditorMaximized\"\n class=\"size-3.5\" />\n <ScalarIconArrowsOut\n v-else\n class=\"size-3.5\" />\n </span>\n </ScalarButton>\n </div>\n </div>\n\n <div class=\"flex min-h-0 w-full min-w-0 flex-1 rounded-lg border\">\n <div\n class=\"relative w-full min-w-0 flex-1\"\n :class=\"isEditorMaximized ? 'h-full min-h-0' : 'h-125'\">\n <div class=\"pointer-events-none absolute top-2 right-2 z-10\">\n <EditorSavePanel\n :isAutoSaveEnabled=\"isAutoSaveEnabled\"\n :isDirty=\"isDirty\"\n :saveLoader=\"saveLoader\"\n @saveNow=\"saveNow\"\n @update:isAutoSaveEnabled=\"isAutoSaveEnabled = $event\" />\n </div>\n\n <EditorDiagnosticsPanel\n :diagnosticCounts=\"diagnosticCounts\"\n :expanded=\"isDiagnosticsPaneExpanded\"\n :visibleDiagnostics=\"visibleDiagnostics\"\n @focusDiagnostic=\"focusDiagnostic\"\n @toggle=\"isDiagnosticsPaneExpanded = !isDiagnosticsPaneExpanded\" />\n\n <div\n ref=\"monacoEditorRef\"\n class=\"h-full w-full min-w-0 flex-1 [&_.monaco-editor]:rounded-lg [&_.overflow-guard]:rounded-lg\" />\n </div>\n </div>\n </div>\n <div v-else>No operation context found</div>\n</template>\n<style scoped>\n.editor-container {\n width: 100%;\n height: 100%;\n}\n\n:deep(.json-path-highlight) {\n background-color: rgba(255, 200, 0, 0.35);\n border-radius: 4px;\n}\n\n:deep(.json-focus-highlight) {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-accent, #24b47e) 18%,\n transparent\n );\n border-radius: 4px;\n}\n</style>\n"],"mappings":""}
@@ -322,7 +322,7 @@ var Editor_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
322
322
  }))])]),
323
323
  _: 1
324
324
  }, 8, ["aria-label", "onClick"])])
325
- ]), createElementVNode("div", _hoisted_9, [createElementVNode("div", { class: normalizeClass(["relative w-full min-w-0 flex-1", unref(isEditorMaximized) ? "h-full min-h-0" : "h-[500px]"]) }, [
325
+ ]), createElementVNode("div", _hoisted_9, [createElementVNode("div", { class: normalizeClass(["relative w-full min-w-0 flex-1", unref(isEditorMaximized) ? "h-full min-h-0" : "h-125"]) }, [
326
326
  createElementVNode("div", _hoisted_10, [createVNode(EditorSavePanel_default, {
327
327
  isAutoSaveEnabled: unref(isAutoSaveEnabled),
328
328
  isDirty: unref(isDirty),
@@ -348,7 +348,7 @@ var Editor_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
348
348
  createElementVNode("div", {
349
349
  ref_key: "monacoEditorRef",
350
350
  ref: monacoEditorRef,
351
- class: "h-full w-full min-w-0 flex-1"
351
+ class: "h-full w-full min-w-0 flex-1 [&_.monaco-editor]:rounded-lg [&_.overflow-guard]:rounded-lg"
352
352
  }, null, 512)
353
353
  ], 2)])], 2)) : (openBlock(), createElementBlock("div", _hoisted_11, "No operation context found"));
354
354
  };
@@ -1 +1 @@
1
- {"version":3,"file":"Editor.vue.script.js","names":[],"sources":["../../../../../../src/v2/features/collection/components/Editor/Editor.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton, ScalarHotkey, useLoadingState } from '@scalar/components'\nimport { debounce } from '@scalar/helpers/general/debounce'\nimport { isObject } from '@scalar/helpers/object/is-object'\nimport { ScalarIconArrowsIn, ScalarIconArrowsOut } from '@scalar/icons'\nimport * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js'\nimport {\n computed,\n nextTick,\n onBeforeUnmount,\n onMounted,\n ref,\n shallowRef,\n watch,\n} from 'vue'\n\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport { useEditor, useJsonPointerLinkSupport } from '@/v2/features/editor'\nimport { createJsonModel } from '@/v2/features/editor/helpers/json/create-json-model'\nimport { createYamlModel } from '@/v2/features/editor/helpers/yaml/create-yaml-model'\nimport { useEditorMarkers } from '@/v2/features/editor/hooks/use-editor-markers'\n\nimport EditorDiagnosticsPanel from './components/EditorDiagnosticsPanel.vue'\nimport EditorSavePanel from './components/EditorSavePanel.vue'\nimport { getDiagnosticCounts } from './helpers/get-diagnostic-counts'\nimport { getOperationContext } from './helpers/get-operation-context'\nimport { getVisibleDiagnostics } from './helpers/get-visible-diagnostics'\nimport { parseEditorObject } from './helpers/parse-editor-object'\nimport { stringifyDocument } from './helpers/stringify-document'\nimport { useEditorState } from './hooks/use-editor-state'\n\nconst { collectionType, documentSlug, method, path, workspaceStore } =\n defineProps<CollectionProps>()\n\nconst MAX_VISIBLE_DIAGNOSTICS = 6\nconst EDITOR_PERSIST_DEBOUNCE_KEY = 'editor:replace-document'\n\nconst monacoEditorRef = ref<HTMLElement>()\nconst editorApi = shallowRef<ReturnType<typeof useEditor>>()\n\nconst saveLoader = useLoadingState()\nconst {\n isAutoSaveEnabled,\n isDirty,\n editorLanguage,\n isDiagnosticsPaneExpanded,\n isEditorMaximized,\n isYamlMode,\n editorBottomPadding,\n editorRootClass,\n getLanguageToggleClass,\n toggleEditorMaximized,\n} = useEditorState()\n\nconst jsonModel = createJsonModel()\nconst yamlModel = createYamlModel()\n\nconst selectedLanguage = ref<'json' | 'yaml'>('json')\n\nconst currentModel = computed(() => {\n return selectedLanguage.value === 'json' ? jsonModel : yamlModel\n})\n\nconst monacoEditorInstance = computed(() => editorApi.value?.editor)\nconst { markers: diagnostics } = useEditorMarkers(monacoEditorInstance)\n\nconst syncEditorBottomPadding = () => {\n editorApi.value?.editor.updateOptions({\n padding: {\n top: 0,\n bottom: editorBottomPadding.value,\n },\n })\n}\n\nconst diagnosticCounts = computed(() => getDiagnosticCounts(diagnostics.value))\nconst visibleDiagnostics = computed(() =>\n getVisibleDiagnostics(diagnostics.value, MAX_VISIBLE_DIAGNOSTICS),\n)\n\nconst focusDiagnostic = (marker: monaco.editor.IMarker) => {\n const editor = editorApi.value?.editor\n if (!editor) {\n return\n }\n editor.setSelection({\n startLineNumber: marker.startLineNumber,\n startColumn: marker.startColumn,\n endLineNumber: marker.endLineNumber,\n endColumn: marker.endColumn,\n })\n editor.revealPositionInCenter({\n lineNumber: marker.startLineNumber,\n column: marker.startColumn,\n })\n}\n\nconst getEditorValue = (): string | null => currentModel.value.model.getValue()\n\n/** Value from the editor for a specific language (use when switching to avoid reading the wrong model). */\nconst getEditorValueForLanguage = (language: 'json' | 'yaml'): string | null =>\n (language === 'json' ? jsonModel : yamlModel).model.getValue()\n\nconst getDocumentValue = async (\n language?: 'json' | 'yaml',\n): Promise<string> => {\n const document = await workspaceStore.getEditableDocument(documentSlug)\n return stringifyDocument(document, language ?? selectedLanguage.value)\n}\n\nconst debouncedPersist = debounce({ delay: 1500 })\n\nconst applyProgrammaticEditorValue = (value: string): void => {\n // Cancel pending auto-save work so synthetic model updates do not persist stale data.\n debouncedPersist.cleanup()\n editorApi.value?.setValue(value, true)\n}\n\nconst loadDocumentIntoEditor = async () => {\n applyProgrammaticEditorValue(await getDocumentValue())\n isDirty.value = false\n await focusOperation()\n}\n\nconst formatDocument = async () => {\n await editorApi.value?.formatDocument()\n}\n\nconst focusOperation = async () => {\n const operationContext = getOperationContext(path, method)\n if (!operationContext) {\n return\n }\n\n await editorApi.value?.focusPath([\n 'paths',\n operationContext.path,\n operationContext.method,\n ])\n}\n\nconst persistEditorToWorkspace = async (value: string) => {\n const parsed = parseEditorObject(value, editorLanguage.value)\n if (!parsed) {\n const firstError = diagnostics.value.find(\n (m) => m.severity === monaco.MarkerSeverity.Error,\n )\n if (firstError) {\n focusDiagnostic(firstError)\n }\n await saveLoader.invalidate()\n return\n }\n\n saveLoader.start()\n await workspaceStore.replaceDocument(documentSlug, parsed)\n isDirty.value = false\n await saveLoader.validate({ duration: 900 })\n}\n\nconst saveNow = async () => {\n const value = getEditorValue()\n if (!value) {\n return\n }\n await persistEditorToWorkspace(value)\n}\n\nconst handleEditorChange = (value: string) => {\n isDirty.value = true\n\n if (!isAutoSaveEnabled.value) {\n return\n }\n\n debouncedPersist.execute(EDITOR_PERSIST_DEBOUNCE_KEY, () =>\n persistEditorToWorkspace(value),\n )\n}\n\nconst focusOperationServers = async () => {\n const operationContext = getOperationContext(path, method)\n if (!operationContext) {\n return\n }\n\n const value = getEditorValue()\n if (!value) {\n return\n }\n\n const parsed = parseEditorObject(value, editorLanguage.value)\n\n if (!parsed || !isObject(parsed.paths)) {\n return\n }\n\n const pathsObject = parsed.paths as Record<string, unknown>\n const operationPathItem = pathsObject[operationContext.path]\n if (!isObject(operationPathItem)) {\n return\n }\n\n const operation = operationPathItem[operationContext.method]\n if (!isObject(operation)) {\n return\n }\n\n // Add default servers if not present\n operation.servers ??= []\n\n // Update the editor value\n editorApi.value?.setValue(stringifyDocument(parsed, editorLanguage.value))\n await editorApi.value?.focusPath([\n 'paths',\n operationContext.path,\n operationContext.method,\n 'servers',\n ])\n}\n\nuseJsonPointerLinkSupport(editorApi, currentModel)\n\nonMounted(() => {\n editorApi.value = useEditor({\n element: monacoEditorRef.value ?? document.createElement('div'),\n onChange: handleEditorChange,\n model: currentModel,\n actions: [\n {\n id: 'scalar.editor.focusOperation',\n label: 'Focus Operation',\n keybindings: [monaco.KeyMod.Alt | monaco.KeyCode.KeyO],\n run: async () => {\n await focusOperation()\n },\n },\n {\n id: 'scalar.editor.focusOperationServers',\n label: 'Focus Operation Servers',\n keybindings: [monaco.KeyMod.Alt | monaco.KeyCode.KeyS],\n run: async () => {\n await focusOperationServers()\n },\n },\n {\n id: 'scalar.editor.formatDocument',\n label: 'Format Document',\n keybindings: [\n monaco.KeyMod.Alt | monaco.KeyMod.Shift | monaco.KeyCode.KeyF,\n ],\n run: async () => {\n await formatDocument()\n },\n },\n ],\n })\n\n syncEditorBottomPadding()\n void loadDocumentIntoEditor()\n})\n\nonBeforeUnmount(() => {\n debouncedPersist.cleanup()\n\n // Persist if there is a pending save\n if (isDirty.value && isAutoSaveEnabled.value) {\n void saveNow()\n }\n editorApi.value?.dispose?.()\n // Dispose models created at setup; useEditor only disposes the editor widget, not external models.\n jsonModel.model.dispose()\n yamlModel.model.dispose()\n})\n\nwatch(() => documentSlug, loadDocumentIntoEditor)\n\nwatch(\n () => [path, method] as const,\n async () => {\n await focusOperation()\n },\n)\n\nwatch(isDiagnosticsPaneExpanded, () => {\n syncEditorBottomPadding()\n})\n\nwatch(editorLanguage, async (nextLanguage, previousLanguage) => {\n const wasDirty = isDirty.value\n // Read from the previous model before switching; getEditorValue() would use currentModel\n // which changes with selectedLanguage, so we would read the (empty) new model otherwise.\n const value = getEditorValueForLanguage(previousLanguage ?? 'json')\n if (!value) {\n selectedLanguage.value = nextLanguage\n await nextTick()\n await focusOperation()\n return\n }\n\n const parsed = parseEditorObject(value, previousLanguage ?? 'json')\n selectedLanguage.value = nextLanguage\n await nextTick()\n if (parsed) {\n applyProgrammaticEditorValue(stringifyDocument(parsed, nextLanguage))\n isDirty.value = wasDirty\n }\n await focusOperation()\n})\n\nwatch(\n isAutoSaveEnabled,\n (isEnabled) => {\n if (!isEnabled) {\n debouncedPersist.cleanup()\n return\n }\n\n if (isDirty.value) {\n const value = getEditorValue()\n if (!value) {\n return\n }\n debouncedPersist.execute(EDITOR_PERSIST_DEBOUNCE_KEY, () =>\n persistEditorToWorkspace(value),\n )\n }\n },\n { flush: 'post' },\n)\n</script>\n\n<template>\n <div\n v-if=\"\n collectionType === 'operation' &&\n getOperationContext(path, method) !== null\n \"\n class=\"flex w-full min-w-0 flex-1 flex-col gap-2\"\n :class=\"editorRootClass\">\n <div\n class=\"grid grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] items-center gap-3\">\n <div\n class=\"flex min-w-0 items-center gap-1 overflow-x-auto whitespace-nowrap\">\n <span class=\"text-c-2 text-xs font-medium whitespace-nowrap\">\n Shortcuts\n </span>\n\n <ScalarButton\n class=\"whitespace-nowrap\"\n size=\"xs\"\n variant=\"ghost\"\n @click=\"focusOperation\">\n <span>Operation</span>\n <span class=\"text-c-3 ml-2 text-[11px]\">\n <ScalarHotkey\n hotkey=\"O\"\n :modifier=\"['Alt']\" />\n </span>\n </ScalarButton>\n\n <ScalarButton\n class=\"whitespace-nowrap\"\n size=\"xs\"\n variant=\"ghost\"\n @click=\"focusOperationServers\">\n <span>Servers</span>\n <span class=\"text-c-3 ml-2 text-[11px]\">\n <ScalarHotkey\n hotkey=\"S\"\n :modifier=\"['Alt']\" />\n </span>\n </ScalarButton>\n </div>\n\n <div\n aria-label=\"Editor language\"\n class=\"bg-b-1 shadow-border flex items-center justify-self-center overflow-hidden rounded-lg p-0.5\"\n role=\"tablist\">\n <ScalarButton\n :aria-selected=\"!isYamlMode\"\n :class=\"getLanguageToggleClass(!isYamlMode)\"\n role=\"tab\"\n size=\"xs\"\n type=\"button\"\n variant=\"ghost\"\n @click=\"editorLanguage = 'json'\">\n JSON\n </ScalarButton>\n <ScalarButton\n :aria-selected=\"isYamlMode\"\n :class=\"getLanguageToggleClass(isYamlMode)\"\n role=\"tab\"\n size=\"xs\"\n type=\"button\"\n variant=\"ghost\"\n @click=\"editorLanguage = 'yaml'\">\n YAML\n </ScalarButton>\n </div>\n\n <div class=\"flex min-w-0 shrink-0 items-center gap-2 justify-self-end\">\n <ScalarButton\n size=\"xs\"\n variant=\"ghost\"\n @click=\"formatDocument\">\n <span>Format {{ isYamlMode ? 'YAML' : 'JSON' }}</span>\n <span class=\"text-c-3 ml-2 text-[11px]\">\n <ScalarHotkey\n hotkey=\"F\"\n :modifier=\"['Alt', 'Shift']\" />\n </span>\n </ScalarButton>\n <ScalarButton\n :aria-label=\"\n isEditorMaximized ? 'Restore editor size' : 'Maximize editor'\n \"\n size=\"xs\"\n variant=\"ghost\"\n @click=\"toggleEditorMaximized\">\n <span>{{ isEditorMaximized ? 'Restore' : 'Maximize' }}</span>\n <span class=\"text-c-3 ml-2 text-[11px]\">\n <ScalarIconArrowsIn\n v-if=\"isEditorMaximized\"\n class=\"size-3.5\" />\n <ScalarIconArrowsOut\n v-else\n class=\"size-3.5\" />\n </span>\n </ScalarButton>\n </div>\n </div>\n\n <div class=\"flex min-h-0 w-full min-w-0 flex-1 rounded-lg border\">\n <div\n class=\"relative w-full min-w-0 flex-1\"\n :class=\"isEditorMaximized ? 'h-full min-h-0' : 'h-[500px]'\">\n <div class=\"pointer-events-none absolute top-2 right-2 z-10\">\n <EditorSavePanel\n :isAutoSaveEnabled=\"isAutoSaveEnabled\"\n :isDirty=\"isDirty\"\n :saveLoader=\"saveLoader\"\n @saveNow=\"saveNow\"\n @update:isAutoSaveEnabled=\"isAutoSaveEnabled = $event\" />\n </div>\n\n <EditorDiagnosticsPanel\n :diagnosticCounts=\"diagnosticCounts\"\n :expanded=\"isDiagnosticsPaneExpanded\"\n :visibleDiagnostics=\"visibleDiagnostics\"\n @focusDiagnostic=\"focusDiagnostic\"\n @toggle=\"isDiagnosticsPaneExpanded = !isDiagnosticsPaneExpanded\" />\n\n <div\n ref=\"monacoEditorRef\"\n class=\"h-full w-full min-w-0 flex-1\" />\n </div>\n </div>\n </div>\n <div v-else>No operation context found</div>\n</template>\n<style scoped>\n.editor-container {\n width: 100%;\n height: 100%;\n}\n\n:deep(.json-path-highlight) {\n background-color: rgba(255, 200, 0, 0.35);\n border-radius: 4px;\n}\n\n:deep(.json-focus-highlight) {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-accent, #24b47e) 18%,\n transparent\n );\n border-radius: 4px;\n}\n</style>\n"],"mappings":"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"}
1
+ {"version":3,"file":"Editor.vue.script.js","names":[],"sources":["../../../../../../src/v2/features/collection/components/Editor/Editor.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton, ScalarHotkey, useLoadingState } from '@scalar/components'\nimport { debounce } from '@scalar/helpers/general/debounce'\nimport { isObject } from '@scalar/helpers/object/is-object'\nimport { ScalarIconArrowsIn, ScalarIconArrowsOut } from '@scalar/icons'\nimport * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js'\nimport {\n computed,\n nextTick,\n onBeforeUnmount,\n onMounted,\n ref,\n shallowRef,\n watch,\n} from 'vue'\n\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport { useEditor, useJsonPointerLinkSupport } from '@/v2/features/editor'\nimport { createJsonModel } from '@/v2/features/editor/helpers/json/create-json-model'\nimport { createYamlModel } from '@/v2/features/editor/helpers/yaml/create-yaml-model'\nimport { useEditorMarkers } from '@/v2/features/editor/hooks/use-editor-markers'\n\nimport EditorDiagnosticsPanel from './components/EditorDiagnosticsPanel.vue'\nimport EditorSavePanel from './components/EditorSavePanel.vue'\nimport { getDiagnosticCounts } from './helpers/get-diagnostic-counts'\nimport { getOperationContext } from './helpers/get-operation-context'\nimport { getVisibleDiagnostics } from './helpers/get-visible-diagnostics'\nimport { parseEditorObject } from './helpers/parse-editor-object'\nimport { stringifyDocument } from './helpers/stringify-document'\nimport { useEditorState } from './hooks/use-editor-state'\n\nconst { collectionType, documentSlug, method, path, workspaceStore } =\n defineProps<CollectionProps>()\n\nconst MAX_VISIBLE_DIAGNOSTICS = 6\nconst EDITOR_PERSIST_DEBOUNCE_KEY = 'editor:replace-document'\n\nconst monacoEditorRef = ref<HTMLElement>()\nconst editorApi = shallowRef<ReturnType<typeof useEditor>>()\n\nconst saveLoader = useLoadingState()\nconst {\n isAutoSaveEnabled,\n isDirty,\n editorLanguage,\n isDiagnosticsPaneExpanded,\n isEditorMaximized,\n isYamlMode,\n editorBottomPadding,\n editorRootClass,\n getLanguageToggleClass,\n toggleEditorMaximized,\n} = useEditorState()\n\nconst jsonModel = createJsonModel()\nconst yamlModel = createYamlModel()\n\nconst selectedLanguage = ref<'json' | 'yaml'>('json')\n\nconst currentModel = computed(() => {\n return selectedLanguage.value === 'json' ? jsonModel : yamlModel\n})\n\nconst monacoEditorInstance = computed(() => editorApi.value?.editor)\nconst { markers: diagnostics } = useEditorMarkers(monacoEditorInstance)\n\nconst syncEditorBottomPadding = () => {\n editorApi.value?.editor.updateOptions({\n padding: {\n top: 0,\n bottom: editorBottomPadding.value,\n },\n })\n}\n\nconst diagnosticCounts = computed(() => getDiagnosticCounts(diagnostics.value))\nconst visibleDiagnostics = computed(() =>\n getVisibleDiagnostics(diagnostics.value, MAX_VISIBLE_DIAGNOSTICS),\n)\n\nconst focusDiagnostic = (marker: monaco.editor.IMarker) => {\n const editor = editorApi.value?.editor\n if (!editor) {\n return\n }\n editor.setSelection({\n startLineNumber: marker.startLineNumber,\n startColumn: marker.startColumn,\n endLineNumber: marker.endLineNumber,\n endColumn: marker.endColumn,\n })\n editor.revealPositionInCenter({\n lineNumber: marker.startLineNumber,\n column: marker.startColumn,\n })\n}\n\nconst getEditorValue = (): string | null => currentModel.value.model.getValue()\n\n/** Value from the editor for a specific language (use when switching to avoid reading the wrong model). */\nconst getEditorValueForLanguage = (language: 'json' | 'yaml'): string | null =>\n (language === 'json' ? jsonModel : yamlModel).model.getValue()\n\nconst getDocumentValue = async (\n language?: 'json' | 'yaml',\n): Promise<string> => {\n const document = await workspaceStore.getEditableDocument(documentSlug)\n return stringifyDocument(document, language ?? selectedLanguage.value)\n}\n\nconst debouncedPersist = debounce({ delay: 1500 })\n\nconst applyProgrammaticEditorValue = (value: string): void => {\n // Cancel pending auto-save work so synthetic model updates do not persist stale data.\n debouncedPersist.cleanup()\n editorApi.value?.setValue(value, true)\n}\n\nconst loadDocumentIntoEditor = async () => {\n applyProgrammaticEditorValue(await getDocumentValue())\n isDirty.value = false\n await focusOperation()\n}\n\nconst formatDocument = async () => {\n await editorApi.value?.formatDocument()\n}\n\nconst focusOperation = async () => {\n const operationContext = getOperationContext(path, method)\n if (!operationContext) {\n return\n }\n\n await editorApi.value?.focusPath([\n 'paths',\n operationContext.path,\n operationContext.method,\n ])\n}\n\nconst persistEditorToWorkspace = async (value: string) => {\n const parsed = parseEditorObject(value, editorLanguage.value)\n if (!parsed) {\n const firstError = diagnostics.value.find(\n (m) => m.severity === monaco.MarkerSeverity.Error,\n )\n if (firstError) {\n focusDiagnostic(firstError)\n }\n await saveLoader.invalidate()\n return\n }\n\n saveLoader.start()\n await workspaceStore.replaceDocument(documentSlug, parsed)\n isDirty.value = false\n await saveLoader.validate({ duration: 900 })\n}\n\nconst saveNow = async () => {\n const value = getEditorValue()\n if (!value) {\n return\n }\n await persistEditorToWorkspace(value)\n}\n\nconst handleEditorChange = (value: string) => {\n isDirty.value = true\n\n if (!isAutoSaveEnabled.value) {\n return\n }\n\n debouncedPersist.execute(EDITOR_PERSIST_DEBOUNCE_KEY, () =>\n persistEditorToWorkspace(value),\n )\n}\n\nconst focusOperationServers = async () => {\n const operationContext = getOperationContext(path, method)\n if (!operationContext) {\n return\n }\n\n const value = getEditorValue()\n if (!value) {\n return\n }\n\n const parsed = parseEditorObject(value, editorLanguage.value)\n\n if (!parsed || !isObject(parsed.paths)) {\n return\n }\n\n const pathsObject = parsed.paths as Record<string, unknown>\n const operationPathItem = pathsObject[operationContext.path]\n if (!isObject(operationPathItem)) {\n return\n }\n\n const operation = operationPathItem[operationContext.method]\n if (!isObject(operation)) {\n return\n }\n\n // Add default servers if not present\n operation.servers ??= []\n\n // Update the editor value\n editorApi.value?.setValue(stringifyDocument(parsed, editorLanguage.value))\n await editorApi.value?.focusPath([\n 'paths',\n operationContext.path,\n operationContext.method,\n 'servers',\n ])\n}\n\nuseJsonPointerLinkSupport(editorApi, currentModel)\n\nonMounted(() => {\n editorApi.value = useEditor({\n element: monacoEditorRef.value ?? document.createElement('div'),\n onChange: handleEditorChange,\n model: currentModel,\n actions: [\n {\n id: 'scalar.editor.focusOperation',\n label: 'Focus Operation',\n keybindings: [monaco.KeyMod.Alt | monaco.KeyCode.KeyO],\n run: async () => {\n await focusOperation()\n },\n },\n {\n id: 'scalar.editor.focusOperationServers',\n label: 'Focus Operation Servers',\n keybindings: [monaco.KeyMod.Alt | monaco.KeyCode.KeyS],\n run: async () => {\n await focusOperationServers()\n },\n },\n {\n id: 'scalar.editor.formatDocument',\n label: 'Format Document',\n keybindings: [\n monaco.KeyMod.Alt | monaco.KeyMod.Shift | monaco.KeyCode.KeyF,\n ],\n run: async () => {\n await formatDocument()\n },\n },\n ],\n })\n\n syncEditorBottomPadding()\n void loadDocumentIntoEditor()\n})\n\nonBeforeUnmount(() => {\n debouncedPersist.cleanup()\n\n // Persist if there is a pending save\n if (isDirty.value && isAutoSaveEnabled.value) {\n void saveNow()\n }\n editorApi.value?.dispose?.()\n // Dispose models created at setup; useEditor only disposes the editor widget, not external models.\n jsonModel.model.dispose()\n yamlModel.model.dispose()\n})\n\nwatch(() => documentSlug, loadDocumentIntoEditor)\n\nwatch(\n () => [path, method] as const,\n async () => {\n await focusOperation()\n },\n)\n\nwatch(isDiagnosticsPaneExpanded, () => {\n syncEditorBottomPadding()\n})\n\nwatch(editorLanguage, async (nextLanguage, previousLanguage) => {\n const wasDirty = isDirty.value\n // Read from the previous model before switching; getEditorValue() would use currentModel\n // which changes with selectedLanguage, so we would read the (empty) new model otherwise.\n const value = getEditorValueForLanguage(previousLanguage ?? 'json')\n if (!value) {\n selectedLanguage.value = nextLanguage\n await nextTick()\n await focusOperation()\n return\n }\n\n const parsed = parseEditorObject(value, previousLanguage ?? 'json')\n selectedLanguage.value = nextLanguage\n await nextTick()\n if (parsed) {\n applyProgrammaticEditorValue(stringifyDocument(parsed, nextLanguage))\n isDirty.value = wasDirty\n }\n await focusOperation()\n})\n\nwatch(\n isAutoSaveEnabled,\n (isEnabled) => {\n if (!isEnabled) {\n debouncedPersist.cleanup()\n return\n }\n\n if (isDirty.value) {\n const value = getEditorValue()\n if (!value) {\n return\n }\n debouncedPersist.execute(EDITOR_PERSIST_DEBOUNCE_KEY, () =>\n persistEditorToWorkspace(value),\n )\n }\n },\n { flush: 'post' },\n)\n</script>\n\n<template>\n <div\n v-if=\"\n collectionType === 'operation' &&\n getOperationContext(path, method) !== null\n \"\n class=\"flex w-full min-w-0 flex-1 flex-col gap-2\"\n :class=\"editorRootClass\">\n <div\n class=\"grid grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] items-center gap-3\">\n <div\n class=\"flex min-w-0 items-center gap-1 overflow-x-auto whitespace-nowrap\">\n <span class=\"text-c-2 text-xs font-medium whitespace-nowrap\">\n Shortcuts\n </span>\n\n <ScalarButton\n class=\"whitespace-nowrap\"\n size=\"xs\"\n variant=\"ghost\"\n @click=\"focusOperation\">\n <span>Operation</span>\n <span class=\"text-c-3 ml-2 text-[11px]\">\n <ScalarHotkey\n hotkey=\"O\"\n :modifier=\"['Alt']\" />\n </span>\n </ScalarButton>\n\n <ScalarButton\n class=\"whitespace-nowrap\"\n size=\"xs\"\n variant=\"ghost\"\n @click=\"focusOperationServers\">\n <span>Servers</span>\n <span class=\"text-c-3 ml-2 text-[11px]\">\n <ScalarHotkey\n hotkey=\"S\"\n :modifier=\"['Alt']\" />\n </span>\n </ScalarButton>\n </div>\n\n <div\n aria-label=\"Editor language\"\n class=\"bg-b-1 shadow-border flex items-center justify-self-center overflow-hidden rounded-lg p-0.5\"\n role=\"tablist\">\n <ScalarButton\n :aria-selected=\"!isYamlMode\"\n :class=\"getLanguageToggleClass(!isYamlMode)\"\n role=\"tab\"\n size=\"xs\"\n type=\"button\"\n variant=\"ghost\"\n @click=\"editorLanguage = 'json'\">\n JSON\n </ScalarButton>\n <ScalarButton\n :aria-selected=\"isYamlMode\"\n :class=\"getLanguageToggleClass(isYamlMode)\"\n role=\"tab\"\n size=\"xs\"\n type=\"button\"\n variant=\"ghost\"\n @click=\"editorLanguage = 'yaml'\">\n YAML\n </ScalarButton>\n </div>\n\n <div class=\"flex min-w-0 shrink-0 items-center gap-2 justify-self-end\">\n <ScalarButton\n size=\"xs\"\n variant=\"ghost\"\n @click=\"formatDocument\">\n <span>Format {{ isYamlMode ? 'YAML' : 'JSON' }}</span>\n <span class=\"text-c-3 ml-2 text-[11px]\">\n <ScalarHotkey\n hotkey=\"F\"\n :modifier=\"['Alt', 'Shift']\" />\n </span>\n </ScalarButton>\n <ScalarButton\n :aria-label=\"\n isEditorMaximized ? 'Restore editor size' : 'Maximize editor'\n \"\n size=\"xs\"\n variant=\"ghost\"\n @click=\"toggleEditorMaximized\">\n <span>{{ isEditorMaximized ? 'Restore' : 'Maximize' }}</span>\n <span class=\"text-c-3 ml-2 text-[11px]\">\n <ScalarIconArrowsIn\n v-if=\"isEditorMaximized\"\n class=\"size-3.5\" />\n <ScalarIconArrowsOut\n v-else\n class=\"size-3.5\" />\n </span>\n </ScalarButton>\n </div>\n </div>\n\n <div class=\"flex min-h-0 w-full min-w-0 flex-1 rounded-lg border\">\n <div\n class=\"relative w-full min-w-0 flex-1\"\n :class=\"isEditorMaximized ? 'h-full min-h-0' : 'h-125'\">\n <div class=\"pointer-events-none absolute top-2 right-2 z-10\">\n <EditorSavePanel\n :isAutoSaveEnabled=\"isAutoSaveEnabled\"\n :isDirty=\"isDirty\"\n :saveLoader=\"saveLoader\"\n @saveNow=\"saveNow\"\n @update:isAutoSaveEnabled=\"isAutoSaveEnabled = $event\" />\n </div>\n\n <EditorDiagnosticsPanel\n :diagnosticCounts=\"diagnosticCounts\"\n :expanded=\"isDiagnosticsPaneExpanded\"\n :visibleDiagnostics=\"visibleDiagnostics\"\n @focusDiagnostic=\"focusDiagnostic\"\n @toggle=\"isDiagnosticsPaneExpanded = !isDiagnosticsPaneExpanded\" />\n\n <div\n ref=\"monacoEditorRef\"\n class=\"h-full w-full min-w-0 flex-1 [&_.monaco-editor]:rounded-lg [&_.overflow-guard]:rounded-lg\" />\n </div>\n </div>\n </div>\n <div v-else>No operation context found</div>\n</template>\n<style scoped>\n.editor-container {\n width: 100%;\n height: 100%;\n}\n\n:deep(.json-path-highlight) {\n background-color: rgba(255, 200, 0, 0.35);\n border-radius: 4px;\n}\n\n:deep(.json-focus-highlight) {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-accent, #24b47e) 18%,\n transparent\n );\n border-radius: 4px;\n}\n</style>\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"apply-scalar-theme.js","names":[],"sources":["../../../../../../src/v2/features/editor/helpers/theme/apply-scalar-theme.ts"],"sourcesContent":["import * as monaco from 'monaco-editor'\n\nimport { loadCssVariables } from './load-css-variables'\n\nconst THEME_NAME = 'scalar-theme'\n\n/**\n * Applies a custom Scalar theme to the Monaco editor.\n *\n * This function loads CSS variables for either dark or light mode, maps the colors to Monaco's editor theme keys,\n * and then applies the new theme. Theme color tokens are resolved from CSS custom properties.\n *\n * Example usage:\n *\n * await applyScalarTheme('scalar', true); // Apply dark mode\n * await applyScalarTheme('scalar', false); // Apply light mode\n *\n * @param theme - The theme string key to load variables for (e.g. 'scalar').\n * @param isDarkMode - Whether to use dark or light variables.\n */\nexport const applyScalarTheme = async (theme: string, isDarkMode: boolean) => {\n // Load all CSS variables for the given theme\n const allVars = await loadCssVariables(theme)\n\n // Pick variables for dark or light mode\n const vars = isDarkMode ? allVars.dark : allVars.light\n\n /**\n * Map Monaco editor theme keys to CSS variable names.\n */\n const varsMap = {\n 'editor.background': '--scalar-background-1',\n 'editor.foreground': '--scalar-color-1',\n 'editorLineNumber.foreground': '--scalar-color-3',\n 'editorLineNumber.activeForeground': '--scalar-color-1',\n 'editorLineHighlight.background': '--scalar-background-2',\n 'editorCursor.foreground': '--scalar-color-1',\n 'editorCursor.background': '--scalar-background-1',\n 'editor.selectionBackground': '--scalar-background-3',\n 'editor.inactiveSelectionBackground': '--scalar-background-3',\n 'editorIndentGuide.background': '--scalar-background-3',\n 'editorIndentGuide.activeBackground': '--scalar-background-2',\n 'editorWhitespace.foreground': '--scalar-border-color',\n 'editorBracketMatch.background': '--scalar-background-3',\n 'editorBracketMatch.border': '--scalar-color-accent',\n 'editor.selectionHighlightBackground': '--scalar-background-3',\n 'editor.hoverHighlightBackground': '--scalar-background-3',\n 'editorLink.activeForeground': '--scalar-color-3',\n 'editorOverviewRuler.border': '--scalar-border-color',\n }\n\n /**\n * Build a colors object for Monaco from the variable map.\n * Only assign if the variable exists in the loaded vars.\n */\n const colors = Object.fromEntries(\n Object.entries(varsMap)\n .filter(([_, cssVar]) => !!vars[cssVar])\n .map(([prop, cssVar]) => [prop, vars[cssVar]]),\n )\n\n // Define the theme in Monaco using the chosen variables.\n monaco.editor.defineTheme(THEME_NAME, {\n base: isDarkMode ? 'vs-dark' : 'vs',\n inherit: true,\n rules: [\n // Default text\n { token: '', foreground: vars['--scalar-color-3'] },\n // Comments\n {\n token: 'comment',\n foreground: vars['--scalar-color-2'],\n fontStyle: 'italic',\n },\n // Keywords\n {\n token: 'keyword',\n foreground: vars['--scalar-color-accent'],\n fontStyle: 'bold',\n },\n // Numbers\n { token: 'number', foreground: vars['--scalar-color-purple'] },\n // Strings\n { token: 'string', foreground: vars['--scalar-color-2'] },\n // Delimiters (punctuation)\n { token: 'delimiter', foreground: vars['--scalar-color-3'] },\n ],\n colors,\n })\n\n // Finally, set the theme\n monaco.editor.setTheme(THEME_NAME)\n}\n"],"mappings":";;;AAIA,IAAM,aAAa;;;;;;;;;;;;;;;AAgBnB,IAAa,mBAAmB,OAAO,OAAe,eAAwB;CAE5E,MAAM,UAAU,MAAM,iBAAiB,MAAM;CAG7C,MAAM,OAAO,aAAa,QAAQ,OAAO,QAAQ;;;;;CA8BjD,MAAM,SAAS,OAAO,YACpB,OAAO,QA1BO;EACd,qBAAqB;EACrB,qBAAqB;EACrB,+BAA+B;EAC/B,qCAAqC;EACrC,kCAAkC;EAClC,2BAA2B;EAC3B,2BAA2B;EAC3B,8BAA8B;EAC9B,sCAAsC;EACtC,gCAAgC;EAChC,sCAAsC;EACtC,+BAA+B;EAC/B,iCAAiC;EACjC,6BAA6B;EAC7B,uCAAuC;EACvC,mCAAmC;EACnC,+BAA+B;EAC/B,8BAA8B;EAC/B,CAOwB,CACpB,QAAQ,CAAC,GAAG,YAAY,CAAC,CAAC,KAAK,QAAQ,CACvC,KAAK,CAAC,MAAM,YAAY,CAAC,MAAM,KAAK,QAAQ,CAAC,CACjD;AAGD,QAAO,OAAO,YAAY,YAAY;EACpC,MAAM,aAAa,YAAY;EAC/B,SAAS;EACT,OAAO;GAEL;IAAE,OAAO;IAAI,YAAY,KAAK;IAAqB;GAEnD;IACE,OAAO;IACP,YAAY,KAAK;IACjB,WAAW;IACZ;GAED;IACE,OAAO;IACP,YAAY,KAAK;IACjB,WAAW;IACZ;GAED;IAAE,OAAO;IAAU,YAAY,KAAK;IAA0B;GAE9D;IAAE,OAAO;IAAU,YAAY,KAAK;IAAqB;GAEzD;IAAE,OAAO;IAAa,YAAY,KAAK;IAAqB;GAC7D;EACD;EACD,CAAC;AAGF,QAAO,OAAO,SAAS,WAAW"}
1
+ {"version":3,"file":"apply-scalar-theme.js","names":[],"sources":["../../../../../../src/v2/features/editor/helpers/theme/apply-scalar-theme.ts"],"sourcesContent":["import * as monaco from 'monaco-editor'\n\nimport { loadCssVariables } from './load-css-variables'\n\nconst THEME_NAME = 'scalar-theme'\n\n/**\n * Applies a custom Scalar theme to the Monaco editor.\n *\n * This function loads CSS variables for either dark or light mode, maps the colors to Monaco's editor theme keys,\n * and then applies the new theme. Theme color tokens are resolved from CSS custom properties.\n *\n * Example usage:\n *\n * await applyScalarTheme('scalar', true); // Apply dark mode\n * await applyScalarTheme('scalar', false); // Apply light mode\n *\n * @param theme - The theme string key to load variables for (e.g. 'scalar').\n * @param isDarkMode - Whether to use dark or light variables.\n */\nexport const applyScalarTheme = async (theme: string, isDarkMode: boolean) => {\n // Load all CSS variables for the given theme\n const allVars = await loadCssVariables(theme)\n\n // Pick variables for dark or light mode\n const vars = isDarkMode ? allVars.dark : allVars.light\n\n /**\n * Map Monaco editor theme keys to CSS variable names.\n */\n const varsMap = {\n 'editor.background': '--scalar-background-1',\n 'editor.foreground': '--scalar-color-1',\n 'editorLineNumber.foreground': '--scalar-color-3',\n 'editorLineNumber.activeForeground': '--scalar-color-1',\n 'editorLineHighlight.background': '--scalar-background-2',\n 'editorCursor.foreground': '--scalar-color-1',\n 'editorCursor.background': '--scalar-background-1',\n 'editor.selectionBackground': '--scalar-background-3',\n 'editor.inactiveSelectionBackground': '--scalar-background-3',\n 'editorIndentGuide.background': '--scalar-background-3',\n 'editorIndentGuide.activeBackground': '--scalar-background-2',\n 'editorWhitespace.foreground': '--scalar-border-color',\n 'editorBracketMatch.background': '--scalar-background-3',\n 'editorBracketMatch.border': '--scalar-color-accent',\n 'editor.selectionHighlightBackground': '--scalar-background-3',\n 'editor.hoverHighlightBackground': '--scalar-background-3',\n 'editorLink.activeForeground': '--scalar-color-3',\n 'editorOverviewRuler.border': '--scalar-border-color',\n }\n\n /**\n * Build a colors object for Monaco from the variable map.\n * Only assign if the variable exists in the loaded vars.\n */\n const colors = Object.fromEntries(\n Object.entries(varsMap)\n .filter(([_, cssVar]) => !!vars[cssVar])\n .map(([prop, cssVar]) => [prop, vars[cssVar] as string]),\n )\n\n // Define the theme in Monaco using the chosen variables.\n monaco.editor.defineTheme(THEME_NAME, {\n base: isDarkMode ? 'vs-dark' : 'vs',\n inherit: true,\n rules: [\n // Default text\n { token: '', foreground: vars['--scalar-color-3'] },\n // Comments\n {\n token: 'comment',\n foreground: vars['--scalar-color-2'],\n fontStyle: 'italic',\n },\n // Keywords\n {\n token: 'keyword',\n foreground: vars['--scalar-color-accent'],\n fontStyle: 'bold',\n },\n // Numbers\n { token: 'number', foreground: vars['--scalar-color-purple'] },\n // Strings\n { token: 'string', foreground: vars['--scalar-color-2'] },\n // Delimiters (punctuation)\n { token: 'delimiter', foreground: vars['--scalar-color-3'] },\n ],\n colors,\n })\n\n // Finally, set the theme\n monaco.editor.setTheme(THEME_NAME)\n}\n"],"mappings":";;;AAIA,IAAM,aAAa;;;;;;;;;;;;;;;AAgBnB,IAAa,mBAAmB,OAAO,OAAe,eAAwB;CAE5E,MAAM,UAAU,MAAM,iBAAiB,MAAM;CAG7C,MAAM,OAAO,aAAa,QAAQ,OAAO,QAAQ;;;;;CA8BjD,MAAM,SAAS,OAAO,YACpB,OAAO,QA1BO;EACd,qBAAqB;EACrB,qBAAqB;EACrB,+BAA+B;EAC/B,qCAAqC;EACrC,kCAAkC;EAClC,2BAA2B;EAC3B,2BAA2B;EAC3B,8BAA8B;EAC9B,sCAAsC;EACtC,gCAAgC;EAChC,sCAAsC;EACtC,+BAA+B;EAC/B,iCAAiC;EACjC,6BAA6B;EAC7B,uCAAuC;EACvC,mCAAmC;EACnC,+BAA+B;EAC/B,8BAA8B;EAC/B,CAOwB,CACpB,QAAQ,CAAC,GAAG,YAAY,CAAC,CAAC,KAAK,QAAQ,CACvC,KAAK,CAAC,MAAM,YAAY,CAAC,MAAM,KAAK,QAAkB,CAAC,CAC3D;AAGD,QAAO,OAAO,YAAY,YAAY;EACpC,MAAM,aAAa,YAAY;EAC/B,SAAS;EACT,OAAO;GAEL;IAAE,OAAO;IAAI,YAAY,KAAK;IAAqB;GAEnD;IACE,OAAO;IACP,YAAY,KAAK;IACjB,WAAW;IACZ;GAED;IACE,OAAO;IACP,YAAY,KAAK;IACjB,WAAW;IACZ;GAED;IAAE,OAAO;IAAU,YAAY,KAAK;IAA0B;GAE9D;IAAE,OAAO;IAAU,YAAY,KAAK;IAAqB;GAEzD;IAAE,OAAO;IAAa,YAAY,KAAK;IAAqB;GAC7D;EACD;EACD,CAAC;AAGF,QAAO,OAAO,SAAS,WAAW"}
@@ -1,14 +1,36 @@
1
+ /**
2
+ * Maps a comma-separated selector list to the theme modes it applies to.
3
+ * Only **exact** `.light-mode` or `.dark-mode` selectors match (no compound selectors like `.light-mode .foo`).
4
+ */
5
+ export declare const getColorModesFromSelectors: (text: string) => ("dark" | "light")[];
6
+ /**
7
+ * Parses a single custom property value from the stylesheet into a normalized form:
8
+ * - `#RRGGBB` / `#RRGGBBAA` (uppercase)
9
+ * - `#RGB` short hex expanded to six digits
10
+ * - `rgb()` / `rgba()` with comma-separated channels (lower input only)
11
+ * - `var(--x)` / `var(--x, fallback)` returned as-is for a later resolve pass
12
+ */
13
+ export declare const parseVariableValue: (value: string) => string | undefined;
14
+ /**
15
+ * Recursively resolves a value if it is (or becomes) `var(--name)` against `variables`.
16
+ * Missing names or non-var values are returned unchanged.
17
+ */
18
+ export declare const resolveVariableValue: (value: string, variables: Record<string, string>) => string;
19
+ /**
20
+ * Resolves `var(--*)` values in a flat map of custom properties in one pass.
21
+ * Values that are not var references are copied through.
22
+ */
23
+ export declare const resolveVariables: (variables: Record<string, string>) => Record<string, string>;
1
24
  /**
2
25
  * Extracts CSS custom properties (variables) from a given CSS string
3
26
  * for .light-mode and .dark-mode selectors and returns an object
4
27
  * with 'light' and 'dark' keys containing the filtered variables.
5
- * Only variables matching hex color values (#RRGGBB or #RRGGBBAA) are accepted.
6
28
  *
7
29
  * @param css - The CSS string to parse.
8
30
  * @returns An object with `light` and `dark` properties containing the extracted CSS variables.
9
31
  */
10
32
  export declare const loadCssVariables: (css: string) => Promise<{
11
- light: any;
12
- dark: any;
33
+ light: Record<string, string>;
34
+ dark: Record<string, string>;
13
35
  }>;
14
36
  //# sourceMappingURL=load-css-variables.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"load-css-variables.d.ts","sourceRoot":"","sources":["../../../../../../src/v2/features/editor/helpers/theme/load-css-variables.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,GAAU,KAAK,MAAM;WAIU,GAAG;UAAQ,GAAG;EA2CzE,CAAA"}
1
+ {"version":3,"file":"load-css-variables.d.ts","sourceRoot":"","sources":["../../../../../../src/v2/features/editor/helpers/theme/load-css-variables.ts"],"names":[],"mappings":"AAoBA;;;GAGG;AACH,eAAO,MAAM,0BAA0B,GAAI,MAAM,MAAM,yBActD,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,uBAmC/C,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,oBAAoB,GAAI,OAAO,MAAM,EAAE,WAAW,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAG,MAcvF,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAAI,WAAW,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAWzF,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,GAAU,KAAK,MAAM;;;EAsCjD,CAAA"}
@@ -1,10 +1,84 @@
1
1
  import { z } from "zod";
2
2
  //#region src/v2/features/editor/helpers/theme/load-css-variables.ts
3
3
  /**
4
+ * Patterns for CSS color values we can normalize to hex (or pass through as var()).
5
+ * Space-separated rgb() and modern slash syntax are not supported here.
6
+ */
7
+ var hexShortRegex = /^#([0-9a-fA-F]){3}$/;
8
+ var hexRegex = /^#([0-9a-fA-F]{6})$/;
9
+ var hexAlphaRegex = /^#([0-9a-fA-F]{8})$/;
10
+ var rgbRegex = /^rgb\(\s*(\d{1,3})\s*,?\s*(\d{1,3})\s*,?\s*(\d{1,3})\s*\)$/;
11
+ var rgbaRegex = /^rgba\(\s*(\d{1,3})\s*,?\s*(\d{1,3})\s*,?\s*(\d{1,3})\s*,?\s*(\d*\.?\d+)\s*\)$/;
12
+ /** Optional fallback: var(--name, fallback) */
13
+ var varRegex = /^var\(\s*(--[^)]+)\s*(?:,\s*([^)]*))?\s*\)$/i;
14
+ /**
15
+ * Maps a comma-separated selector list to the theme modes it applies to.
16
+ * Only **exact** `.light-mode` or `.dark-mode` selectors match (no compound selectors like `.light-mode .foo`).
17
+ */
18
+ var getColorModesFromSelectors = (text) => {
19
+ return text.split(",").map((selector) => selector.trim()).map((selector) => {
20
+ if (selector === ".light-mode") return "light";
21
+ if (selector === ".dark-mode") return "dark";
22
+ return null;
23
+ }).filter((mode) => mode !== null);
24
+ };
25
+ /**
26
+ * Parses a single custom property value from the stylesheet into a normalized form:
27
+ * - `#RRGGBB` / `#RRGGBBAA` (uppercase)
28
+ * - `#RGB` short hex expanded to six digits
29
+ * - `rgb()` / `rgba()` with comma-separated channels (lower input only)
30
+ * - `var(--x)` / `var(--x, fallback)` returned as-is for a later resolve pass
31
+ */
32
+ var parseVariableValue = (value) => {
33
+ const normalized = value.trim().toLowerCase();
34
+ const hexValue = z.union([z.string().regex(hexRegex), z.string().regex(hexAlphaRegex)]).safeParse(normalized);
35
+ if (!hexValue.error) return hexValue.data.toUpperCase();
36
+ const shortHexValue = z.string().regex(hexShortRegex).safeParse(normalized);
37
+ if (!shortHexValue.error) {
38
+ const [_, r, g, b] = shortHexValue.data.toUpperCase();
39
+ return `#${r}${r}${g}${g}${b}${b}`;
40
+ }
41
+ const rgbValue = z.union([z.string().regex(rgbRegex), z.string().regex(rgbaRegex)]).safeParse(normalized);
42
+ if (!rgbValue.error) {
43
+ const [_, r = "0", g = "0", b = "0", a = "1"] = rgbValue.data.startsWith("rgba") ? rgbaRegex.exec(rgbValue.data) ?? [] : rgbRegex.exec(rgbValue.data) ?? [];
44
+ const toHex = (v) => Number.parseInt(v, 10).toString(16).padStart(2, "0").toUpperCase();
45
+ const alpha = Math.round(Number.parseFloat(a) * 255);
46
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}${alpha === 255 ? "" : toHex(String(alpha))}`;
47
+ }
48
+ const varValue = z.string().regex(varRegex).safeParse(normalized);
49
+ if (!varValue.error) return varValue.data;
50
+ };
51
+ /**
52
+ * Recursively resolves a value if it is (or becomes) `var(--name)` against `variables`.
53
+ * Missing names or non-var values are returned unchanged.
54
+ */
55
+ var resolveVariableValue = (value, variables) => {
56
+ const varValue = z.string().regex(varRegex).safeParse(value);
57
+ if (!varValue.error) {
58
+ const [_, varName] = varRegex.exec(varValue.data) ?? [];
59
+ if (!varName) return value;
60
+ const resolved = variables[varName];
61
+ if (!resolved) return value;
62
+ return resolveVariableValue(resolved, variables);
63
+ }
64
+ return value;
65
+ };
66
+ /**
67
+ * Resolves `var(--*)` values in a flat map of custom properties in one pass.
68
+ * Values that are not var references are copied through.
69
+ */
70
+ var resolveVariables = (variables) => {
71
+ const resolved = Object.entries(variables).map(([name, value]) => {
72
+ const varValue = z.string().regex(varRegex).safeParse(value);
73
+ if (!varValue.error) return [name, resolveVariableValue(varValue.data, variables)];
74
+ return [name, value];
75
+ });
76
+ return Object.fromEntries(resolved);
77
+ };
78
+ /**
4
79
  * Extracts CSS custom properties (variables) from a given CSS string
5
80
  * for .light-mode and .dark-mode selectors and returns an object
6
81
  * with 'light' and 'dark' keys containing the filtered variables.
7
- * Only variables matching hex color values (#RRGGBB or #RRGGBBAA) are accepted.
8
82
  *
9
83
  * @param css - The CSS string to parse.
10
84
  * @returns An object with `light` and `dark` properties containing the extracted CSS variables.
@@ -12,28 +86,30 @@ import { z } from "zod";
12
86
  var loadCssVariables = async (css) => {
13
87
  const sheet = new CSSStyleSheet();
14
88
  await sheet.replace(css);
15
- return Array.from(sheet.cssRules).reduce((acc, cur) => {
16
- if (!(cur instanceof CSSStyleRule)) return acc;
17
- const styles = Object.values(cur.style).reduce((style, name) => {
89
+ const parsed = Array.from(sheet.cssRules).filter((cssRule) => cssRule instanceof CSSStyleRule).reduce((variables, cssRule) => {
90
+ const colorModes = getColorModesFromSelectors(cssRule.selectorText);
91
+ if (!colorModes.length) return variables;
92
+ const styles = Array.from(cssRule.style).reduce((style, name) => {
18
93
  if (!name.startsWith("--")) return style;
19
- const value = z.string().regex(/^(?:#(?:[0-9A-F]{6}|[0-9A-F]{8}))$/i).safeParse(cur.style.getPropertyValue(name).toUpperCase().trim());
20
- if (value.error) return style;
21
- style[name] = value.data;
94
+ const parsedValue = parseVariableValue(cssRule.style.getPropertyValue(name));
95
+ if (parsedValue) style[name] = parsedValue;
22
96
  return style;
23
97
  }, {});
24
- if (cur.selectorText.includes(".light-mode")) acc.light = {
25
- ...acc.light,
26
- ...styles
27
- };
28
- if (cur.selectorText.includes(".dark-mode")) acc.dark = {
29
- ...acc.dark,
30
- ...styles
31
- };
32
- return acc;
98
+ colorModes.forEach((colorMode) => {
99
+ variables[colorMode] = {
100
+ ...variables[colorMode],
101
+ ...styles
102
+ };
103
+ });
104
+ return variables;
33
105
  }, {
34
106
  light: {},
35
107
  dark: {}
36
108
  });
109
+ return {
110
+ light: resolveVariables(parsed.light),
111
+ dark: resolveVariables(parsed.dark)
112
+ };
37
113
  };
38
114
  //#endregion
39
115
  export { loadCssVariables };
@@ -1 +1 @@
1
- {"version":3,"file":"load-css-variables.js","names":[],"sources":["../../../../../../src/v2/features/editor/helpers/theme/load-css-variables.ts"],"sourcesContent":["import { z } from 'zod'\n\n/**\n * Extracts CSS custom properties (variables) from a given CSS string\n * for .light-mode and .dark-mode selectors and returns an object\n * with 'light' and 'dark' keys containing the filtered variables.\n * Only variables matching hex color values (#RRGGBB or #RRGGBBAA) are accepted.\n *\n * @param css - The CSS string to parse.\n * @returns An object with `light` and `dark` properties containing the extracted CSS variables.\n */\nexport const loadCssVariables = async (css: string) => {\n const sheet = new CSSStyleSheet()\n await sheet.replace(css)\n\n const parsed = Array.from(sheet.cssRules).reduce<{ light: any; dark: any }>(\n (acc, cur) => {\n // Process only style rules (skip e.g. media, font-face, etc.)\n if (!(cur instanceof CSSStyleRule)) {\n return acc\n }\n\n // Collect valid CSS variable declarations from the rule's style\n const styles = Object.values(cur.style).reduce<Record<string, string>>((style, name) => {\n if (!name.startsWith('--')) {\n return style\n }\n\n // Only accept variables that match hex color format\n const value = z\n .string()\n .regex(/^(?:#(?:[0-9A-F]{6}|[0-9A-F]{8}))$/i)\n .safeParse(cur.style.getPropertyValue(name).toUpperCase().trim())\n\n if (value.error) {\n return style\n }\n\n style[name] = value.data\n\n return style\n }, {})\n\n // Merge variables into the correct theme object based on selector\n if (cur.selectorText.includes('.light-mode')) {\n acc.light = { ...acc.light, ...styles }\n }\n\n if (cur.selectorText.includes('.dark-mode')) {\n acc.dark = { ...acc.dark, ...styles }\n }\n\n return acc\n },\n { light: {}, dark: {} },\n )\n\n return parsed\n}\n"],"mappings":";;;;;;;;;;;AAWA,IAAa,mBAAmB,OAAO,QAAgB;CACrD,MAAM,QAAQ,IAAI,eAAe;AACjC,OAAM,MAAM,QAAQ,IAAI;AA4CxB,QA1Ce,MAAM,KAAK,MAAM,SAAS,CAAC,QACvC,KAAK,QAAQ;AAEZ,MAAI,EAAE,eAAe,cACnB,QAAO;EAIT,MAAM,SAAS,OAAO,OAAO,IAAI,MAAM,CAAC,QAAgC,OAAO,SAAS;AACtF,OAAI,CAAC,KAAK,WAAW,KAAK,CACxB,QAAO;GAIT,MAAM,QAAQ,EACX,QAAQ,CACR,MAAM,sCAAsC,CAC5C,UAAU,IAAI,MAAM,iBAAiB,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC;AAEnE,OAAI,MAAM,MACR,QAAO;AAGT,SAAM,QAAQ,MAAM;AAEpB,UAAO;KACN,EAAE,CAAC;AAGN,MAAI,IAAI,aAAa,SAAS,cAAc,CAC1C,KAAI,QAAQ;GAAE,GAAG,IAAI;GAAO,GAAG;GAAQ;AAGzC,MAAI,IAAI,aAAa,SAAS,aAAa,CACzC,KAAI,OAAO;GAAE,GAAG,IAAI;GAAM,GAAG;GAAQ;AAGvC,SAAO;IAET;EAAE,OAAO,EAAE;EAAE,MAAM,EAAE;EAAE,CACxB"}
1
+ {"version":3,"file":"load-css-variables.js","names":[],"sources":["../../../../../../src/v2/features/editor/helpers/theme/load-css-variables.ts"],"sourcesContent":["import { z } from 'zod'\n\n/** Which theme bucket a CSS rule applies to after parsing. */\ntype ColorMode = 'light' | 'dark'\n\n/** Accumulated custom properties per mode while walking stylesheet rules. */\ntype Variables = Record<ColorMode, Record<string, string>>\n\n/**\n * Patterns for CSS color values we can normalize to hex (or pass through as var()).\n * Space-separated rgb() and modern slash syntax are not supported here.\n */\nconst hexShortRegex = /^#([0-9a-fA-F]){3}$/\nconst hexRegex = /^#([0-9a-fA-F]{6})$/\nconst hexAlphaRegex = /^#([0-9a-fA-F]{8})$/\nconst rgbRegex = /^rgb\\(\\s*(\\d{1,3})\\s*,?\\s*(\\d{1,3})\\s*,?\\s*(\\d{1,3})\\s*\\)$/\nconst rgbaRegex = /^rgba\\(\\s*(\\d{1,3})\\s*,?\\s*(\\d{1,3})\\s*,?\\s*(\\d{1,3})\\s*,?\\s*(\\d*\\.?\\d+)\\s*\\)$/\n/** Optional fallback: var(--name, fallback) */\nconst varRegex = /^var\\(\\s*(--[^)]+)\\s*(?:,\\s*([^)]*))?\\s*\\)$/i\n\n/**\n * Maps a comma-separated selector list to the theme modes it applies to.\n * Only **exact** `.light-mode` or `.dark-mode` selectors match (no compound selectors like `.light-mode .foo`).\n */\nexport const getColorModesFromSelectors = (text: string) => {\n const selectors = text.split(',').map((selector) => selector.trim())\n\n return selectors\n .map((selector) => {\n if (selector === '.light-mode') {\n return 'light'\n }\n if (selector === '.dark-mode') {\n return 'dark'\n }\n return null\n })\n .filter((mode) => mode !== null)\n}\n\n/**\n * Parses a single custom property value from the stylesheet into a normalized form:\n * - `#RRGGBB` / `#RRGGBBAA` (uppercase)\n * - `#RGB` short hex expanded to six digits\n * - `rgb()` / `rgba()` with comma-separated channels (lower input only)\n * - `var(--x)` / `var(--x, fallback)` returned as-is for a later resolve pass\n */\nexport const parseVariableValue = (value: string) => {\n const normalized = value.trim().toLowerCase()\n\n const hexValue = z.union([z.string().regex(hexRegex), z.string().regex(hexAlphaRegex)]).safeParse(normalized)\n\n if (!hexValue.error) {\n return hexValue.data.toUpperCase()\n }\n\n const shortHexValue = z.string().regex(hexShortRegex).safeParse(normalized)\n\n if (!shortHexValue.error) {\n const [_, r, g, b] = shortHexValue.data.toUpperCase()\n return `#${r}${r}${g}${g}${b}${b}`\n }\n\n const rgbValue = z.union([z.string().regex(rgbRegex), z.string().regex(rgbaRegex)]).safeParse(normalized)\n\n if (!rgbValue.error) {\n const [_, r = '0', g = '0', b = '0', a = '1'] = rgbValue.data.startsWith('rgba')\n ? (rgbaRegex.exec(rgbValue.data) ?? [])\n : (rgbRegex.exec(rgbValue.data) ?? [])\n\n const toHex = (v: string) => Number.parseInt(v, 10).toString(16).padStart(2, '0').toUpperCase()\n const alpha = Math.round(Number.parseFloat(a) * 255)\n\n return `#${toHex(r)}${toHex(g)}${toHex(b)}${alpha === 255 ? '' : toHex(String(alpha))}`\n }\n\n const varValue = z.string().regex(varRegex).safeParse(normalized)\n if (!varValue.error) {\n return varValue.data\n }\n\n return undefined\n}\n\n/**\n * Recursively resolves a value if it is (or becomes) `var(--name)` against `variables`.\n * Missing names or non-var values are returned unchanged.\n */\nexport const resolveVariableValue = (value: string, variables: Record<string, string>): string => {\n const varValue = z.string().regex(varRegex).safeParse(value)\n if (!varValue.error) {\n const [_, varName] = varRegex.exec(varValue.data) ?? []\n if (!varName) {\n return value\n }\n const resolved = variables[varName]\n if (!resolved) {\n return value\n }\n return resolveVariableValue(resolved, variables)\n }\n return value\n}\n\n/**\n * Resolves `var(--*)` values in a flat map of custom properties in one pass.\n * Values that are not var references are copied through.\n */\nexport const resolveVariables = (variables: Record<string, string>): Record<string, string> => {\n const entries = Object.entries(variables)\n\n const resolved = entries.map(([name, value]) => {\n const varValue = z.string().regex(varRegex).safeParse(value)\n if (!varValue.error) {\n return [name, resolveVariableValue(varValue.data, variables)]\n }\n return [name, value]\n })\n return Object.fromEntries(resolved)\n}\n\n/**\n * Extracts CSS custom properties (variables) from a given CSS string\n * for .light-mode and .dark-mode selectors and returns an object\n * with 'light' and 'dark' keys containing the filtered variables.\n *\n * @param css - The CSS string to parse.\n * @returns An object with `light` and `dark` properties containing the extracted CSS variables.\n */\nexport const loadCssVariables = async (css: string) => {\n const sheet = new CSSStyleSheet()\n await sheet.replace(css)\n\n const cssRules = Array.from(sheet.cssRules).filter((cssRule) => cssRule instanceof CSSStyleRule)\n const parsed = cssRules.reduce<Variables>(\n (variables, cssRule) => {\n const colorModes = getColorModesFromSelectors(cssRule.selectorText)\n if (!colorModes.length) {\n return variables\n }\n\n // Collect valid CSS variable declarations from the rule's style\n const styles = Array.from(cssRule.style).reduce<Record<string, string>>((style, name) => {\n if (!name.startsWith('--')) {\n return style\n }\n const value = cssRule.style.getPropertyValue(name)\n const parsedValue = parseVariableValue(value)\n if (parsedValue) {\n style[name] = parsedValue\n }\n return style\n }, {})\n\n colorModes.forEach((colorMode) => {\n variables[colorMode] = { ...variables[colorMode], ...styles }\n })\n\n return variables\n },\n { light: {}, dark: {} },\n )\n\n return {\n light: resolveVariables(parsed.light),\n dark: resolveVariables(parsed.dark),\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"posthog.d.ts","sourceRoot":"","sources":["../../src/v2/posthog.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,GAAG,EAAS,MAAM,KAAK,CAAA;AASrC,eAAO,MAAM,UAAU,GAAI,SAAS,GAAG,CAAC,OAAO,CAAC,SAY/C,CAAA"}
1
+ {"version":3,"file":"posthog.d.ts","sourceRoot":"","sources":["../../src/v2/posthog.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,GAAG,EAAS,MAAM,KAAK,CAAA;AAarC,eAAO,MAAM,UAAU,GAAI,SAAS,GAAG,CAAC,OAAO,CAAC,SAY/C,CAAA"}
@@ -7,6 +7,7 @@ var posthog = ph.init("phc_3elIjSOvGOo5aEwg6krzIY9IcQiRubsBtglOXsQ4Uu4", {
7
7
  defaults: "2025-11-30",
8
8
  opt_out_capturing_by_default: true
9
9
  });
10
+ posthog.register({ product: "api-client" });
10
11
  var usePosthog = (enabled) => {
11
12
  watch(enabled, (value) => {
12
13
  if (value) posthog.opt_in_capturing();
@@ -1 +1 @@
1
- {"version":3,"file":"posthog.js","names":[],"sources":["../../src/v2/posthog.ts"],"sourcesContent":["import ph from 'posthog-js'\nimport { type Ref, watch } from 'vue'\n\nconst posthog = ph.init('phc_3elIjSOvGOo5aEwg6krzIY9IcQiRubsBtglOXsQ4Uu4', {\n api_host: 'https://magic.scalar.com',\n ui_host: 'https://us.posthog.com',\n defaults: '2025-11-30',\n opt_out_capturing_by_default: true,\n})\n\nexport const usePosthog = (enabled: Ref<boolean>) => {\n watch(\n enabled,\n (value) => {\n if (value) {\n posthog.opt_in_capturing()\n } else {\n posthog.opt_out_capturing()\n }\n },\n { immediate: true },\n )\n}\n"],"mappings":";;;AAGA,IAAM,UAAU,GAAG,KAAK,mDAAmD;CACzE,UAAU;CACV,SAAS;CACT,UAAU;CACV,8BAA8B;CAC/B,CAAC;AAEF,IAAa,cAAc,YAA0B;AACnD,OACE,UACC,UAAU;AACT,MAAI,MACF,SAAQ,kBAAkB;MAE1B,SAAQ,mBAAmB;IAG/B,EAAE,WAAW,MAAM,CACpB"}
1
+ {"version":3,"file":"posthog.js","names":[],"sources":["../../src/v2/posthog.ts"],"sourcesContent":["import ph from 'posthog-js'\nimport { type Ref, watch } from 'vue'\n\nconst posthog = ph.init('phc_3elIjSOvGOo5aEwg6krzIY9IcQiRubsBtglOXsQ4Uu4', {\n api_host: 'https://magic.scalar.com',\n ui_host: 'https://us.posthog.com',\n defaults: '2025-11-30',\n opt_out_capturing_by_default: true,\n})\n\nposthog.register({\n product: 'api-client',\n})\n\nexport const usePosthog = (enabled: Ref<boolean>) => {\n watch(\n enabled,\n (value) => {\n if (value) {\n posthog.opt_in_capturing()\n } else {\n posthog.opt_out_capturing()\n }\n },\n { immediate: true },\n )\n}\n"],"mappings":";;;AAGA,IAAM,UAAU,GAAG,KAAK,mDAAmD;CACzE,UAAU;CACV,SAAS;CACT,UAAU;CACV,8BAA8B;CAC/B,CAAC;AAEF,QAAQ,SAAS,EACf,SAAS,cACV,CAAC;AAEF,IAAa,cAAc,YAA0B;AACnD,OACE,UACC,UAAU;AACT,MAAI,MACF,SAAQ,kBAAkB;MAE1B,SAAQ,mBAAmB;IAG/B,EAAE,WAAW,MAAM,CACpB"}
@@ -45,7 +45,7 @@ var ResponseEmpty_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */
45
45
  const handleHotKey = (event) => {
46
46
  if (event?.createNew && route.name === "request") addRequest();
47
47
  };
48
- const packageVersion = "2.39.1";
48
+ const packageVersion = "2.39.3";
49
49
  onMounted(() => events.hotKeys.on(handleHotKey));
50
50
  onBeforeUnmount(() => events.hotKeys.off(handleHotKey));
51
51
  return (_ctx, _cache) => {
package/package.json CHANGED
@@ -18,7 +18,7 @@
18
18
  "rest",
19
19
  "testing"
20
20
  ],
21
- "version": "2.39.1",
21
+ "version": "2.39.3",
22
22
  "engines": {
23
23
  "node": ">=22"
24
24
  },
@@ -349,22 +349,22 @@
349
349
  "zod": "^4.3.5",
350
350
  "@scalar/components": "0.21.1",
351
351
  "@scalar/draggable": "0.4.1",
352
- "@scalar/icons": "0.7.0",
353
- "@scalar/helpers": "0.4.2",
354
352
  "@scalar/import": "0.5.3",
355
- "@scalar/oas-utils": "0.10.12",
353
+ "@scalar/helpers": "0.4.2",
356
354
  "@scalar/json-magic": "0.12.4",
357
- "@scalar/object-utils": "1.3.3",
355
+ "@scalar/icons": "0.7.0",
356
+ "@scalar/oas-utils": "0.10.13",
358
357
  "@scalar/openapi-types": "0.6.1",
358
+ "@scalar/object-utils": "1.3.3",
359
359
  "@scalar/postman-to-openapi": "0.6.0",
360
- "@scalar/sidebar": "0.8.14",
360
+ "@scalar/sidebar": "0.8.15",
361
361
  "@scalar/snippetz": "0.7.7",
362
362
  "@scalar/themes": "0.15.1",
363
363
  "@scalar/types": "0.7.5",
364
+ "@scalar/use-codemirror": "0.14.10",
364
365
  "@scalar/use-hooks": "0.4.1",
365
- "@scalar/use-toasts": "0.10.1",
366
- "@scalar/workspace-store": "0.41.1",
367
- "@scalar/use-codemirror": "0.14.10"
366
+ "@scalar/workspace-store": "0.41.2",
367
+ "@scalar/use-toasts": "0.10.1"
368
368
  },
369
369
  "devDependencies": {
370
370
  "@tailwindcss/vite": "^4.2.0",
@@ -379,8 +379,8 @@
379
379
  "vite": "8.0.0",
380
380
  "vite-svg-loader": "5.1.1",
381
381
  "vitest": "4.1.0",
382
- "@scalar/pre-post-request-scripts": "0.3.14",
383
- "@scalar/galaxy": "0.6.1"
382
+ "@scalar/galaxy": "0.6.1",
383
+ "@scalar/pre-post-request-scripts": "0.3.15"
384
384
  },
385
385
  "scripts": {
386
386
  "build": "vite build && vue-tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",