@scalar/api-client 2.39.3 → 2.39.4
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.
- package/CHANGELOG.md +6 -0
- package/dist/hooks/useResponseBody.js +2 -2
- package/dist/hooks/useResponseBody.js.map +1 -1
- package/dist/libs/send-request/decode-buffer.js +2 -2
- package/dist/libs/send-request/decode-buffer.js.map +1 -1
- package/dist/style.css +34 -34
- package/dist/v2/blocks/operation-block/helpers/decode-buffer.js +2 -2
- package/dist/v2/blocks/operation-block/helpers/decode-buffer.js.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestTableRow.vue.d.ts.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestTableRow.vue.js.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestTableRow.vue.script.js +10 -8
- package/dist/v2/blocks/request-block/components/RequestTableRow.vue.script.js.map +1 -1
- package/dist/v2/blocks/response-block/helpers/process-response-body.js +2 -2
- package/dist/v2/blocks/response-block/helpers/process-response-body.js.map +1 -1
- package/dist/v2/components/code-input/CodeInput.vue.d.ts +8 -2
- package/dist/v2/components/code-input/CodeInput.vue.d.ts.map +1 -1
- package/dist/v2/components/code-input/CodeInput.vue.js +1 -1
- package/dist/v2/components/code-input/CodeInput.vue.js.map +1 -1
- package/dist/v2/components/code-input/CodeInput.vue.script.js +5 -2
- package/dist/v2/components/code-input/CodeInput.vue.script.js.map +1 -1
- package/dist/v2/constants.js +1 -1
- package/dist/views/Request/ResponseSection/ResponseEmpty.vue.script.js +1 -1
- package/package.json +11 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { extractFilename } from "../libs/extractAttachmentFilename.js";
|
|
2
2
|
import { computed, isRef } from "vue";
|
|
3
|
-
import
|
|
3
|
+
import MimeType 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
|
|
14
|
+
return new MimeType(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,
|
|
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,9 +1,9 @@
|
|
|
1
1
|
import { isTextMediaType } from "../../views/Request/consts/mediaTypes.js";
|
|
2
|
-
import
|
|
2
|
+
import MimeType 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
|
|
6
|
+
const mimeType = new MimeType(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,
|
|
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"}
|
package/dist/style.css
CHANGED
|
@@ -1439,13 +1439,13 @@ input[data-v-c1a50a6e]::placeholder {
|
|
|
1439
1439
|
}
|
|
1440
1440
|
|
|
1441
1441
|
@media (max-width: 720px) and (max-height: 480px) {
|
|
1442
|
-
.scalar-modal-layout .scalar-modal[data-v-
|
|
1442
|
+
.scalar-modal-layout .scalar-modal[data-v-5bb1dcc2] {
|
|
1443
1443
|
max-height: 90svh;
|
|
1444
1444
|
margin-top: 5svh;
|
|
1445
1445
|
}
|
|
1446
1446
|
}
|
|
1447
1447
|
|
|
1448
|
-
@keyframes fadein-layout-
|
|
1448
|
+
@keyframes fadein-layout-5bb1dcc2 {
|
|
1449
1449
|
0% {
|
|
1450
1450
|
opacity: 0;
|
|
1451
1451
|
}
|
|
@@ -1455,7 +1455,7 @@ input[data-v-c1a50a6e]::placeholder {
|
|
|
1455
1455
|
}
|
|
1456
1456
|
}
|
|
1457
1457
|
|
|
1458
|
-
@keyframes fadein-modal-
|
|
1458
|
+
@keyframes fadein-modal-5bb1dcc2 {
|
|
1459
1459
|
0% {
|
|
1460
1460
|
opacity: 0;
|
|
1461
1461
|
transform: translate3d(0, 10px, 0);
|
|
@@ -1468,7 +1468,7 @@ input[data-v-c1a50a6e]::placeholder {
|
|
|
1468
1468
|
}
|
|
1469
1469
|
|
|
1470
1470
|
@media (min-width: 800px) {
|
|
1471
|
-
.full-size-styles[data-v-
|
|
1471
|
+
.full-size-styles[data-v-5bb1dcc2] {
|
|
1472
1472
|
width: 50dvw !important;
|
|
1473
1473
|
}
|
|
1474
1474
|
}
|
|
@@ -3183,22 +3183,22 @@ input[data-v-c1a50a6e]::placeholder {
|
|
|
3183
3183
|
display: none;
|
|
3184
3184
|
}
|
|
3185
3185
|
|
|
3186
|
-
.scalar-modal-layout[data-v-
|
|
3187
|
-
animation: .3s ease-in-out forwards fadein-layout-
|
|
3186
|
+
.scalar-modal-layout[data-v-5bb1dcc2] {
|
|
3187
|
+
animation: .3s ease-in-out forwards fadein-layout-5bb1dcc2;
|
|
3188
3188
|
}
|
|
3189
3189
|
|
|
3190
|
-
.scalar-modal[data-v-
|
|
3190
|
+
.scalar-modal[data-v-5bb1dcc2] {
|
|
3191
3191
|
box-shadow: var(--scalar-shadow-2);
|
|
3192
|
-
animation: .3s ease-in-out .1s forwards fadein-modal-
|
|
3192
|
+
animation: .3s ease-in-out .1s forwards fadein-modal-5bb1dcc2;
|
|
3193
3193
|
transform: translate3d(0, 10px, 0);
|
|
3194
3194
|
}
|
|
3195
3195
|
|
|
3196
|
-
.scalar-modal-layout-full[data-v-
|
|
3196
|
+
.scalar-modal-layout-full[data-v-5bb1dcc2] {
|
|
3197
3197
|
opacity: 1 !important;
|
|
3198
3198
|
background: none !important;
|
|
3199
3199
|
}
|
|
3200
3200
|
|
|
3201
|
-
.modal-content-search .modal-body[data-v-
|
|
3201
|
+
.modal-content-search .modal-body[data-v-5bb1dcc2] {
|
|
3202
3202
|
flex-direction: column;
|
|
3203
3203
|
max-height: 440px;
|
|
3204
3204
|
padding: 0;
|
|
@@ -3207,16 +3207,16 @@ input[data-v-c1a50a6e]::placeholder {
|
|
|
3207
3207
|
}
|
|
3208
3208
|
|
|
3209
3209
|
@media (max-width: 720px) and (max-height: 480px) {
|
|
3210
|
-
.scalar-modal-layout .scalar-modal[data-v-
|
|
3210
|
+
.scalar-modal-layout .scalar-modal[data-v-5bb1dcc2] {
|
|
3211
3211
|
max-height: 90svh;
|
|
3212
3212
|
margin-top: 5svh;
|
|
3213
3213
|
}
|
|
3214
3214
|
}
|
|
3215
3215
|
|
|
3216
|
-
.full-size-styles[data-v-
|
|
3216
|
+
.full-size-styles[data-v-5bb1dcc2] {
|
|
3217
3217
|
margin: initial;
|
|
3218
3218
|
border-right: var(--scalar-border-width) solid var(--scalar-border-color);
|
|
3219
|
-
animation: .3s ease-in-out forwards fadein-layout-
|
|
3219
|
+
animation: .3s ease-in-out forwards fadein-layout-5bb1dcc2;
|
|
3220
3220
|
left: 0;
|
|
3221
3221
|
transform: translate3d(0, 0, 0);
|
|
3222
3222
|
background-color: var(--scalar-background-1) !important;
|
|
@@ -3228,12 +3228,12 @@ input[data-v-c1a50a6e]::placeholder {
|
|
|
3228
3228
|
}
|
|
3229
3229
|
|
|
3230
3230
|
@media (min-width: 800px) {
|
|
3231
|
-
.full-size-styles[data-v-
|
|
3231
|
+
.full-size-styles[data-v-5bb1dcc2] {
|
|
3232
3232
|
width: 50dvw !important;
|
|
3233
3233
|
}
|
|
3234
3234
|
}
|
|
3235
3235
|
|
|
3236
|
-
.full-size-styles[data-v-
|
|
3236
|
+
.full-size-styles[data-v-5bb1dcc2]:after {
|
|
3237
3237
|
content: "";
|
|
3238
3238
|
width: 50dvw;
|
|
3239
3239
|
height: 100dvh;
|
|
@@ -8497,23 +8497,23 @@ input[data-v-c1a50a6e]::placeholder {
|
|
|
8497
8497
|
/*
|
|
8498
8498
|
Deep styling for customizing Codemirror
|
|
8499
8499
|
*/
|
|
8500
|
-
[data-v-
|
|
8500
|
+
[data-v-e041f4b0] .cm-editor {
|
|
8501
8501
|
height: 100%;
|
|
8502
8502
|
outline: none;
|
|
8503
8503
|
padding: 0;
|
|
8504
8504
|
background: transparent;
|
|
8505
8505
|
}
|
|
8506
|
-
[data-v-
|
|
8506
|
+
[data-v-e041f4b0] .cm-placeholder {
|
|
8507
8507
|
color: var(--scalar-color-3);
|
|
8508
8508
|
}
|
|
8509
|
-
[data-v-
|
|
8509
|
+
[data-v-e041f4b0] .cm-content {
|
|
8510
8510
|
font-family: var(--scalar-font-code);
|
|
8511
8511
|
font-size: var(--scalar-small);
|
|
8512
8512
|
max-height: 20px;
|
|
8513
8513
|
padding: 8px 0;
|
|
8514
8514
|
}
|
|
8515
8515
|
/* Tooltip helper */
|
|
8516
|
-
[data-v-
|
|
8516
|
+
[data-v-e041f4b0] .cm-tooltip {
|
|
8517
8517
|
background: transparent !important;
|
|
8518
8518
|
filter: brightness(var(--scalar-lifted-brightness));
|
|
8519
8519
|
border-radius: var(--scalar-radius);
|
|
@@ -8522,43 +8522,43 @@ input[data-v-c1a50a6e]::placeholder {
|
|
|
8522
8522
|
outline: none !important;
|
|
8523
8523
|
overflow: hidden !important;
|
|
8524
8524
|
}
|
|
8525
|
-
[data-v-
|
|
8525
|
+
[data-v-e041f4b0] .cm-tooltip-autocomplete ul li {
|
|
8526
8526
|
padding: 3px 6px !important;
|
|
8527
8527
|
}
|
|
8528
|
-
[data-v-
|
|
8528
|
+
[data-v-e041f4b0] .cm-completionIcon-type:after {
|
|
8529
8529
|
color: var(--scalar-color-3) !important;
|
|
8530
8530
|
}
|
|
8531
|
-
[data-v-
|
|
8531
|
+
[data-v-e041f4b0] .cm-tooltip-autocomplete ul li[aria-selected] {
|
|
8532
8532
|
background: var(--scalar-background-2) !important;
|
|
8533
8533
|
color: var(--scalar-color-1) !important;
|
|
8534
8534
|
}
|
|
8535
|
-
[data-v-
|
|
8535
|
+
[data-v-e041f4b0] .cm-tooltip-autocomplete ul {
|
|
8536
8536
|
padding: 6px !important;
|
|
8537
8537
|
position: relative;
|
|
8538
8538
|
}
|
|
8539
|
-
[data-v-
|
|
8539
|
+
[data-v-e041f4b0] .cm-tooltip-autocomplete ul li:hover {
|
|
8540
8540
|
border-radius: 3px;
|
|
8541
8541
|
color: var(--scalar-color-1) !important;
|
|
8542
8542
|
background: var(--scalar-background-3) !important;
|
|
8543
8543
|
}
|
|
8544
8544
|
/* Disable active line highlighting */
|
|
8545
|
-
[data-v-
|
|
8545
|
+
[data-v-e041f4b0] .cm-activeLine,[data-v-e041f4b0] .cm-activeLineGutter {
|
|
8546
8546
|
background-color: transparent;
|
|
8547
8547
|
}
|
|
8548
8548
|
/* Color selection matching */
|
|
8549
|
-
[data-v-
|
|
8549
|
+
[data-v-e041f4b0] .cm-selectionMatch,[data-v-e041f4b0] .cm-matchingBracket {
|
|
8550
8550
|
border-radius: var(--scalar-radius);
|
|
8551
8551
|
background: var(--scalar-background-4) !important;
|
|
8552
8552
|
}
|
|
8553
8553
|
/* Color Picker Swatches */
|
|
8554
|
-
[data-v-
|
|
8554
|
+
[data-v-e041f4b0] .cm-css-color-picker-wrapper {
|
|
8555
8555
|
display: inline-flex;
|
|
8556
8556
|
outline: 1px solid var(--scalar-background-3);
|
|
8557
8557
|
border-radius: 3px;
|
|
8558
8558
|
overflow: hidden;
|
|
8559
8559
|
}
|
|
8560
8560
|
/* Number gutter */
|
|
8561
|
-
[data-v-
|
|
8561
|
+
[data-v-e041f4b0] .cm-gutters {
|
|
8562
8562
|
background-color: transparent;
|
|
8563
8563
|
border-right: none;
|
|
8564
8564
|
color: var(--scalar-color-3);
|
|
@@ -8566,7 +8566,7 @@ input[data-v-c1a50a6e]::placeholder {
|
|
|
8566
8566
|
line-height: 22px;
|
|
8567
8567
|
border-radius: 0 0 0 3px;
|
|
8568
8568
|
}
|
|
8569
|
-
[data-v-
|
|
8569
|
+
[data-v-e041f4b0] .cm-gutters:before {
|
|
8570
8570
|
content: '';
|
|
8571
8571
|
position: absolute;
|
|
8572
8572
|
top: 2px;
|
|
@@ -8576,7 +8576,7 @@ input[data-v-c1a50a6e]::placeholder {
|
|
|
8576
8576
|
border-radius: var(--scalar-radius) 0 0 var(--scalar-radius);
|
|
8577
8577
|
background-color: var(--scalar-background-1);
|
|
8578
8578
|
}
|
|
8579
|
-
[data-v-
|
|
8579
|
+
[data-v-e041f4b0] .cm-gutterElement {
|
|
8580
8580
|
font-family: var(--scalar-font-code) !important;
|
|
8581
8581
|
padding-left: 0px !important;
|
|
8582
8582
|
padding-right: 6px !important;
|
|
@@ -8585,16 +8585,16 @@ input[data-v-c1a50a6e]::placeholder {
|
|
|
8585
8585
|
justify-content: flex-end;
|
|
8586
8586
|
position: relative;
|
|
8587
8587
|
}
|
|
8588
|
-
[data-v-
|
|
8588
|
+
[data-v-e041f4b0] .cm-lineNumbers .cm-gutterElement {
|
|
8589
8589
|
min-width: fit-content;
|
|
8590
8590
|
}
|
|
8591
|
-
[data-v-
|
|
8591
|
+
[data-v-e041f4b0] .cm-gutter + .cm-gutter :not(.cm-foldGutter) .cm-gutterElement {
|
|
8592
8592
|
padding-left: 0 !important;
|
|
8593
8593
|
}
|
|
8594
|
-
[data-v-
|
|
8594
|
+
[data-v-e041f4b0] .cm-scroller {
|
|
8595
8595
|
overflow: auto;
|
|
8596
8596
|
}
|
|
8597
|
-
.line-wrapping[data-v-
|
|
8597
|
+
.line-wrapping[data-v-e041f4b0]:focus-within .cm-content {
|
|
8598
8598
|
display: inline-table;
|
|
8599
8599
|
min-height: fit-content;
|
|
8600
8600
|
padding: 3px 6px;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isTextMediaType } from "../../../../views/Request/consts/mediaTypes.js";
|
|
2
|
-
import
|
|
2
|
+
import MimeType 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 MimeTypeParser from "whatwg-mimetype";
|
|
|
7
7
|
* @returns The decoded string or Blob
|
|
8
8
|
*/
|
|
9
9
|
var decodeBuffer = (buffer, contentType) => {
|
|
10
|
-
const mimeType = new
|
|
10
|
+
const mimeType = new MimeType(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,
|
|
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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RequestTableRow.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RequestTableRow.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"names":[],"mappings":"AAmTA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAGxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AACnH,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACb,MAAM,8DAA8D,CAAA;AAcrE,MAAM,MAAM,QAAQ,GAAG;IACrB,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAA;IACZ,0DAA0D;IAC1D,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAA;IAC3B,6CAA6C;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,mFAAmF;IACnF,WAAW,CAAC,EAAE,kBAAkB,CAAC,aAAa,CAAC,CAAA;IAC/C,iDAAiD;IACjD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,wEAAwE;IACxE,MAAM,CAAC,EAAE,YAAY,CAAA;IACrB,wCAAwC;IACxC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,mDAAmD;IACnD,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,uDAAuD;IACvD,iBAAiB,CAAC,EAAE,eAAe,CAAA;CACpC,CAAA;AAED,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,QAAQ,CAAA;IACd,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,kBAAkB,CAAA;IAC/B,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC3B,CAAC;AA6lBF,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAhlBG,MAAM;eAAS,MAAM,GAAG,IAAI;oBAAc,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAAjD,MAAM;eAAS,MAAM,GAAG,IAAI;oBAAc,OAAO;;kFAmlBpE,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RequestTableRow.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton, ScalarIcon, ScalarIconButton } from '@scalar/components'\nimport { ScalarIconGlobe, ScalarIconTrash } from '@scalar/icons'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n ParameterObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { validateParameter } from '@/v2/blocks/request-block/helpers/validate-parameter'\nimport { CodeInput } from '@/v2/components/code-input'\nimport {\n DataTableCell,\n DataTableCheckbox,\n DataTableRow,\n} from '@/v2/components/data-table'\n\nimport RequestTableTooltip from './RequestTableTooltip.vue'\n\nexport type TableRow = {\n /** The parameter or field name/key */\n name: string\n /** The parameter value, can be a string, file, or null */\n value: string | File | null\n /** Optional description for the parameter */\n description?: string\n /** Optional route for global parameters (e.g., cookies shared across workspace) */\n globalRoute?: ApiReferenceEvents['ui:navigate']\n /** Whether the parameter is disabled/inactive */\n isDisabled?: boolean\n /** OpenAPI schema object with type, validation rules, examples, etc. */\n schema?: SchemaObject\n /** Whether the parameter is required */\n isRequired?: boolean\n /**\n * Whether the parameter is readonly and can not be modifies directly\n * User can still override the parameter which is going to show up with the linethrough style\n */\n isReadonly?: boolean\n /** Whether the parameter is overridden later on */\n isOverridden?: boolean\n /** Track the original parameter so we can update it */\n originalParameter?: ParameterObject\n}\n\nconst {\n data,\n environment,\n hasCheckboxDisabled,\n invalidParams,\n showUploadButton,\n} = defineProps<{\n data: TableRow\n hasCheckboxDisabled?: boolean\n invalidParams?: Set<string>\n label?: string\n environment: XScalarEnvironment\n showUploadButton?: boolean\n}>()\n\nconst emit = defineEmits<{\n (\n e: 'upsertRow',\n payload: { name: string; value: string | File; isDisabled: boolean },\n ): void\n (e: 'deleteRow'): void\n (e: 'uploadFile'): void\n (e: 'removeFile'): void\n (e: 'navigate', route: NonNullable<TableRow['globalRoute']>): void\n}>()\n\n/**\n * Track local state for the row\n *\n * Now this is required because of the way we get default values from the schema.\n * If we have a default value in data.value, then we update isDisabled to true. We lose the default value since now\n * we have an example where value: ''. This is why we need to track the local state and update all of the params at the\n * same time.\n */\nconst name = ref<string>(data.name ?? '')\nconst value = ref<string | File>(unpackProxyObject(data.value) ?? '')\nconst isDisabled = ref<boolean>(data.isDisabled ?? false)\n\n// Keep the above state synced with the data prop\nwatch(\n () => data.name,\n (newName) => (name.value = newName ?? ''),\n)\nwatch(\n () => data.value,\n (newValue) => (value.value = unpackProxyObject(newValue) ?? ''),\n)\nwatch(\n () => data.isDisabled,\n (newIsDisabled) => (isDisabled.value = newIsDisabled ?? false),\n)\n\n/** Check if the value is a File instance */\nconst isFile = computed(() => value.value instanceof File)\n\n/** Display value handles File instances and shows filename instead */\nconst displayValue = computed(\n () =>\n (isFile.value\n ? getFileName(value.value as File)\n : (value.value as string)) ?? '',\n)\n\nconst defaultValue = computed(() => data.schema?.default as string)\n\n/** See if we can extract enum values from the schema */\nconst enumValue = computed<string[]>(() => {\n if (!data.schema) {\n return []\n }\n\n // Grab the enum from the schema\n if (data.schema.enum) {\n return data.schema.enum.map((item) => String(item))\n }\n\n // Grab the enum from the items schema\n if ('items' in data.schema) {\n const resolved = resolve.schema(data.schema.items)\n if (resolved?.enum) {\n return resolved.enum.map((item) => String(item))\n }\n }\n\n return []\n})\n\nconst minimumValue = computed(() =>\n data.schema && 'minimum' in data.schema ? data.schema.minimum : undefined,\n)\nconst maximumValue = computed(() =>\n data.schema && 'maximum' in data.schema ? data.schema.maximum : undefined,\n)\nconst typeValue = computed(() =>\n data.schema && 'type' in data.schema ? data.schema.type : undefined,\n)\n\nconst validationResult = computed(() =>\n validateParameter(data.schema, value.value),\n)\n\n/** Handle row updates while preserving existing properties */\nconst handleUpdateRow = (\n payload: Partial<{ name: string; value: string; isDisabled: boolean }>,\n): void => {\n // Update our local state\n if (payload.name !== undefined) {\n name.value = payload.name\n }\n if (payload.value !== undefined) {\n value.value = payload.value\n }\n\n // Is disabled should always be false unless you explicitly set it to true\n isDisabled.value = payload.isDisabled ?? false\n\n // Emit all of the local state\n emit('upsertRow', {\n name: name.value,\n value: value.value,\n isDisabled: isDisabled.value,\n })\n}\n</script>\n\n<template>\n <DataTableRow\n :id=\"data.name\"\n :class=\"{\n alert: validationResult.ok === false,\n error: validationResult.ok === false && invalidParams?.has(data.name),\n }\">\n <DataTableCheckbox\n class=\"!border-r\"\n :disabled=\"hasCheckboxDisabled ?? false\"\n :modelValue=\"!isDisabled\"\n @update:modelValue=\"(v) => handleUpdateRow({ isDisabled: !v })\" />\n\n <!-- Name -->\n <DataTableCell>\n <CodeInput\n :aria-label=\"`${label} Key`\"\n disableCloseBrackets\n :disabled=\"data.isReadonly\"\n disableEnter\n disableTabIndent\n :environment=\"environment\"\n lineWrapping\n :modelValue=\"name\"\n placeholder=\"Key\"\n :required=\"Boolean(data.isRequired)\"\n @selectVariable=\"(v: string) => handleUpdateRow({ name: v })\"\n @update:modelValue=\"(v) => handleUpdateRow({ name: v })\" />\n </DataTableCell>\n\n <!-- Value -->\n <DataTableCell>\n <CodeInput\n :aria-label=\"`${label} Value`\"\n class=\"pr-6 group-hover:pr-10 group-has-[.cm-focused]:pr-10\"\n :default=\"defaultValue\"\n disableCloseBrackets\n :disabled=\"data.isReadonly\"\n disableEnter\n disableTabIndent\n :enum=\"enumValue\"\n :environment=\"environment\"\n :examples=\"\n data.schema?.examples?.map((example) => String(example)) ?? []\n \"\n :linethrough=\"data.isOverridden\"\n lineWrapping\n :max=\"maximumValue\"\n :min=\"minimumValue\"\n :modelValue=\"displayValue\"\n placeholder=\"Value\"\n :type=\"typeValue\"\n @update:modelValue=\"(v) => handleUpdateRow({ value: v })\">\n <template #icon>\n <ScalarButton\n v-if=\"\n Boolean(data.name || value) &&\n !data.isRequired &&\n data.isReadonly !== true\n \"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 hidden h-fit rounded p-1 group-hover:flex group-has-[.cm-focused]:flex\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"emit('deleteRow')\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n\n <ScalarIconButton\n v-if=\"data.globalRoute !== undefined\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 h-fit\"\n :icon=\"ScalarIconGlobe\"\n label=\"Global cookies are shared across the whole workspace. Click to navigate.\"\n size=\"xs\"\n tooltip=\"top\"\n variant=\"ghost\"\n @click=\"emit('navigate', data.globalRoute)\" />\n\n <RequestTableTooltip\n v-if=\"data.isReadonly\"\n description=\"This is a readonly property and you can not modify it! If you want to change it you have to override it or disable it using the checkbox\"\n :value=\"null\" />\n <RequestTableTooltip\n v-else-if=\"data.schema\"\n :description=\"data.description\"\n :schema=\"data.schema\"\n :value />\n </template>\n </CodeInput>\n </DataTableCell>\n\n <!-- File upload -->\n <DataTableCell\n v-if=\"showUploadButton\"\n class=\"group/upload flex items-center justify-center whitespace-nowrap\">\n <template v-if=\"isFile\">\n <div\n class=\"text-c-2 filemask flex w-full max-w-[100%] items-center justify-center overflow-hidden p-1\">\n <span>{{ displayValue }}</span>\n </div>\n <button\n class=\"bg-b-2 centered-x centered-y absolute hidden w-[calc(100%_-_8px)] rounded p-0.5 text-center text-xs font-medium group-hover/upload:block\"\n type=\"button\"\n @click=\"emit('removeFile')\">\n Delete\n </button>\n </template>\n <template v-else>\n <div class=\"p-0.5\">\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 h-fit border-0 py-px shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"emit('uploadFile')\">\n <span>Select File</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </div>\n </template>\n </DataTableCell>\n </DataTableRow>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"RequestTableRow.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton, ScalarIcon, ScalarIconButton } from '@scalar/components'\nimport { ScalarIconGlobe, ScalarIconTrash } from '@scalar/icons'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n ParameterObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { validateParameter } from '@/v2/blocks/request-block/helpers/validate-parameter'\nimport { CodeInput } from '@/v2/components/code-input'\nimport {\n DataTableCell,\n DataTableCheckbox,\n DataTableRow,\n} from '@/v2/components/data-table'\n\nimport RequestTableTooltip from './RequestTableTooltip.vue'\n\nexport type TableRow = {\n /** The parameter or field name/key */\n name: string\n /** The parameter value, can be a string, file, or null */\n value: string | File | null\n /** Optional description for the parameter */\n description?: string\n /** Optional route for global parameters (e.g., cookies shared across workspace) */\n globalRoute?: ApiReferenceEvents['ui:navigate']\n /** Whether the parameter is disabled/inactive */\n isDisabled?: boolean\n /** OpenAPI schema object with type, validation rules, examples, etc. */\n schema?: SchemaObject\n /** Whether the parameter is required */\n isRequired?: boolean\n /**\n * Whether the parameter is readonly and can not be modifies directly\n * User can still override the parameter which is going to show up with the linethrough style\n */\n isReadonly?: boolean\n /** Whether the parameter is overridden later on */\n isOverridden?: boolean\n /** Track the original parameter so we can update it */\n originalParameter?: ParameterObject\n}\n\nconst {\n data,\n environment,\n hasCheckboxDisabled,\n invalidParams,\n showUploadButton,\n} = defineProps<{\n data: TableRow\n hasCheckboxDisabled?: boolean\n invalidParams?: Set<string>\n label?: string\n environment: XScalarEnvironment\n showUploadButton?: boolean\n}>()\n\nconst emit = defineEmits<{\n (\n e: 'upsertRow',\n payload: { name: string; value: string | File; isDisabled: boolean },\n ): void\n (e: 'deleteRow'): void\n (e: 'uploadFile'): void\n (e: 'removeFile'): void\n (e: 'navigate', route: NonNullable<TableRow['globalRoute']>): void\n}>()\n\n/**\n * Track local state for the row\n *\n * Now this is required because of the way we get default values from the schema.\n * If we have a default value in data.value, then we update isDisabled to true. We lose the default value since now\n * we have an example where value: ''. This is why we need to track the local state and update all of the params at the\n * same time.\n */\nconst name = ref<string>(data.name ?? '')\nconst value = ref<string | File>(unpackProxyObject(data.value) ?? '')\nconst isDisabled = ref<boolean>(data.isDisabled ?? false)\n\n// Keep the above state synced with the data prop\nwatch(\n () => data.name,\n (newName) => (name.value = newName ?? ''),\n)\nwatch(\n () => data.value,\n (newValue) => (value.value = unpackProxyObject(newValue) ?? ''),\n)\nwatch(\n () => data.isDisabled,\n (newIsDisabled) => (isDisabled.value = newIsDisabled ?? false),\n)\n\n/** Check if the value is a File instance */\nconst isFile = computed(() => value.value instanceof File)\n\n/** Display value handles File instances and shows filename instead */\nconst displayValue = computed(\n () =>\n (isFile.value\n ? getFileName(value.value as File)\n : (value.value as string)) ?? '',\n)\n\nconst defaultValue = computed(() => data.schema?.default as string)\n\n/** See if we can extract enum values from the schema */\nconst enumValue = computed<string[]>(() => {\n if (!data.schema) {\n return []\n }\n\n // Grab the enum from the schema\n if (data.schema.enum) {\n return data.schema.enum.map((item) => String(item))\n }\n\n // Grab the enum from the items schema\n if ('items' in data.schema) {\n const resolved = resolve.schema(data.schema.items)\n if (resolved?.enum) {\n return resolved.enum.map((item) => String(item))\n }\n }\n\n return []\n})\n\nconst minimumValue = computed(() =>\n data.schema && 'minimum' in data.schema ? data.schema.minimum : undefined,\n)\nconst maximumValue = computed(() =>\n data.schema && 'maximum' in data.schema ? data.schema.maximum : undefined,\n)\nconst typeValue = computed(() =>\n data.schema && 'type' in data.schema ? data.schema.type : undefined,\n)\n\nconst validationResult = computed(() =>\n validateParameter(data.schema, value.value),\n)\n\n/** Handle row updates while preserving existing properties */\nconst handleUpdateRow = (\n payload: Partial<{ name: string; value: string; isDisabled: boolean }>,\n): void => {\n // Update our local state\n if (payload.name !== undefined) {\n name.value = payload.name\n }\n if (payload.value !== undefined) {\n value.value = payload.value\n }\n\n // Is disabled should always be false unless you explicitly set it to true\n isDisabled.value = payload.isDisabled ?? false\n\n // Emit all of the local state\n emit('upsertRow', {\n name: name.value,\n value: value.value,\n isDisabled: isDisabled.value,\n })\n}\n</script>\n\n<template>\n <DataTableRow\n :id=\"data.name\"\n :class=\"{\n alert: validationResult.ok === false,\n error: validationResult.ok === false && invalidParams?.has(data.name),\n }\">\n <DataTableCheckbox\n class=\"!border-r\"\n :disabled=\"hasCheckboxDisabled ?? false\"\n :modelValue=\"!isDisabled\"\n @update:modelValue=\"(v) => handleUpdateRow({ isDisabled: !v })\" />\n\n <!-- Name -->\n <DataTableCell>\n <CodeInput\n :aria-label=\"`${label} Key`\"\n disableCloseBrackets\n :disabled=\"data.isReadonly\"\n disableEnter\n disableTabIndent\n :environment=\"environment\"\n lineWrapping\n :modelValue=\"name\"\n placeholder=\"Key\"\n :required=\"Boolean(data.isRequired)\"\n @navigate=\"(route) => emit('navigate', route)\"\n @selectVariable=\"(v: string) => handleUpdateRow({ name: v })\"\n @update:modelValue=\"(v) => handleUpdateRow({ name: v })\" />\n </DataTableCell>\n\n <!-- Value -->\n <DataTableCell>\n <CodeInput\n :aria-label=\"`${label} Value`\"\n class=\"pr-6 group-hover:pr-10 group-has-[.cm-focused]:pr-10\"\n :default=\"defaultValue\"\n disableCloseBrackets\n :disabled=\"data.isReadonly\"\n disableEnter\n disableTabIndent\n :enum=\"enumValue\"\n :environment=\"environment\"\n :examples=\"\n data.schema?.examples?.map((example) => String(example)) ?? []\n \"\n :linethrough=\"data.isOverridden\"\n lineWrapping\n :max=\"maximumValue\"\n :min=\"minimumValue\"\n :modelValue=\"displayValue\"\n placeholder=\"Value\"\n :type=\"typeValue\"\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ value: v })\">\n <template #icon>\n <ScalarButton\n v-if=\"\n Boolean(data.name || value) &&\n !data.isRequired &&\n data.isReadonly !== true\n \"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 hidden h-fit rounded p-1 group-hover:flex group-has-[.cm-focused]:flex\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"emit('deleteRow')\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n\n <ScalarIconButton\n v-if=\"data.globalRoute !== undefined\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 h-fit\"\n :icon=\"ScalarIconGlobe\"\n label=\"Global cookies are shared across the whole workspace. Click to navigate.\"\n size=\"xs\"\n tooltip=\"top\"\n variant=\"ghost\"\n @click=\"emit('navigate', data.globalRoute)\" />\n\n <RequestTableTooltip\n v-if=\"data.isReadonly\"\n description=\"This is a readonly property and you can not modify it! If you want to change it you have to override it or disable it using the checkbox\"\n :value=\"null\" />\n <RequestTableTooltip\n v-else-if=\"data.schema\"\n :description=\"data.description\"\n :schema=\"data.schema\"\n :value />\n </template>\n </CodeInput>\n </DataTableCell>\n\n <!-- File upload -->\n <DataTableCell\n v-if=\"showUploadButton\"\n class=\"group/upload flex items-center justify-center whitespace-nowrap\">\n <template v-if=\"isFile\">\n <div\n class=\"text-c-2 filemask flex w-full max-w-[100%] items-center justify-center overflow-hidden p-1\">\n <span>{{ displayValue }}</span>\n </div>\n <button\n class=\"bg-b-2 centered-x centered-y absolute hidden w-[calc(100%_-_8px)] rounded p-0.5 text-center text-xs font-medium group-hover/upload:block\"\n type=\"button\"\n @click=\"emit('removeFile')\">\n Delete\n </button>\n </template>\n <template v-else>\n <div class=\"p-0.5\">\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 h-fit border-0 py-px shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"emit('uploadFile')\">\n <span>Select File</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </div>\n </template>\n </DataTableCell>\n </DataTableRow>\n</template>\n"],"mappings":""}
|
|
@@ -106,8 +106,9 @@ var RequestTableRow_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ *
|
|
|
106
106
|
modelValue: name.value,
|
|
107
107
|
placeholder: "Key",
|
|
108
108
|
required: Boolean(__props.data.isRequired),
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
onNavigate: _cache[1] || (_cache[1] = (route) => emit("navigate", route)),
|
|
110
|
+
onSelectVariable: _cache[2] || (_cache[2] = (v) => handleUpdateRow({ name: v })),
|
|
111
|
+
"onUpdate:modelValue": _cache[3] || (_cache[3] = (v) => handleUpdateRow({ name: v }))
|
|
111
112
|
}, null, 8, [
|
|
112
113
|
"aria-label",
|
|
113
114
|
"disabled",
|
|
@@ -136,7 +137,8 @@ var RequestTableRow_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ *
|
|
|
136
137
|
modelValue: displayValue.value,
|
|
137
138
|
placeholder: "Value",
|
|
138
139
|
type: typeValue.value,
|
|
139
|
-
|
|
140
|
+
onNavigate: _cache[6] || (_cache[6] = (route) => emit("navigate", route)),
|
|
141
|
+
"onUpdate:modelValue": _cache[7] || (_cache[7] = (v) => handleUpdateRow({ value: v }))
|
|
140
142
|
}, {
|
|
141
143
|
icon: withCtx(() => [
|
|
142
144
|
Boolean(__props.data.name || value.value) && !__props.data.isRequired && __props.data.isReadonly !== true ? (openBlock(), createBlock(unref(ScalarButton), {
|
|
@@ -144,7 +146,7 @@ var RequestTableRow_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ *
|
|
|
144
146
|
class: "text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 hidden h-fit rounded p-1 group-hover:flex group-has-[.cm-focused]:flex",
|
|
145
147
|
size: "sm",
|
|
146
148
|
variant: "ghost",
|
|
147
|
-
onClick: _cache[
|
|
149
|
+
onClick: _cache[4] || (_cache[4] = ($event) => emit("deleteRow"))
|
|
148
150
|
}, {
|
|
149
151
|
default: withCtx(() => [createVNode(unref(ScalarIconTrash), { class: "size-3.5" })]),
|
|
150
152
|
_: 1
|
|
@@ -157,7 +159,7 @@ var RequestTableRow_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ *
|
|
|
157
159
|
size: "xs",
|
|
158
160
|
tooltip: "top",
|
|
159
161
|
variant: "ghost",
|
|
160
|
-
onClick: _cache[
|
|
162
|
+
onClick: _cache[5] || (_cache[5] = ($event) => emit("navigate", __props.data.globalRoute))
|
|
161
163
|
}, null, 8, ["icon"])) : createCommentVNode("", true),
|
|
162
164
|
__props.data.isReadonly ? (openBlock(), createBlock(RequestTableTooltip_default, {
|
|
163
165
|
key: 2,
|
|
@@ -197,14 +199,14 @@ var RequestTableRow_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ *
|
|
|
197
199
|
default: withCtx(() => [isFile.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createElementVNode("div", _hoisted_1, [createElementVNode("span", null, toDisplayString(displayValue.value), 1)]), createElementVNode("button", {
|
|
198
200
|
class: "bg-b-2 centered-x centered-y absolute hidden w-[calc(100%_-_8px)] rounded p-0.5 text-center text-xs font-medium group-hover/upload:block",
|
|
199
201
|
type: "button",
|
|
200
|
-
onClick: _cache[
|
|
202
|
+
onClick: _cache[8] || (_cache[8] = ($event) => emit("removeFile"))
|
|
201
203
|
}, " Delete ")], 64)) : (openBlock(), createElementBlock("div", _hoisted_2, [createVNode(unref(ScalarButton), {
|
|
202
204
|
class: "bg-b-2 hover:bg-b-3 text-c-2 h-fit border-0 py-px shadow-none",
|
|
203
205
|
size: "sm",
|
|
204
206
|
variant: "outlined",
|
|
205
|
-
onClick: _cache[
|
|
207
|
+
onClick: _cache[9] || (_cache[9] = ($event) => emit("uploadFile"))
|
|
206
208
|
}, {
|
|
207
|
-
default: withCtx(() => [_cache[
|
|
209
|
+
default: withCtx(() => [_cache[10] || (_cache[10] = createElementVNode("span", null, "Select File", -1)), createVNode(unref(ScalarIcon), {
|
|
208
210
|
class: "ml-1",
|
|
209
211
|
icon: "Upload",
|
|
210
212
|
size: "xs",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RequestTableRow.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton, ScalarIcon, ScalarIconButton } from '@scalar/components'\nimport { ScalarIconGlobe, ScalarIconTrash } from '@scalar/icons'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n ParameterObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { validateParameter } from '@/v2/blocks/request-block/helpers/validate-parameter'\nimport { CodeInput } from '@/v2/components/code-input'\nimport {\n DataTableCell,\n DataTableCheckbox,\n DataTableRow,\n} from '@/v2/components/data-table'\n\nimport RequestTableTooltip from './RequestTableTooltip.vue'\n\nexport type TableRow = {\n /** The parameter or field name/key */\n name: string\n /** The parameter value, can be a string, file, or null */\n value: string | File | null\n /** Optional description for the parameter */\n description?: string\n /** Optional route for global parameters (e.g., cookies shared across workspace) */\n globalRoute?: ApiReferenceEvents['ui:navigate']\n /** Whether the parameter is disabled/inactive */\n isDisabled?: boolean\n /** OpenAPI schema object with type, validation rules, examples, etc. */\n schema?: SchemaObject\n /** Whether the parameter is required */\n isRequired?: boolean\n /**\n * Whether the parameter is readonly and can not be modifies directly\n * User can still override the parameter which is going to show up with the linethrough style\n */\n isReadonly?: boolean\n /** Whether the parameter is overridden later on */\n isOverridden?: boolean\n /** Track the original parameter so we can update it */\n originalParameter?: ParameterObject\n}\n\nconst {\n data,\n environment,\n hasCheckboxDisabled,\n invalidParams,\n showUploadButton,\n} = defineProps<{\n data: TableRow\n hasCheckboxDisabled?: boolean\n invalidParams?: Set<string>\n label?: string\n environment: XScalarEnvironment\n showUploadButton?: boolean\n}>()\n\nconst emit = defineEmits<{\n (\n e: 'upsertRow',\n payload: { name: string; value: string | File; isDisabled: boolean },\n ): void\n (e: 'deleteRow'): void\n (e: 'uploadFile'): void\n (e: 'removeFile'): void\n (e: 'navigate', route: NonNullable<TableRow['globalRoute']>): void\n}>()\n\n/**\n * Track local state for the row\n *\n * Now this is required because of the way we get default values from the schema.\n * If we have a default value in data.value, then we update isDisabled to true. We lose the default value since now\n * we have an example where value: ''. This is why we need to track the local state and update all of the params at the\n * same time.\n */\nconst name = ref<string>(data.name ?? '')\nconst value = ref<string | File>(unpackProxyObject(data.value) ?? '')\nconst isDisabled = ref<boolean>(data.isDisabled ?? false)\n\n// Keep the above state synced with the data prop\nwatch(\n () => data.name,\n (newName) => (name.value = newName ?? ''),\n)\nwatch(\n () => data.value,\n (newValue) => (value.value = unpackProxyObject(newValue) ?? ''),\n)\nwatch(\n () => data.isDisabled,\n (newIsDisabled) => (isDisabled.value = newIsDisabled ?? false),\n)\n\n/** Check if the value is a File instance */\nconst isFile = computed(() => value.value instanceof File)\n\n/** Display value handles File instances and shows filename instead */\nconst displayValue = computed(\n () =>\n (isFile.value\n ? getFileName(value.value as File)\n : (value.value as string)) ?? '',\n)\n\nconst defaultValue = computed(() => data.schema?.default as string)\n\n/** See if we can extract enum values from the schema */\nconst enumValue = computed<string[]>(() => {\n if (!data.schema) {\n return []\n }\n\n // Grab the enum from the schema\n if (data.schema.enum) {\n return data.schema.enum.map((item) => String(item))\n }\n\n // Grab the enum from the items schema\n if ('items' in data.schema) {\n const resolved = resolve.schema(data.schema.items)\n if (resolved?.enum) {\n return resolved.enum.map((item) => String(item))\n }\n }\n\n return []\n})\n\nconst minimumValue = computed(() =>\n data.schema && 'minimum' in data.schema ? data.schema.minimum : undefined,\n)\nconst maximumValue = computed(() =>\n data.schema && 'maximum' in data.schema ? data.schema.maximum : undefined,\n)\nconst typeValue = computed(() =>\n data.schema && 'type' in data.schema ? data.schema.type : undefined,\n)\n\nconst validationResult = computed(() =>\n validateParameter(data.schema, value.value),\n)\n\n/** Handle row updates while preserving existing properties */\nconst handleUpdateRow = (\n payload: Partial<{ name: string; value: string; isDisabled: boolean }>,\n): void => {\n // Update our local state\n if (payload.name !== undefined) {\n name.value = payload.name\n }\n if (payload.value !== undefined) {\n value.value = payload.value\n }\n\n // Is disabled should always be false unless you explicitly set it to true\n isDisabled.value = payload.isDisabled ?? false\n\n // Emit all of the local state\n emit('upsertRow', {\n name: name.value,\n value: value.value,\n isDisabled: isDisabled.value,\n })\n}\n</script>\n\n<template>\n <DataTableRow\n :id=\"data.name\"\n :class=\"{\n alert: validationResult.ok === false,\n error: validationResult.ok === false && invalidParams?.has(data.name),\n }\">\n <DataTableCheckbox\n class=\"!border-r\"\n :disabled=\"hasCheckboxDisabled ?? false\"\n :modelValue=\"!isDisabled\"\n @update:modelValue=\"(v) => handleUpdateRow({ isDisabled: !v })\" />\n\n <!-- Name -->\n <DataTableCell>\n <CodeInput\n :aria-label=\"`${label} Key`\"\n disableCloseBrackets\n :disabled=\"data.isReadonly\"\n disableEnter\n disableTabIndent\n :environment=\"environment\"\n lineWrapping\n :modelValue=\"name\"\n placeholder=\"Key\"\n :required=\"Boolean(data.isRequired)\"\n @selectVariable=\"(v: string) => handleUpdateRow({ name: v })\"\n @update:modelValue=\"(v) => handleUpdateRow({ name: v })\" />\n </DataTableCell>\n\n <!-- Value -->\n <DataTableCell>\n <CodeInput\n :aria-label=\"`${label} Value`\"\n class=\"pr-6 group-hover:pr-10 group-has-[.cm-focused]:pr-10\"\n :default=\"defaultValue\"\n disableCloseBrackets\n :disabled=\"data.isReadonly\"\n disableEnter\n disableTabIndent\n :enum=\"enumValue\"\n :environment=\"environment\"\n :examples=\"\n data.schema?.examples?.map((example) => String(example)) ?? []\n \"\n :linethrough=\"data.isOverridden\"\n lineWrapping\n :max=\"maximumValue\"\n :min=\"minimumValue\"\n :modelValue=\"displayValue\"\n placeholder=\"Value\"\n :type=\"typeValue\"\n @update:modelValue=\"(v) => handleUpdateRow({ value: v })\">\n <template #icon>\n <ScalarButton\n v-if=\"\n Boolean(data.name || value) &&\n !data.isRequired &&\n data.isReadonly !== true\n \"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 hidden h-fit rounded p-1 group-hover:flex group-has-[.cm-focused]:flex\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"emit('deleteRow')\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n\n <ScalarIconButton\n v-if=\"data.globalRoute !== undefined\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 h-fit\"\n :icon=\"ScalarIconGlobe\"\n label=\"Global cookies are shared across the whole workspace. Click to navigate.\"\n size=\"xs\"\n tooltip=\"top\"\n variant=\"ghost\"\n @click=\"emit('navigate', data.globalRoute)\" />\n\n <RequestTableTooltip\n v-if=\"data.isReadonly\"\n description=\"This is a readonly property and you can not modify it! If you want to change it you have to override it or disable it using the checkbox\"\n :value=\"null\" />\n <RequestTableTooltip\n v-else-if=\"data.schema\"\n :description=\"data.description\"\n :schema=\"data.schema\"\n :value />\n </template>\n </CodeInput>\n </DataTableCell>\n\n <!-- File upload -->\n <DataTableCell\n v-if=\"showUploadButton\"\n class=\"group/upload flex items-center justify-center whitespace-nowrap\">\n <template v-if=\"isFile\">\n <div\n class=\"text-c-2 filemask flex w-full max-w-[100%] items-center justify-center overflow-hidden p-1\">\n <span>{{ displayValue }}</span>\n </div>\n <button\n class=\"bg-b-2 centered-x centered-y absolute hidden w-[calc(100%_-_8px)] rounded p-0.5 text-center text-xs font-medium group-hover/upload:block\"\n type=\"button\"\n @click=\"emit('removeFile')\">\n Delete\n </button>\n </template>\n <template v-else>\n <div class=\"p-0.5\">\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 h-fit border-0 py-px shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"emit('uploadFile')\">\n <span>Select File</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </div>\n </template>\n </DataTableCell>\n </DataTableRow>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"RequestTableRow.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton, ScalarIcon, ScalarIconButton } from '@scalar/components'\nimport { ScalarIconGlobe, ScalarIconTrash } from '@scalar/icons'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n ParameterObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { validateParameter } from '@/v2/blocks/request-block/helpers/validate-parameter'\nimport { CodeInput } from '@/v2/components/code-input'\nimport {\n DataTableCell,\n DataTableCheckbox,\n DataTableRow,\n} from '@/v2/components/data-table'\n\nimport RequestTableTooltip from './RequestTableTooltip.vue'\n\nexport type TableRow = {\n /** The parameter or field name/key */\n name: string\n /** The parameter value, can be a string, file, or null */\n value: string | File | null\n /** Optional description for the parameter */\n description?: string\n /** Optional route for global parameters (e.g., cookies shared across workspace) */\n globalRoute?: ApiReferenceEvents['ui:navigate']\n /** Whether the parameter is disabled/inactive */\n isDisabled?: boolean\n /** OpenAPI schema object with type, validation rules, examples, etc. */\n schema?: SchemaObject\n /** Whether the parameter is required */\n isRequired?: boolean\n /**\n * Whether the parameter is readonly and can not be modifies directly\n * User can still override the parameter which is going to show up with the linethrough style\n */\n isReadonly?: boolean\n /** Whether the parameter is overridden later on */\n isOverridden?: boolean\n /** Track the original parameter so we can update it */\n originalParameter?: ParameterObject\n}\n\nconst {\n data,\n environment,\n hasCheckboxDisabled,\n invalidParams,\n showUploadButton,\n} = defineProps<{\n data: TableRow\n hasCheckboxDisabled?: boolean\n invalidParams?: Set<string>\n label?: string\n environment: XScalarEnvironment\n showUploadButton?: boolean\n}>()\n\nconst emit = defineEmits<{\n (\n e: 'upsertRow',\n payload: { name: string; value: string | File; isDisabled: boolean },\n ): void\n (e: 'deleteRow'): void\n (e: 'uploadFile'): void\n (e: 'removeFile'): void\n (e: 'navigate', route: NonNullable<TableRow['globalRoute']>): void\n}>()\n\n/**\n * Track local state for the row\n *\n * Now this is required because of the way we get default values from the schema.\n * If we have a default value in data.value, then we update isDisabled to true. We lose the default value since now\n * we have an example where value: ''. This is why we need to track the local state and update all of the params at the\n * same time.\n */\nconst name = ref<string>(data.name ?? '')\nconst value = ref<string | File>(unpackProxyObject(data.value) ?? '')\nconst isDisabled = ref<boolean>(data.isDisabled ?? false)\n\n// Keep the above state synced with the data prop\nwatch(\n () => data.name,\n (newName) => (name.value = newName ?? ''),\n)\nwatch(\n () => data.value,\n (newValue) => (value.value = unpackProxyObject(newValue) ?? ''),\n)\nwatch(\n () => data.isDisabled,\n (newIsDisabled) => (isDisabled.value = newIsDisabled ?? false),\n)\n\n/** Check if the value is a File instance */\nconst isFile = computed(() => value.value instanceof File)\n\n/** Display value handles File instances and shows filename instead */\nconst displayValue = computed(\n () =>\n (isFile.value\n ? getFileName(value.value as File)\n : (value.value as string)) ?? '',\n)\n\nconst defaultValue = computed(() => data.schema?.default as string)\n\n/** See if we can extract enum values from the schema */\nconst enumValue = computed<string[]>(() => {\n if (!data.schema) {\n return []\n }\n\n // Grab the enum from the schema\n if (data.schema.enum) {\n return data.schema.enum.map((item) => String(item))\n }\n\n // Grab the enum from the items schema\n if ('items' in data.schema) {\n const resolved = resolve.schema(data.schema.items)\n if (resolved?.enum) {\n return resolved.enum.map((item) => String(item))\n }\n }\n\n return []\n})\n\nconst minimumValue = computed(() =>\n data.schema && 'minimum' in data.schema ? data.schema.minimum : undefined,\n)\nconst maximumValue = computed(() =>\n data.schema && 'maximum' in data.schema ? data.schema.maximum : undefined,\n)\nconst typeValue = computed(() =>\n data.schema && 'type' in data.schema ? data.schema.type : undefined,\n)\n\nconst validationResult = computed(() =>\n validateParameter(data.schema, value.value),\n)\n\n/** Handle row updates while preserving existing properties */\nconst handleUpdateRow = (\n payload: Partial<{ name: string; value: string; isDisabled: boolean }>,\n): void => {\n // Update our local state\n if (payload.name !== undefined) {\n name.value = payload.name\n }\n if (payload.value !== undefined) {\n value.value = payload.value\n }\n\n // Is disabled should always be false unless you explicitly set it to true\n isDisabled.value = payload.isDisabled ?? false\n\n // Emit all of the local state\n emit('upsertRow', {\n name: name.value,\n value: value.value,\n isDisabled: isDisabled.value,\n })\n}\n</script>\n\n<template>\n <DataTableRow\n :id=\"data.name\"\n :class=\"{\n alert: validationResult.ok === false,\n error: validationResult.ok === false && invalidParams?.has(data.name),\n }\">\n <DataTableCheckbox\n class=\"!border-r\"\n :disabled=\"hasCheckboxDisabled ?? false\"\n :modelValue=\"!isDisabled\"\n @update:modelValue=\"(v) => handleUpdateRow({ isDisabled: !v })\" />\n\n <!-- Name -->\n <DataTableCell>\n <CodeInput\n :aria-label=\"`${label} Key`\"\n disableCloseBrackets\n :disabled=\"data.isReadonly\"\n disableEnter\n disableTabIndent\n :environment=\"environment\"\n lineWrapping\n :modelValue=\"name\"\n placeholder=\"Key\"\n :required=\"Boolean(data.isRequired)\"\n @navigate=\"(route) => emit('navigate', route)\"\n @selectVariable=\"(v: string) => handleUpdateRow({ name: v })\"\n @update:modelValue=\"(v) => handleUpdateRow({ name: v })\" />\n </DataTableCell>\n\n <!-- Value -->\n <DataTableCell>\n <CodeInput\n :aria-label=\"`${label} Value`\"\n class=\"pr-6 group-hover:pr-10 group-has-[.cm-focused]:pr-10\"\n :default=\"defaultValue\"\n disableCloseBrackets\n :disabled=\"data.isReadonly\"\n disableEnter\n disableTabIndent\n :enum=\"enumValue\"\n :environment=\"environment\"\n :examples=\"\n data.schema?.examples?.map((example) => String(example)) ?? []\n \"\n :linethrough=\"data.isOverridden\"\n lineWrapping\n :max=\"maximumValue\"\n :min=\"minimumValue\"\n :modelValue=\"displayValue\"\n placeholder=\"Value\"\n :type=\"typeValue\"\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ value: v })\">\n <template #icon>\n <ScalarButton\n v-if=\"\n Boolean(data.name || value) &&\n !data.isRequired &&\n data.isReadonly !== true\n \"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 hidden h-fit rounded p-1 group-hover:flex group-has-[.cm-focused]:flex\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"emit('deleteRow')\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n\n <ScalarIconButton\n v-if=\"data.globalRoute !== undefined\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 h-fit\"\n :icon=\"ScalarIconGlobe\"\n label=\"Global cookies are shared across the whole workspace. Click to navigate.\"\n size=\"xs\"\n tooltip=\"top\"\n variant=\"ghost\"\n @click=\"emit('navigate', data.globalRoute)\" />\n\n <RequestTableTooltip\n v-if=\"data.isReadonly\"\n description=\"This is a readonly property and you can not modify it! If you want to change it you have to override it or disable it using the checkbox\"\n :value=\"null\" />\n <RequestTableTooltip\n v-else-if=\"data.schema\"\n :description=\"data.description\"\n :schema=\"data.schema\"\n :value />\n </template>\n </CodeInput>\n </DataTableCell>\n\n <!-- File upload -->\n <DataTableCell\n v-if=\"showUploadButton\"\n class=\"group/upload flex items-center justify-center whitespace-nowrap\">\n <template v-if=\"isFile\">\n <div\n class=\"text-c-2 filemask flex w-full max-w-[100%] items-center justify-center overflow-hidden p-1\">\n <span>{{ displayValue }}</span>\n </div>\n <button\n class=\"bg-b-2 centered-x centered-y absolute hidden w-[calc(100%_-_8px)] rounded p-0.5 text-center text-xs font-medium group-hover/upload:block\"\n type=\"button\"\n @click=\"emit('removeFile')\">\n Delete\n </button>\n </template>\n <template v-else>\n <div class=\"p-0.5\">\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 h-fit border-0 py-px shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"emit('uploadFile')\">\n <span>Select File</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </div>\n </template>\n </DataTableCell>\n </DataTableRow>\n</template>\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { extractFilename } from "./extract-filename.js";
|
|
2
|
-
import
|
|
2
|
+
import MimeType 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
|
|
11
|
+
const mimeType = contentType?.value ? new MimeType(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,
|
|
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"}
|
|
@@ -101,9 +101,12 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
|
|
|
101
101
|
serializeValue: (value: CodeInputModelValue) => string;
|
|
102
102
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
103
103
|
submit: (value: string) => any;
|
|
104
|
-
redirectToEnvironment: () => any;
|
|
105
104
|
"update:modelValue": (value: string) => any;
|
|
106
105
|
blur: (value: string) => any;
|
|
106
|
+
navigate: (route: {
|
|
107
|
+
page: "document";
|
|
108
|
+
path: "environment";
|
|
109
|
+
}) => any;
|
|
107
110
|
}, string, import("vue").PublicProps, Readonly<{
|
|
108
111
|
modelValue: CodeInputModelValue;
|
|
109
112
|
/** Environment for variable substitution. Pass undefined to disable environment variables */
|
|
@@ -160,9 +163,12 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
|
|
|
160
163
|
linethrough?: boolean;
|
|
161
164
|
}> & Readonly<{
|
|
162
165
|
onSubmit?: ((value: string) => any) | undefined;
|
|
163
|
-
onRedirectToEnvironment?: (() => any) | undefined;
|
|
164
166
|
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
165
167
|
onBlur?: ((value: string) => any) | undefined;
|
|
168
|
+
onNavigate?: ((route: {
|
|
169
|
+
page: "document";
|
|
170
|
+
path: "environment";
|
|
171
|
+
}) => any) | undefined;
|
|
166
172
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, {
|
|
167
173
|
warning?: (props: {}) => any;
|
|
168
174
|
} & {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeInput.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/components/code-input/CodeInput.vue"],"names":[],"mappings":"AA4pBA,OAAO,EAIL,KAAK,kBAAkB,EACvB,KAAK,SAAS,EACf,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AAEnH,OAAO,EAAyC,KAAK,GAAG,EAAE,MAAM,KAAK,CAAA;AAIrE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAKrD,MAAM,MAAM,mBAAmB,GAC3B,MAAM,GACN,MAAM,GACN,OAAO,GACP,KAAK,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,GAChC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAE3B;;;;;;;;;;;;;;;;;;;;;;;GAuBG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAKzC,QAAA,MAAM,YAAY;gBAEJ,mBAAmB;IAC/B,6FAA6F;iBAChF,kBAAkB,GAAG,SAAS;IAC3C,mEAAmE;WAC5D,MAAM,GAAG,MAAM,EAAE;IACxB,sCAAsC;eAC3B,OAAO;IAClB,yBAAyB;YACjB,OAAO;IACf,kDAAkD;aACzC,YAAY;IACrB,mDAAmD;WAC5C,MAAM,EAAE;IACf,2CAA2C;eAChC,MAAM,EAAE;IACnB,2CAA2C;;IAE3C,2CAA2C;eAChC,OAAO;IAClB,uCAAuC;kBACzB,MAAM;IACpB,8BAA8B;eACnB,OAAO;IAClB,oCAAoC;kBACtB,OAAO;IACrB,kCAAkC;kBACpB,OAAO;IACrB,qBAAqB;WACd,OAAO;IACd,2BAA2B;mBACZ,OAAO;IACtB,+BAA+B;eACpB,kBAAkB;IAC7B,uCAAuC;iBAC1B,SAAS,EAAE;IACxB,sCAAsC;uBACnB,OAAO;IAC1B,wBAAwB;mBACT,OAAO;IACtB,wCAAwC;2BACjB,OAAO;IAC9B,gCAAgC;iBACnB,OAAO;IACpB,wCAAwC;oBACxB,OAAO;IACvB,sDAAsD;uBACnC,OAAO;IAC1B,mDAAmD;wBAC/B,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI;IAC3C,mDAAmD;wBAC/B,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI;IAC3C,0CAA0C;kBAC5B,OAAO;;IAyQrB;;;;OAIG;uBACgB,OAAO,GAAG,KAAK,GAAG,MAAM;;0BAxLhB,MAAM,KAAG,IAAI;0BAgBb,MAAM,KAAG,IAAI;wBAWf,MAAM,KAAG,IAAI;;;;;4BAuDT,mBAAmB,KAAG,MAAM
|
|
1
|
+
{"version":3,"file":"CodeInput.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/components/code-input/CodeInput.vue"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ import CodeInput_vue_vue_type_script_setup_true_lang_default from "./CodeInput.v
|
|
|
3
3
|
/* empty css */
|
|
4
4
|
/* empty css */
|
|
5
5
|
//#region src/v2/components/code-input/CodeInput.vue
|
|
6
|
-
var CodeInput_default = /* @__PURE__ */ _plugin_vue_export_helper_default(CodeInput_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-
|
|
6
|
+
var CodeInput_default = /* @__PURE__ */ _plugin_vue_export_helper_default(CodeInput_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-e041f4b0"]]);
|
|
7
7
|
//#endregion
|
|
8
8
|
export { CodeInput_default as default };
|
|
9
9
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeInput.vue.js","names":[],"sources":["../../../../src/v2/components/code-input/CodeInput.vue"],"sourcesContent":["<script lang=\"ts\">\nexport type CodeInputModelValue =\n | string\n | number\n | boolean\n | Array<string | number | boolean>\n | Record<string, unknown>\n\n/**\n * CodeInput\n *\n * A versatile input component that adapts its rendering based on props:\n * - Disabled mode: Read-only text display\n * - Select mode: Dropdown for enums, booleans, or examples\n * - Editor mode: CodeMirror with environment variable support\n *\n * Type `{{` to trigger environment variable autocomplete when an environment is provided.\n * It takes in any data but always will emit a string value,\n * this string should then be parsed in accordance to the schema or content type.\n *\n * @example\n * ```vue\n * <!-- Basic input with environment variables -->\n * <CodeInput v-model=\"value\" :environment=\"env\" />\n *\n * <!-- Boolean select -->\n * <CodeInput v-model=\"flag\" type=\"boolean\" />\n *\n * <!-- JSON editor with linting -->\n * <CodeInput v-model=\"data\" language=\"json\" :lint=\"true\" />\n * ```\n */\nexport default {\n inheritAttrs: false,\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { isDefined } from '@scalar/helpers/array/is-defined'\nimport {\n colorPicker as colorPickerExtension,\n useCodeMirror,\n useDropdown,\n type CodeMirrorLanguage,\n type Extension,\n} from '@scalar/use-codemirror'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { nanoid } from 'nanoid'\nimport { computed, ref, toRef, useAttrs, watch, type Ref } from 'vue'\n\nimport DataTableInputSelect from '@/v2/components/data-table/DataTableInputSelect.vue'\nimport EnvironmentVariableDropdown from '@/v2/features/environments/components/EnvironmentVariablesDropdown.vue'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nimport { backspaceCommand, pillPlugin } from './code-variable-widget'\n\ntype Props = {\n modelValue: CodeInputModelValue\n /** Environment for variable substitution. Pass undefined to disable environment variables */\n environment: XScalarEnvironment | undefined\n /** Type of the input value, affects rendering mode for booleans */\n type?: string | string[]\n /** Render as disabled text display */\n disabled?: boolean\n /** Show error styling */\n error?: boolean\n /** Layout context affects styling and behavior */\n layout?: ClientLayout\n /** Predefined enum values, triggers select mode */\n enum?: string[]\n /** Example values, triggers select mode */\n examples?: string[]\n /** Default value to show in select mode */\n default?: Props['modelValue']\n /** Allow null in boolean select options */\n nullable?: boolean\n /** Placeholder text for empty input */\n placeholder?: string\n /** Show required indicator */\n required?: boolean\n /** Enable color picker extension */\n colorPicker?: boolean\n /** Show line numbers in editor */\n lineNumbers?: boolean\n /** Enable linting */\n lint?: boolean\n /** Enable line wrapping */\n lineWrapping?: boolean\n /** CodeMirror language mode */\n language?: CodeMirrorLanguage\n /** Additional CodeMirror extensions */\n extensions?: Extension[]\n /** Disable tab key for indentation */\n disableTabIndent?: boolean\n /** Disable enter key */\n disableEnter?: boolean\n /** Disable automatic bracket closing */\n disableCloseBrackets?: boolean\n /** Emit submit event on blur */\n emitOnBlur?: boolean\n /** Enable environment variable pills */\n withVariables?: boolean\n /** Emit change event even if the value is the same */\n alwaysEmitChange?: boolean\n /** Custom change handler, prevents default emit */\n handleFieldChange?: (value: string) => void\n /** Custom submit handler, prevents default emit */\n handleFieldSubmit?: (value: string) => void\n /** Put a linethrough on the input text */\n linethrough?: boolean\n}\n\nconst {\n modelValue,\n environment,\n type,\n disabled = false,\n error = false,\n layout = 'desktop',\n enum: enumProp,\n examples,\n default: defaultProp,\n nullable = false,\n placeholder,\n required,\n colorPicker = false,\n lineNumbers = false,\n lint = false,\n lineWrapping = false,\n language,\n extensions = [],\n disableTabIndent = false,\n disableEnter = false,\n disableCloseBrackets = false,\n emitOnBlur = true,\n alwaysEmitChange = false,\n withVariables = true,\n handleFieldChange,\n handleFieldSubmit,\n} = defineProps<Props>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n 'submit': [value: string]\n 'blur': [value: string]\n 'redirectToEnvironment': []\n}>()\n\n// ---------------------------------------------------------------------------\n// Component identity and focus state\n\nconst attrs = useAttrs() as { id?: string }\nconst componentId = attrs.id || `id-${nanoid()}`\nconst isFocused = ref(false)\n\n// ---------------------------------------------------------------------------\n// Rendering mode detection\n\n/**\n * Determines if we should render a select dropdown for boolean types.\n */\nconst isBooleanMode = computed((): boolean => {\n if (enumProp?.length) {\n return false\n }\n return type === 'boolean' || (Array.isArray(type) && type.includes('boolean'))\n})\n\n/**\n * Options for boolean select mode.\n */\nconst booleanOptions = computed((): string[] =>\n nullable ? ['true', 'false', 'null'] : ['true', 'false'],\n)\n\n/**\n * Default type when dealing with type arrays.\n * Finds the first non-null type.\n */\nconst defaultType = computed((): string | undefined => {\n if (Array.isArray(type)) {\n return type.find((t) => t !== 'null') ?? 'string'\n }\n return type\n})\n\n// ---------------------------------------------------------------------------\n// Event handlers\n\n/**\n * Handles value changes during typing.\n */\nconst handleChange = (value: string): void => {\n if (!alwaysEmitChange && value === serializeValue(modelValue)) {\n return\n }\n\n // Use custom handler or emit update\n if (handleFieldChange) {\n handleFieldChange(value)\n } else {\n emit('update:modelValue', value)\n }\n}\n\n/**\n * Handles form submission (enter key or blur with emitOnBlur).\n */\nconst handleSubmit = (value: string): void => {\n if (handleFieldSubmit) {\n handleFieldSubmit(value)\n } else {\n emit('submit', value)\n }\n}\n\n/**\n * Handles input blur event.\n */\nconst handleBlur = (value: string): void => {\n isFocused.value = false\n\n if (emitOnBlur && modelValue) {\n handleSubmit(value)\n }\n\n emit('blur', value)\n}\n\n/**\n * Handles model value updates from select components.\n */\nconst handleSelectChange = (value: string): void =>\n emit('update:modelValue', value)\n\n// ---------------------------------------------------------------------------\n// CodeMirror setup\n\n/**\n * Build extensions array.\n * Note: Extensions are not reactive after initialization.\n */\nconst buildExtensions = (): Extension[] => {\n const extensionsList: Extension[] = [...extensions]\n\n if (colorPicker) {\n extensionsList.push(colorPickerExtension)\n }\n\n return extensionsList\n}\n\n/**\n * Reactive pill plugin for environment variable visualization.\n */\nconst pillPluginExtension = computed(() =>\n pillPlugin({\n environment,\n isReadOnly: layout === 'modal',\n }),\n)\n\n/**\n * Combined extensions for CodeMirror.\n */\nconst codeMirrorExtensions = computed((): Extension[] => [\n ...buildExtensions(),\n pillPluginExtension.value,\n backspaceCommand,\n])\n\nconst codeMirrorRef: Ref<HTMLDivElement | null> = ref(null)\n\n/** Converts the model value to a string for CodeMirror */\nconst serializeValue = (value: CodeInputModelValue): string => {\n if (typeof value === 'string') {\n return value\n }\n return JSON.stringify(value)\n}\n\nconst { codeMirror } = useCodeMirror({\n content: toRef(() => serializeValue(modelValue)),\n onChange: (value) => {\n handleChange(value)\n updateDropdownVisibility()\n },\n onFocus: () => {\n isFocused.value = true\n },\n onBlur: handleBlur,\n codeMirrorRef,\n disableTabIndent: toRef(() => disableTabIndent),\n disableEnter: toRef(() => disableEnter),\n disableCloseBrackets: toRef(() => disableCloseBrackets),\n lineNumbers: toRef(() => lineNumbers),\n language: toRef(() => language),\n lint: toRef(() => lint),\n extensions: codeMirrorExtensions,\n placeholder: toRef(() => placeholder),\n})\n\n/**\n * Handle autofocus attribute.\n */\nwatch(codeMirror, () => {\n if (codeMirror.value && Object.hasOwn(attrs, 'autofocus')) {\n codeMirror.value.focus()\n }\n})\n\n// ---------------------------------------------------------------------------\n// Environment variable dropdown\n\nconst showDropdown = ref(false)\nconst dropdownQuery = ref('')\nconst dropdownPosition = ref({ left: 0, top: 0 })\nconst dropdownRef = ref<InstanceType<\n typeof EnvironmentVariableDropdown\n> | null>(null)\n\nconst { handleDropdownSelect, updateDropdownVisibility } = useDropdown({\n codeMirror,\n query: dropdownQuery,\n showDropdown,\n dropdownPosition,\n})\n\n/**\n * Determines if the environment variable dropdown should be visible.\n */\nconst displayVariablesDropdown = computed((): boolean => {\n return (\n showDropdown.value &&\n withVariables &&\n layout !== 'modal' &&\n Boolean(environment)\n )\n})\n\n// ---------------------------------------------------------------------------\n// Keyboard event handling\n\n/**\n * Handles keyboard navigation for dropdown and form submission.\n */\nconst handleKeyDown = (key: string, event: KeyboardEvent): void => {\n if (showDropdown.value) {\n if (key === 'down' || key === 'up') {\n event.preventDefault()\n dropdownRef.value?.handleArrowKey(key)\n } else if (key === 'enter') {\n event.preventDefault()\n dropdownRef.value?.handleSelect()\n }\n return\n }\n\n if (key === 'escape' && !disableTabIndent) {\n event.stopPropagation()\n }\n\n if (key === 'enter' && event.target instanceof HTMLDivElement) {\n handleSubmit(event.target.textContent ?? '')\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n\ndefineExpose({\n /**\n * Focus the codemirror element\n *\n * @param cursorAtEnd boolean place the cursor at the end of the input\n */\n focus: (position?: 'start' | 'end' | number) => {\n if (!codeMirror.value) {\n return\n }\n codeMirror.value.focus()\n\n if (!isDefined(position)) {\n return\n }\n\n const anchor = (() => {\n if (position === 'start') {\n return 0\n }\n if (position === 'end') {\n return codeMirror.value.state.doc.length\n }\n return position\n })()\n\n // Move the cursor to the specified position\n codeMirror.value.dispatch({\n selection: { anchor },\n scrollIntoView: true,\n })\n },\n isFocused,\n handleChange,\n handleSubmit,\n handleBlur,\n booleanOptions,\n codeMirror,\n modelValue,\n cursorPosition: () => codeMirror.value?.state.selection.main.head,\n serializeValue,\n})\n</script>\n\n<template>\n <!-- Disabled mode: read-only text display -->\n <div\n v-if=\"disabled\"\n class=\"text-c-2 flex cursor-default items-center justify-center\"\n :class=\"{\n 'font-code pr-2 pl-1 text-base': layout === 'modal',\n 'px-2': layout !== 'modal',\n 'line-through': linethrough,\n }\"\n data-testid=\"code-input-disabled\">\n <span class=\"whitespace-nowrap\">{{ modelValue }}</span>\n </div>\n\n <!-- Enum mode: select dropdown with predefined values -->\n <DataTableInputSelect\n v-else-if=\"enumProp?.length\"\n :default=\"defaultProp\"\n :modelValue=\"modelValue\"\n :type=\"defaultType\"\n :value=\"enumProp\"\n @update:modelValue=\"handleSelectChange\" />\n\n <!-- Boolean mode: select dropdown with true/false (and optionally null) -->\n <DataTableInputSelect\n v-else-if=\"isBooleanMode\"\n :default=\"defaultProp\"\n :modelValue=\"modelValue\"\n :value=\"booleanOptions\"\n @update:modelValue=\"handleSelectChange\" />\n\n <!-- Examples mode: select dropdown with example values -->\n <DataTableInputSelect\n v-else-if=\"examples?.length\"\n :default=\"defaultProp\"\n :modelValue=\"modelValue\"\n :value=\"examples\"\n @update:modelValue=\"handleSelectChange\" />\n\n <!-- Editor mode: CodeMirror with environment variable support -->\n <div\n v-else\n :id=\"componentId\"\n v-bind=\"$attrs\"\n ref=\"codeMirrorRef\"\n class=\"group/input group-[.alert]:outline-orange group-[.error]:outline-red font-code peer relative w-full overflow-hidden text-xs leading-[1.44] whitespace-nowrap -outline-offset-1 has-[:focus-visible]:rounded-[4px] has-[:focus-visible]:outline\"\n :class=\"{\n 'line-wrapping has-[:focus-visible]:bg-b-1 has-[:focus-visible]:absolute has-[:focus-visible]:z-1':\n lineWrapping,\n 'flow-code-input--error': error,\n 'line-through': linethrough,\n }\"\n @keydown.down.stop=\"handleKeyDown('down', $event)\"\n @keydown.enter=\"handleKeyDown('enter', $event)\"\n @keydown.escape=\"handleKeyDown('escape', $event)\"\n @keydown.up.stop=\"handleKeyDown('up', $event)\">\n <!-- Tab exit hint (shown when focused) -->\n <div\n v-if=\"!disableTabIndent\"\n class=\"z-context text-c-2 absolute right-1.5 bottom-1 hidden font-sans group-has-[:focus-visible]/input:block\"\n role=\"alert\">\n Press\n <kbd class=\"-mx-0.25 rounded border px-0.5 font-mono\">Esc</kbd> then\n <kbd class=\"-mx-0.25 rounded border px-0.5 font-mono\">Tab</kbd> to exit\n </div>\n </div>\n\n <!-- Warning slot (positioned absolutely) -->\n <div\n v-if=\"$slots.warning\"\n class=\"centered-y text-orange absolute right-7 text-xs\">\n <slot name=\"warning\" />\n </div>\n\n <!-- Icon slot (positioned absolutely) -->\n <div\n v-if=\"$slots.icon\"\n class=\"centered-y absolute right-0 flex h-full items-center p-1.5 group-has-[.cm-focused]:z-1\">\n <slot name=\"icon\" />\n </div>\n\n <!-- Required indicator -->\n <div\n v-if=\"required\"\n class=\"required centered-y text-xxs text-c-3 group-[.error]:text-red bg-b-1 pointer-events-none absolute right-0 mr-0.5 pt-px pr-2 opacity-100 shadow-[-8px_0_4px_var(--scalar-background-1)] transition-opacity duration-150 group-[.alert]:bg-transparent group-[.alert]:shadow-none group-[.error]:bg-transparent group-[.error]:shadow-none peer-has-[.cm-focused]:opacity-0\">\n Required\n </div>\n\n <!-- Environment variable autocomplete dropdown -->\n <EnvironmentVariableDropdown\n v-if=\"displayVariablesDropdown && environment\"\n ref=\"dropdownRef\"\n :dropdownPosition=\"dropdownPosition\"\n :environment=\"environment\"\n :query=\"dropdownQuery\"\n @redirect=\"emit('redirectToEnvironment')\"\n @select=\"handleDropdownSelect\" />\n</template>\n<style scoped>\n/*\n Deep styling for customizing Codemirror\n */\n:deep(.cm-editor) {\n height: 100%;\n outline: none;\n padding: 0;\n background: transparent;\n}\n:deep(.cm-placeholder) {\n color: var(--scalar-color-3);\n}\n:deep(.cm-content) {\n font-family: var(--scalar-font-code);\n font-size: var(--scalar-small);\n max-height: 20px;\n padding: 8px 0;\n}\n/* Tooltip helper */\n:deep(.cm-tooltip) {\n background: transparent !important;\n filter: brightness(var(--scalar-lifted-brightness));\n border-radius: var(--scalar-radius);\n box-shadow: var(--scalar-shadow-2);\n border: none !important;\n outline: none !important;\n overflow: hidden !important;\n}\n:deep(.cm-tooltip-autocomplete ul li) {\n padding: 3px 6px !important;\n}\n:deep(.cm-completionIcon-type:after) {\n color: var(--scalar-color-3) !important;\n}\n:deep(.cm-tooltip-autocomplete ul li[aria-selected]) {\n background: var(--scalar-background-2) !important;\n color: var(--scalar-color-1) !important;\n}\n:deep(.cm-tooltip-autocomplete ul) {\n padding: 6px !important;\n position: relative;\n}\n:deep(.cm-tooltip-autocomplete ul li:hover) {\n border-radius: 3px;\n color: var(--scalar-color-1) !important;\n background: var(--scalar-background-3) !important;\n}\n/* Disable active line highlighting */\n:deep(.cm-activeLine),\n:deep(.cm-activeLineGutter) {\n background-color: transparent;\n}\n/* Color selection matching */\n:deep(.cm-selectionMatch),\n:deep(.cm-matchingBracket) {\n border-radius: var(--scalar-radius);\n background: var(--scalar-background-4) !important;\n}\n/* Color Picker Swatches */\n:deep(.cm-css-color-picker-wrapper) {\n display: inline-flex;\n outline: 1px solid var(--scalar-background-3);\n border-radius: 3px;\n overflow: hidden;\n}\n/* Number gutter */\n:deep(.cm-gutters) {\n background-color: transparent;\n border-right: none;\n color: var(--scalar-color-3);\n font-size: var(--scalar-small);\n line-height: 22px;\n border-radius: 0 0 0 3px;\n}\n:deep(.cm-gutters:before) {\n content: '';\n position: absolute;\n top: 2px;\n left: 2px;\n width: calc(100% - 2px);\n height: calc(100% - 4px);\n border-radius: var(--scalar-radius) 0 0 var(--scalar-radius);\n background-color: var(--scalar-background-1);\n}\n:deep(.cm-gutterElement) {\n font-family: var(--scalar-font-code) !important;\n padding-left: 0px !important;\n padding-right: 6px !important;\n display: flex;\n align-items: center;\n justify-content: flex-end;\n position: relative;\n}\n:deep(.cm-lineNumbers .cm-gutterElement) {\n min-width: fit-content;\n}\n:deep(.cm-gutter + .cm-gutter :not(.cm-foldGutter) .cm-gutterElement) {\n padding-left: 0 !important;\n}\n:deep(.cm-scroller) {\n overflow: auto;\n}\n.line-wrapping:focus-within :deep(.cm-content) {\n display: inline-table;\n min-height: fit-content;\n padding: 3px 6px;\n white-space: break-spaces;\n word-break: break-all;\n}\n</style>\n<style>\n.cm-pill {\n color: var(--scalar-color-1) !important;\n padding: 0px 9px;\n border-radius: 3px;\n display: inline-block;\n border-radius: 30px;\n font-size: var(--scalar-small);\n}\n.light-mode .cm-pill {\n background: var(--scalar-background-3) !important;\n}\n.dark-mode .cm-pill {\n background: color-mix(in srgb, var(--tw-bg-base), transparent 90%) !important;\n}\n.cm-pill:first-of-type {\n margin-left: 0;\n}\n.cm-editor .cm-widgetBuffer {\n display: none;\n}\n.cm-foldPlaceholder:hover {\n color: var(--scalar-color-1);\n}\n.cm-foldGutter .cm-gutterElement {\n font-size: var(--scalar-heading-4);\n padding: 2px !important;\n}\n.cm-foldGutter .cm-gutterElement:first-of-type {\n display: none;\n}\n.cm-foldGutter .cm-gutterElement .cm-foldMarker {\n padding: 2px;\n padding-top: 2px;\n}\n.cm-foldGutter .cm-gutterElement:hover .cm-foldMarker {\n background: var(--scalar-background-2);\n border-radius: var(--scalar-radius);\n color: var(--scalar-color-1);\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"CodeInput.vue.js","names":[],"sources":["../../../../src/v2/components/code-input/CodeInput.vue"],"sourcesContent":["<script lang=\"ts\">\nexport type CodeInputModelValue =\n | string\n | number\n | boolean\n | Array<string | number | boolean>\n | Record<string, unknown>\n\n/**\n * CodeInput\n *\n * A versatile input component that adapts its rendering based on props:\n * - Disabled mode: Read-only text display\n * - Select mode: Dropdown for enums, booleans, or examples\n * - Editor mode: CodeMirror with environment variable support\n *\n * Type `{{` to trigger environment variable autocomplete when an environment is provided.\n * It takes in any data but always will emit a string value,\n * this string should then be parsed in accordance to the schema or content type.\n *\n * @example\n * ```vue\n * <!-- Basic input with environment variables -->\n * <CodeInput v-model=\"value\" :environment=\"env\" />\n *\n * <!-- Boolean select -->\n * <CodeInput v-model=\"flag\" type=\"boolean\" />\n *\n * <!-- JSON editor with linting -->\n * <CodeInput v-model=\"data\" language=\"json\" :lint=\"true\" />\n * ```\n */\nexport default {\n inheritAttrs: false,\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { isDefined } from '@scalar/helpers/array/is-defined'\nimport {\n colorPicker as colorPickerExtension,\n useCodeMirror,\n useDropdown,\n type CodeMirrorLanguage,\n type Extension,\n} from '@scalar/use-codemirror'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { nanoid } from 'nanoid'\nimport { computed, ref, toRef, useAttrs, watch, type Ref } from 'vue'\n\nimport DataTableInputSelect from '@/v2/components/data-table/DataTableInputSelect.vue'\nimport EnvironmentVariableDropdown from '@/v2/features/environments/components/EnvironmentVariablesDropdown.vue'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nimport { backspaceCommand, pillPlugin } from './code-variable-widget'\n\ntype Props = {\n modelValue: CodeInputModelValue\n /** Environment for variable substitution. Pass undefined to disable environment variables */\n environment: XScalarEnvironment | undefined\n /** Type of the input value, affects rendering mode for booleans */\n type?: string | string[]\n /** Render as disabled text display */\n disabled?: boolean\n /** Show error styling */\n error?: boolean\n /** Layout context affects styling and behavior */\n layout?: ClientLayout\n /** Predefined enum values, triggers select mode */\n enum?: string[]\n /** Example values, triggers select mode */\n examples?: string[]\n /** Default value to show in select mode */\n default?: Props['modelValue']\n /** Allow null in boolean select options */\n nullable?: boolean\n /** Placeholder text for empty input */\n placeholder?: string\n /** Show required indicator */\n required?: boolean\n /** Enable color picker extension */\n colorPicker?: boolean\n /** Show line numbers in editor */\n lineNumbers?: boolean\n /** Enable linting */\n lint?: boolean\n /** Enable line wrapping */\n lineWrapping?: boolean\n /** CodeMirror language mode */\n language?: CodeMirrorLanguage\n /** Additional CodeMirror extensions */\n extensions?: Extension[]\n /** Disable tab key for indentation */\n disableTabIndent?: boolean\n /** Disable enter key */\n disableEnter?: boolean\n /** Disable automatic bracket closing */\n disableCloseBrackets?: boolean\n /** Emit submit event on blur */\n emitOnBlur?: boolean\n /** Enable environment variable pills */\n withVariables?: boolean\n /** Emit change event even if the value is the same */\n alwaysEmitChange?: boolean\n /** Custom change handler, prevents default emit */\n handleFieldChange?: (value: string) => void\n /** Custom submit handler, prevents default emit */\n handleFieldSubmit?: (value: string) => void\n /** Put a linethrough on the input text */\n linethrough?: boolean\n}\n\nconst {\n modelValue,\n environment,\n type,\n disabled = false,\n error = false,\n layout = 'desktop',\n enum: enumProp,\n examples,\n default: defaultProp,\n nullable = false,\n placeholder,\n required,\n colorPicker = false,\n lineNumbers = false,\n lint = false,\n lineWrapping = false,\n language,\n extensions = [],\n disableTabIndent = false,\n disableEnter = false,\n disableCloseBrackets = false,\n emitOnBlur = true,\n alwaysEmitChange = false,\n withVariables = true,\n handleFieldChange,\n handleFieldSubmit,\n} = defineProps<Props>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n 'submit': [value: string]\n 'blur': [value: string]\n 'navigate': [route: { page: 'document'; path: 'environment' }]\n}>()\n\n// ---------------------------------------------------------------------------\n// Component identity and focus state\n\nconst attrs = useAttrs() as { id?: string }\nconst componentId = attrs.id || `id-${nanoid()}`\nconst isFocused = ref(false)\n\n// ---------------------------------------------------------------------------\n// Rendering mode detection\n\n/**\n * Determines if we should render a select dropdown for boolean types.\n */\nconst isBooleanMode = computed((): boolean => {\n if (enumProp?.length) {\n return false\n }\n return type === 'boolean' || (Array.isArray(type) && type.includes('boolean'))\n})\n\n/**\n * Options for boolean select mode.\n */\nconst booleanOptions = computed((): string[] =>\n nullable ? ['true', 'false', 'null'] : ['true', 'false'],\n)\n\n/**\n * Default type when dealing with type arrays.\n * Finds the first non-null type.\n */\nconst defaultType = computed((): string | undefined => {\n if (Array.isArray(type)) {\n return type.find((t) => t !== 'null') ?? 'string'\n }\n return type\n})\n\n// ---------------------------------------------------------------------------\n// Event handlers\n\n/**\n * Handles value changes during typing.\n */\nconst handleChange = (value: string): void => {\n if (!alwaysEmitChange && value === serializeValue(modelValue)) {\n return\n }\n\n // Use custom handler or emit update\n if (handleFieldChange) {\n handleFieldChange(value)\n } else {\n emit('update:modelValue', value)\n }\n}\n\n/**\n * Handles form submission (enter key or blur with emitOnBlur).\n */\nconst handleSubmit = (value: string): void => {\n if (handleFieldSubmit) {\n handleFieldSubmit(value)\n } else {\n emit('submit', value)\n }\n}\n\n/**\n * Handles input blur event.\n */\nconst handleBlur = (value: string): void => {\n isFocused.value = false\n\n if (emitOnBlur && modelValue) {\n handleSubmit(value)\n }\n\n emit('blur', value)\n}\n\n/**\n * Handles model value updates from select components.\n */\nconst handleSelectChange = (value: string): void =>\n emit('update:modelValue', value)\n\n// ---------------------------------------------------------------------------\n// CodeMirror setup\n\n/**\n * Build extensions array.\n * Note: Extensions are not reactive after initialization.\n */\nconst buildExtensions = (): Extension[] => {\n const extensionsList: Extension[] = [...extensions]\n\n if (colorPicker) {\n extensionsList.push(colorPickerExtension)\n }\n\n return extensionsList\n}\n\n/**\n * Reactive pill plugin for environment variable visualization.\n */\nconst pillPluginExtension = computed(() =>\n pillPlugin({\n environment,\n isReadOnly: layout === 'modal',\n }),\n)\n\n/**\n * Combined extensions for CodeMirror.\n */\nconst codeMirrorExtensions = computed((): Extension[] => [\n ...buildExtensions(),\n pillPluginExtension.value,\n backspaceCommand,\n])\n\nconst codeMirrorRef: Ref<HTMLDivElement | null> = ref(null)\n\n/** Converts the model value to a string for CodeMirror */\nconst serializeValue = (value: CodeInputModelValue): string => {\n if (typeof value === 'string') {\n return value\n }\n return JSON.stringify(value)\n}\n\nconst { codeMirror } = useCodeMirror({\n content: toRef(() => serializeValue(modelValue)),\n onChange: (value) => {\n handleChange(value)\n updateDropdownVisibility()\n },\n onFocus: () => {\n isFocused.value = true\n },\n onBlur: handleBlur,\n codeMirrorRef,\n disableTabIndent: toRef(() => disableTabIndent),\n disableEnter: toRef(() => disableEnter),\n disableCloseBrackets: toRef(() => disableCloseBrackets),\n lineNumbers: toRef(() => lineNumbers),\n language: toRef(() => language),\n lint: toRef(() => lint),\n extensions: codeMirrorExtensions,\n placeholder: toRef(() => placeholder),\n})\n\n/**\n * Handle autofocus attribute.\n */\nwatch(codeMirror, () => {\n if (codeMirror.value && Object.hasOwn(attrs, 'autofocus')) {\n codeMirror.value.focus()\n }\n})\n\n// ---------------------------------------------------------------------------\n// Environment variable dropdown\n\nconst showDropdown = ref(false)\nconst dropdownQuery = ref('')\nconst dropdownPosition = ref({ left: 0, top: 0 })\nconst dropdownRef = ref<InstanceType<\n typeof EnvironmentVariableDropdown\n> | null>(null)\n\nconst { handleDropdownSelect, updateDropdownVisibility } = useDropdown({\n codeMirror,\n query: dropdownQuery,\n showDropdown,\n dropdownPosition,\n})\n\n/**\n * Determines if the environment variable dropdown should be visible.\n */\nconst displayVariablesDropdown = computed((): boolean => {\n return (\n showDropdown.value &&\n withVariables &&\n layout !== 'modal' &&\n Boolean(environment)\n )\n})\n\n// ---------------------------------------------------------------------------\n// Keyboard event handling\n\n/**\n * Handles keyboard navigation for dropdown and form submission.\n */\nconst handleKeyDown = (key: string, event: KeyboardEvent): void => {\n if (showDropdown.value) {\n if (key === 'down' || key === 'up') {\n event.preventDefault()\n dropdownRef.value?.handleArrowKey(key)\n } else if (key === 'enter') {\n event.preventDefault()\n dropdownRef.value?.handleSelect()\n }\n return\n }\n\n if (key === 'escape' && !disableTabIndent) {\n event.stopPropagation()\n }\n\n if (key === 'enter' && event.target instanceof HTMLDivElement) {\n handleSubmit(event.target.textContent ?? '')\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n\ndefineExpose({\n /**\n * Focus the codemirror element\n *\n * @param cursorAtEnd boolean place the cursor at the end of the input\n */\n focus: (position?: 'start' | 'end' | number) => {\n if (!codeMirror.value) {\n return\n }\n codeMirror.value.focus()\n\n if (!isDefined(position)) {\n return\n }\n\n const anchor = (() => {\n if (position === 'start') {\n return 0\n }\n if (position === 'end') {\n return codeMirror.value.state.doc.length\n }\n return position\n })()\n\n // Move the cursor to the specified position\n codeMirror.value.dispatch({\n selection: { anchor },\n scrollIntoView: true,\n })\n },\n isFocused,\n handleChange,\n handleSubmit,\n handleBlur,\n booleanOptions,\n codeMirror,\n modelValue,\n cursorPosition: () => codeMirror.value?.state.selection.main.head,\n serializeValue,\n})\n</script>\n\n<template>\n <!-- Disabled mode: read-only text display -->\n <div\n v-if=\"disabled\"\n class=\"text-c-2 flex cursor-default items-center justify-center\"\n :class=\"{\n 'font-code pr-2 pl-1 text-base': layout === 'modal',\n 'px-2': layout !== 'modal',\n 'line-through': linethrough,\n }\"\n data-testid=\"code-input-disabled\">\n <span class=\"whitespace-nowrap\">{{ modelValue }}</span>\n </div>\n\n <!-- Enum mode: select dropdown with predefined values -->\n <DataTableInputSelect\n v-else-if=\"enumProp?.length\"\n :default=\"defaultProp\"\n :modelValue=\"modelValue\"\n :type=\"defaultType\"\n :value=\"enumProp\"\n @update:modelValue=\"handleSelectChange\" />\n\n <!-- Boolean mode: select dropdown with true/false (and optionally null) -->\n <DataTableInputSelect\n v-else-if=\"isBooleanMode\"\n :default=\"defaultProp\"\n :modelValue=\"modelValue\"\n :value=\"booleanOptions\"\n @update:modelValue=\"handleSelectChange\" />\n\n <!-- Examples mode: select dropdown with example values -->\n <DataTableInputSelect\n v-else-if=\"examples?.length\"\n :default=\"defaultProp\"\n :modelValue=\"modelValue\"\n :value=\"examples\"\n @update:modelValue=\"handleSelectChange\" />\n\n <!-- Editor mode: CodeMirror with environment variable support -->\n <div\n v-else\n :id=\"componentId\"\n v-bind=\"$attrs\"\n ref=\"codeMirrorRef\"\n class=\"group/input group-[.alert]:outline-orange group-[.error]:outline-red font-code peer relative w-full overflow-hidden text-xs leading-[1.44] whitespace-nowrap -outline-offset-1 has-[:focus-visible]:rounded-[4px] has-[:focus-visible]:outline\"\n :class=\"{\n 'line-wrapping has-[:focus-visible]:bg-b-1 has-[:focus-visible]:absolute has-[:focus-visible]:z-1':\n lineWrapping,\n 'flow-code-input--error': error,\n 'line-through': linethrough,\n }\"\n @keydown.down.stop=\"handleKeyDown('down', $event)\"\n @keydown.enter=\"handleKeyDown('enter', $event)\"\n @keydown.escape=\"handleKeyDown('escape', $event)\"\n @keydown.up.stop=\"handleKeyDown('up', $event)\">\n <!-- Tab exit hint (shown when focused) -->\n <div\n v-if=\"!disableTabIndent\"\n class=\"z-context text-c-2 absolute right-1.5 bottom-1 hidden font-sans group-has-[:focus-visible]/input:block\"\n role=\"alert\">\n Press\n <kbd class=\"-mx-0.25 rounded border px-0.5 font-mono\">Esc</kbd> then\n <kbd class=\"-mx-0.25 rounded border px-0.5 font-mono\">Tab</kbd> to exit\n </div>\n </div>\n\n <!-- Warning slot (positioned absolutely) -->\n <div\n v-if=\"$slots.warning\"\n class=\"centered-y text-orange absolute right-7 text-xs\">\n <slot name=\"warning\" />\n </div>\n\n <!-- Icon slot (positioned absolutely) -->\n <div\n v-if=\"$slots.icon\"\n class=\"centered-y absolute right-0 flex h-full items-center p-1.5 group-has-[.cm-focused]:z-1\">\n <slot name=\"icon\" />\n </div>\n\n <!-- Required indicator -->\n <div\n v-if=\"required\"\n class=\"required centered-y text-xxs text-c-3 group-[.error]:text-red bg-b-1 pointer-events-none absolute right-0 mr-0.5 pt-px pr-2 opacity-100 shadow-[-8px_0_4px_var(--scalar-background-1)] transition-opacity duration-150 group-[.alert]:bg-transparent group-[.alert]:shadow-none group-[.error]:bg-transparent group-[.error]:shadow-none peer-has-[.cm-focused]:opacity-0\">\n Required\n </div>\n\n <!-- Environment variable autocomplete dropdown -->\n <EnvironmentVariableDropdown\n v-if=\"displayVariablesDropdown && environment\"\n ref=\"dropdownRef\"\n :dropdownPosition=\"dropdownPosition\"\n :environment=\"environment\"\n :query=\"dropdownQuery\"\n @redirect=\"emit('navigate', { page: 'document', path: 'environment' })\"\n @select=\"handleDropdownSelect\" />\n</template>\n<style scoped>\n/*\n Deep styling for customizing Codemirror\n */\n:deep(.cm-editor) {\n height: 100%;\n outline: none;\n padding: 0;\n background: transparent;\n}\n:deep(.cm-placeholder) {\n color: var(--scalar-color-3);\n}\n:deep(.cm-content) {\n font-family: var(--scalar-font-code);\n font-size: var(--scalar-small);\n max-height: 20px;\n padding: 8px 0;\n}\n/* Tooltip helper */\n:deep(.cm-tooltip) {\n background: transparent !important;\n filter: brightness(var(--scalar-lifted-brightness));\n border-radius: var(--scalar-radius);\n box-shadow: var(--scalar-shadow-2);\n border: none !important;\n outline: none !important;\n overflow: hidden !important;\n}\n:deep(.cm-tooltip-autocomplete ul li) {\n padding: 3px 6px !important;\n}\n:deep(.cm-completionIcon-type:after) {\n color: var(--scalar-color-3) !important;\n}\n:deep(.cm-tooltip-autocomplete ul li[aria-selected]) {\n background: var(--scalar-background-2) !important;\n color: var(--scalar-color-1) !important;\n}\n:deep(.cm-tooltip-autocomplete ul) {\n padding: 6px !important;\n position: relative;\n}\n:deep(.cm-tooltip-autocomplete ul li:hover) {\n border-radius: 3px;\n color: var(--scalar-color-1) !important;\n background: var(--scalar-background-3) !important;\n}\n/* Disable active line highlighting */\n:deep(.cm-activeLine),\n:deep(.cm-activeLineGutter) {\n background-color: transparent;\n}\n/* Color selection matching */\n:deep(.cm-selectionMatch),\n:deep(.cm-matchingBracket) {\n border-radius: var(--scalar-radius);\n background: var(--scalar-background-4) !important;\n}\n/* Color Picker Swatches */\n:deep(.cm-css-color-picker-wrapper) {\n display: inline-flex;\n outline: 1px solid var(--scalar-background-3);\n border-radius: 3px;\n overflow: hidden;\n}\n/* Number gutter */\n:deep(.cm-gutters) {\n background-color: transparent;\n border-right: none;\n color: var(--scalar-color-3);\n font-size: var(--scalar-small);\n line-height: 22px;\n border-radius: 0 0 0 3px;\n}\n:deep(.cm-gutters:before) {\n content: '';\n position: absolute;\n top: 2px;\n left: 2px;\n width: calc(100% - 2px);\n height: calc(100% - 4px);\n border-radius: var(--scalar-radius) 0 0 var(--scalar-radius);\n background-color: var(--scalar-background-1);\n}\n:deep(.cm-gutterElement) {\n font-family: var(--scalar-font-code) !important;\n padding-left: 0px !important;\n padding-right: 6px !important;\n display: flex;\n align-items: center;\n justify-content: flex-end;\n position: relative;\n}\n:deep(.cm-lineNumbers .cm-gutterElement) {\n min-width: fit-content;\n}\n:deep(.cm-gutter + .cm-gutter :not(.cm-foldGutter) .cm-gutterElement) {\n padding-left: 0 !important;\n}\n:deep(.cm-scroller) {\n overflow: auto;\n}\n.line-wrapping:focus-within :deep(.cm-content) {\n display: inline-table;\n min-height: fit-content;\n padding: 3px 6px;\n white-space: break-spaces;\n word-break: break-all;\n}\n</style>\n<style>\n.cm-pill {\n color: var(--scalar-color-1) !important;\n padding: 0px 9px;\n border-radius: 3px;\n display: inline-block;\n border-radius: 30px;\n font-size: var(--scalar-small);\n}\n.light-mode .cm-pill {\n background: var(--scalar-background-3) !important;\n}\n.dark-mode .cm-pill {\n background: color-mix(in srgb, var(--tw-bg-base), transparent 90%) !important;\n}\n.cm-pill:first-of-type {\n margin-left: 0;\n}\n.cm-editor .cm-widgetBuffer {\n display: none;\n}\n.cm-foldPlaceholder:hover {\n color: var(--scalar-color-1);\n}\n.cm-foldGutter .cm-gutterElement {\n font-size: var(--scalar-heading-4);\n padding: 2px !important;\n}\n.cm-foldGutter .cm-gutterElement:first-of-type {\n display: none;\n}\n.cm-foldGutter .cm-gutterElement .cm-foldMarker {\n padding: 2px;\n padding-top: 2px;\n}\n.cm-foldGutter .cm-gutterElement:hover .cm-foldMarker {\n background: var(--scalar-background-2);\n border-radius: var(--scalar-radius);\n color: var(--scalar-color-1);\n}\n</style>\n"],"mappings":""}
|
|
@@ -112,7 +112,7 @@ var CodeInput_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defi
|
|
|
112
112
|
"update:modelValue",
|
|
113
113
|
"submit",
|
|
114
114
|
"blur",
|
|
115
|
-
"
|
|
115
|
+
"navigate"
|
|
116
116
|
],
|
|
117
117
|
setup(__props, { expose: __expose, emit: __emit }) {
|
|
118
118
|
const emit = __emit;
|
|
@@ -362,7 +362,10 @@ var CodeInput_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defi
|
|
|
362
362
|
dropdownPosition: dropdownPosition.value,
|
|
363
363
|
environment: __props.environment,
|
|
364
364
|
query: dropdownQuery.value,
|
|
365
|
-
onRedirect: _cache[4] || (_cache[4] = ($event) => emit("
|
|
365
|
+
onRedirect: _cache[4] || (_cache[4] = ($event) => emit("navigate", {
|
|
366
|
+
page: "document",
|
|
367
|
+
path: "environment"
|
|
368
|
+
})),
|
|
366
369
|
onSelect: unref(handleDropdownSelect)
|
|
367
370
|
}, null, 8, [
|
|
368
371
|
"dropdownPosition",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeInput.vue.script.js","names":["$attrs","$slots"],"sources":["../../../../src/v2/components/code-input/CodeInput.vue"],"sourcesContent":["<script lang=\"ts\">\nexport type CodeInputModelValue =\n | string\n | number\n | boolean\n | Array<string | number | boolean>\n | Record<string, unknown>\n\n/**\n * CodeInput\n *\n * A versatile input component that adapts its rendering based on props:\n * - Disabled mode: Read-only text display\n * - Select mode: Dropdown for enums, booleans, or examples\n * - Editor mode: CodeMirror with environment variable support\n *\n * Type `{{` to trigger environment variable autocomplete when an environment is provided.\n * It takes in any data but always will emit a string value,\n * this string should then be parsed in accordance to the schema or content type.\n *\n * @example\n * ```vue\n * <!-- Basic input with environment variables -->\n * <CodeInput v-model=\"value\" :environment=\"env\" />\n *\n * <!-- Boolean select -->\n * <CodeInput v-model=\"flag\" type=\"boolean\" />\n *\n * <!-- JSON editor with linting -->\n * <CodeInput v-model=\"data\" language=\"json\" :lint=\"true\" />\n * ```\n */\nexport default {\n inheritAttrs: false,\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { isDefined } from '@scalar/helpers/array/is-defined'\nimport {\n colorPicker as colorPickerExtension,\n useCodeMirror,\n useDropdown,\n type CodeMirrorLanguage,\n type Extension,\n} from '@scalar/use-codemirror'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { nanoid } from 'nanoid'\nimport { computed, ref, toRef, useAttrs, watch, type Ref } from 'vue'\n\nimport DataTableInputSelect from '@/v2/components/data-table/DataTableInputSelect.vue'\nimport EnvironmentVariableDropdown from '@/v2/features/environments/components/EnvironmentVariablesDropdown.vue'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nimport { backspaceCommand, pillPlugin } from './code-variable-widget'\n\ntype Props = {\n modelValue: CodeInputModelValue\n /** Environment for variable substitution. Pass undefined to disable environment variables */\n environment: XScalarEnvironment | undefined\n /** Type of the input value, affects rendering mode for booleans */\n type?: string | string[]\n /** Render as disabled text display */\n disabled?: boolean\n /** Show error styling */\n error?: boolean\n /** Layout context affects styling and behavior */\n layout?: ClientLayout\n /** Predefined enum values, triggers select mode */\n enum?: string[]\n /** Example values, triggers select mode */\n examples?: string[]\n /** Default value to show in select mode */\n default?: Props['modelValue']\n /** Allow null in boolean select options */\n nullable?: boolean\n /** Placeholder text for empty input */\n placeholder?: string\n /** Show required indicator */\n required?: boolean\n /** Enable color picker extension */\n colorPicker?: boolean\n /** Show line numbers in editor */\n lineNumbers?: boolean\n /** Enable linting */\n lint?: boolean\n /** Enable line wrapping */\n lineWrapping?: boolean\n /** CodeMirror language mode */\n language?: CodeMirrorLanguage\n /** Additional CodeMirror extensions */\n extensions?: Extension[]\n /** Disable tab key for indentation */\n disableTabIndent?: boolean\n /** Disable enter key */\n disableEnter?: boolean\n /** Disable automatic bracket closing */\n disableCloseBrackets?: boolean\n /** Emit submit event on blur */\n emitOnBlur?: boolean\n /** Enable environment variable pills */\n withVariables?: boolean\n /** Emit change event even if the value is the same */\n alwaysEmitChange?: boolean\n /** Custom change handler, prevents default emit */\n handleFieldChange?: (value: string) => void\n /** Custom submit handler, prevents default emit */\n handleFieldSubmit?: (value: string) => void\n /** Put a linethrough on the input text */\n linethrough?: boolean\n}\n\nconst {\n modelValue,\n environment,\n type,\n disabled = false,\n error = false,\n layout = 'desktop',\n enum: enumProp,\n examples,\n default: defaultProp,\n nullable = false,\n placeholder,\n required,\n colorPicker = false,\n lineNumbers = false,\n lint = false,\n lineWrapping = false,\n language,\n extensions = [],\n disableTabIndent = false,\n disableEnter = false,\n disableCloseBrackets = false,\n emitOnBlur = true,\n alwaysEmitChange = false,\n withVariables = true,\n handleFieldChange,\n handleFieldSubmit,\n} = defineProps<Props>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n 'submit': [value: string]\n 'blur': [value: string]\n 'redirectToEnvironment': []\n}>()\n\n// ---------------------------------------------------------------------------\n// Component identity and focus state\n\nconst attrs = useAttrs() as { id?: string }\nconst componentId = attrs.id || `id-${nanoid()}`\nconst isFocused = ref(false)\n\n// ---------------------------------------------------------------------------\n// Rendering mode detection\n\n/**\n * Determines if we should render a select dropdown for boolean types.\n */\nconst isBooleanMode = computed((): boolean => {\n if (enumProp?.length) {\n return false\n }\n return type === 'boolean' || (Array.isArray(type) && type.includes('boolean'))\n})\n\n/**\n * Options for boolean select mode.\n */\nconst booleanOptions = computed((): string[] =>\n nullable ? ['true', 'false', 'null'] : ['true', 'false'],\n)\n\n/**\n * Default type when dealing with type arrays.\n * Finds the first non-null type.\n */\nconst defaultType = computed((): string | undefined => {\n if (Array.isArray(type)) {\n return type.find((t) => t !== 'null') ?? 'string'\n }\n return type\n})\n\n// ---------------------------------------------------------------------------\n// Event handlers\n\n/**\n * Handles value changes during typing.\n */\nconst handleChange = (value: string): void => {\n if (!alwaysEmitChange && value === serializeValue(modelValue)) {\n return\n }\n\n // Use custom handler or emit update\n if (handleFieldChange) {\n handleFieldChange(value)\n } else {\n emit('update:modelValue', value)\n }\n}\n\n/**\n * Handles form submission (enter key or blur with emitOnBlur).\n */\nconst handleSubmit = (value: string): void => {\n if (handleFieldSubmit) {\n handleFieldSubmit(value)\n } else {\n emit('submit', value)\n }\n}\n\n/**\n * Handles input blur event.\n */\nconst handleBlur = (value: string): void => {\n isFocused.value = false\n\n if (emitOnBlur && modelValue) {\n handleSubmit(value)\n }\n\n emit('blur', value)\n}\n\n/**\n * Handles model value updates from select components.\n */\nconst handleSelectChange = (value: string): void =>\n emit('update:modelValue', value)\n\n// ---------------------------------------------------------------------------\n// CodeMirror setup\n\n/**\n * Build extensions array.\n * Note: Extensions are not reactive after initialization.\n */\nconst buildExtensions = (): Extension[] => {\n const extensionsList: Extension[] = [...extensions]\n\n if (colorPicker) {\n extensionsList.push(colorPickerExtension)\n }\n\n return extensionsList\n}\n\n/**\n * Reactive pill plugin for environment variable visualization.\n */\nconst pillPluginExtension = computed(() =>\n pillPlugin({\n environment,\n isReadOnly: layout === 'modal',\n }),\n)\n\n/**\n * Combined extensions for CodeMirror.\n */\nconst codeMirrorExtensions = computed((): Extension[] => [\n ...buildExtensions(),\n pillPluginExtension.value,\n backspaceCommand,\n])\n\nconst codeMirrorRef: Ref<HTMLDivElement | null> = ref(null)\n\n/** Converts the model value to a string for CodeMirror */\nconst serializeValue = (value: CodeInputModelValue): string => {\n if (typeof value === 'string') {\n return value\n }\n return JSON.stringify(value)\n}\n\nconst { codeMirror } = useCodeMirror({\n content: toRef(() => serializeValue(modelValue)),\n onChange: (value) => {\n handleChange(value)\n updateDropdownVisibility()\n },\n onFocus: () => {\n isFocused.value = true\n },\n onBlur: handleBlur,\n codeMirrorRef,\n disableTabIndent: toRef(() => disableTabIndent),\n disableEnter: toRef(() => disableEnter),\n disableCloseBrackets: toRef(() => disableCloseBrackets),\n lineNumbers: toRef(() => lineNumbers),\n language: toRef(() => language),\n lint: toRef(() => lint),\n extensions: codeMirrorExtensions,\n placeholder: toRef(() => placeholder),\n})\n\n/**\n * Handle autofocus attribute.\n */\nwatch(codeMirror, () => {\n if (codeMirror.value && Object.hasOwn(attrs, 'autofocus')) {\n codeMirror.value.focus()\n }\n})\n\n// ---------------------------------------------------------------------------\n// Environment variable dropdown\n\nconst showDropdown = ref(false)\nconst dropdownQuery = ref('')\nconst dropdownPosition = ref({ left: 0, top: 0 })\nconst dropdownRef = ref<InstanceType<\n typeof EnvironmentVariableDropdown\n> | null>(null)\n\nconst { handleDropdownSelect, updateDropdownVisibility } = useDropdown({\n codeMirror,\n query: dropdownQuery,\n showDropdown,\n dropdownPosition,\n})\n\n/**\n * Determines if the environment variable dropdown should be visible.\n */\nconst displayVariablesDropdown = computed((): boolean => {\n return (\n showDropdown.value &&\n withVariables &&\n layout !== 'modal' &&\n Boolean(environment)\n )\n})\n\n// ---------------------------------------------------------------------------\n// Keyboard event handling\n\n/**\n * Handles keyboard navigation for dropdown and form submission.\n */\nconst handleKeyDown = (key: string, event: KeyboardEvent): void => {\n if (showDropdown.value) {\n if (key === 'down' || key === 'up') {\n event.preventDefault()\n dropdownRef.value?.handleArrowKey(key)\n } else if (key === 'enter') {\n event.preventDefault()\n dropdownRef.value?.handleSelect()\n }\n return\n }\n\n if (key === 'escape' && !disableTabIndent) {\n event.stopPropagation()\n }\n\n if (key === 'enter' && event.target instanceof HTMLDivElement) {\n handleSubmit(event.target.textContent ?? '')\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n\ndefineExpose({\n /**\n * Focus the codemirror element\n *\n * @param cursorAtEnd boolean place the cursor at the end of the input\n */\n focus: (position?: 'start' | 'end' | number) => {\n if (!codeMirror.value) {\n return\n }\n codeMirror.value.focus()\n\n if (!isDefined(position)) {\n return\n }\n\n const anchor = (() => {\n if (position === 'start') {\n return 0\n }\n if (position === 'end') {\n return codeMirror.value.state.doc.length\n }\n return position\n })()\n\n // Move the cursor to the specified position\n codeMirror.value.dispatch({\n selection: { anchor },\n scrollIntoView: true,\n })\n },\n isFocused,\n handleChange,\n handleSubmit,\n handleBlur,\n booleanOptions,\n codeMirror,\n modelValue,\n cursorPosition: () => codeMirror.value?.state.selection.main.head,\n serializeValue,\n})\n</script>\n\n<template>\n <!-- Disabled mode: read-only text display -->\n <div\n v-if=\"disabled\"\n class=\"text-c-2 flex cursor-default items-center justify-center\"\n :class=\"{\n 'font-code pr-2 pl-1 text-base': layout === 'modal',\n 'px-2': layout !== 'modal',\n 'line-through': linethrough,\n }\"\n data-testid=\"code-input-disabled\">\n <span class=\"whitespace-nowrap\">{{ modelValue }}</span>\n </div>\n\n <!-- Enum mode: select dropdown with predefined values -->\n <DataTableInputSelect\n v-else-if=\"enumProp?.length\"\n :default=\"defaultProp\"\n :modelValue=\"modelValue\"\n :type=\"defaultType\"\n :value=\"enumProp\"\n @update:modelValue=\"handleSelectChange\" />\n\n <!-- Boolean mode: select dropdown with true/false (and optionally null) -->\n <DataTableInputSelect\n v-else-if=\"isBooleanMode\"\n :default=\"defaultProp\"\n :modelValue=\"modelValue\"\n :value=\"booleanOptions\"\n @update:modelValue=\"handleSelectChange\" />\n\n <!-- Examples mode: select dropdown with example values -->\n <DataTableInputSelect\n v-else-if=\"examples?.length\"\n :default=\"defaultProp\"\n :modelValue=\"modelValue\"\n :value=\"examples\"\n @update:modelValue=\"handleSelectChange\" />\n\n <!-- Editor mode: CodeMirror with environment variable support -->\n <div\n v-else\n :id=\"componentId\"\n v-bind=\"$attrs\"\n ref=\"codeMirrorRef\"\n class=\"group/input group-[.alert]:outline-orange group-[.error]:outline-red font-code peer relative w-full overflow-hidden text-xs leading-[1.44] whitespace-nowrap -outline-offset-1 has-[:focus-visible]:rounded-[4px] has-[:focus-visible]:outline\"\n :class=\"{\n 'line-wrapping has-[:focus-visible]:bg-b-1 has-[:focus-visible]:absolute has-[:focus-visible]:z-1':\n lineWrapping,\n 'flow-code-input--error': error,\n 'line-through': linethrough,\n }\"\n @keydown.down.stop=\"handleKeyDown('down', $event)\"\n @keydown.enter=\"handleKeyDown('enter', $event)\"\n @keydown.escape=\"handleKeyDown('escape', $event)\"\n @keydown.up.stop=\"handleKeyDown('up', $event)\">\n <!-- Tab exit hint (shown when focused) -->\n <div\n v-if=\"!disableTabIndent\"\n class=\"z-context text-c-2 absolute right-1.5 bottom-1 hidden font-sans group-has-[:focus-visible]/input:block\"\n role=\"alert\">\n Press\n <kbd class=\"-mx-0.25 rounded border px-0.5 font-mono\">Esc</kbd> then\n <kbd class=\"-mx-0.25 rounded border px-0.5 font-mono\">Tab</kbd> to exit\n </div>\n </div>\n\n <!-- Warning slot (positioned absolutely) -->\n <div\n v-if=\"$slots.warning\"\n class=\"centered-y text-orange absolute right-7 text-xs\">\n <slot name=\"warning\" />\n </div>\n\n <!-- Icon slot (positioned absolutely) -->\n <div\n v-if=\"$slots.icon\"\n class=\"centered-y absolute right-0 flex h-full items-center p-1.5 group-has-[.cm-focused]:z-1\">\n <slot name=\"icon\" />\n </div>\n\n <!-- Required indicator -->\n <div\n v-if=\"required\"\n class=\"required centered-y text-xxs text-c-3 group-[.error]:text-red bg-b-1 pointer-events-none absolute right-0 mr-0.5 pt-px pr-2 opacity-100 shadow-[-8px_0_4px_var(--scalar-background-1)] transition-opacity duration-150 group-[.alert]:bg-transparent group-[.alert]:shadow-none group-[.error]:bg-transparent group-[.error]:shadow-none peer-has-[.cm-focused]:opacity-0\">\n Required\n </div>\n\n <!-- Environment variable autocomplete dropdown -->\n <EnvironmentVariableDropdown\n v-if=\"displayVariablesDropdown && environment\"\n ref=\"dropdownRef\"\n :dropdownPosition=\"dropdownPosition\"\n :environment=\"environment\"\n :query=\"dropdownQuery\"\n @redirect=\"emit('redirectToEnvironment')\"\n @select=\"handleDropdownSelect\" />\n</template>\n<style scoped>\n/*\n Deep styling for customizing Codemirror\n */\n:deep(.cm-editor) {\n height: 100%;\n outline: none;\n padding: 0;\n background: transparent;\n}\n:deep(.cm-placeholder) {\n color: var(--scalar-color-3);\n}\n:deep(.cm-content) {\n font-family: var(--scalar-font-code);\n font-size: var(--scalar-small);\n max-height: 20px;\n padding: 8px 0;\n}\n/* Tooltip helper */\n:deep(.cm-tooltip) {\n background: transparent !important;\n filter: brightness(var(--scalar-lifted-brightness));\n border-radius: var(--scalar-radius);\n box-shadow: var(--scalar-shadow-2);\n border: none !important;\n outline: none !important;\n overflow: hidden !important;\n}\n:deep(.cm-tooltip-autocomplete ul li) {\n padding: 3px 6px !important;\n}\n:deep(.cm-completionIcon-type:after) {\n color: var(--scalar-color-3) !important;\n}\n:deep(.cm-tooltip-autocomplete ul li[aria-selected]) {\n background: var(--scalar-background-2) !important;\n color: var(--scalar-color-1) !important;\n}\n:deep(.cm-tooltip-autocomplete ul) {\n padding: 6px !important;\n position: relative;\n}\n:deep(.cm-tooltip-autocomplete ul li:hover) {\n border-radius: 3px;\n color: var(--scalar-color-1) !important;\n background: var(--scalar-background-3) !important;\n}\n/* Disable active line highlighting */\n:deep(.cm-activeLine),\n:deep(.cm-activeLineGutter) {\n background-color: transparent;\n}\n/* Color selection matching */\n:deep(.cm-selectionMatch),\n:deep(.cm-matchingBracket) {\n border-radius: var(--scalar-radius);\n background: var(--scalar-background-4) !important;\n}\n/* Color Picker Swatches */\n:deep(.cm-css-color-picker-wrapper) {\n display: inline-flex;\n outline: 1px solid var(--scalar-background-3);\n border-radius: 3px;\n overflow: hidden;\n}\n/* Number gutter */\n:deep(.cm-gutters) {\n background-color: transparent;\n border-right: none;\n color: var(--scalar-color-3);\n font-size: var(--scalar-small);\n line-height: 22px;\n border-radius: 0 0 0 3px;\n}\n:deep(.cm-gutters:before) {\n content: '';\n position: absolute;\n top: 2px;\n left: 2px;\n width: calc(100% - 2px);\n height: calc(100% - 4px);\n border-radius: var(--scalar-radius) 0 0 var(--scalar-radius);\n background-color: var(--scalar-background-1);\n}\n:deep(.cm-gutterElement) {\n font-family: var(--scalar-font-code) !important;\n padding-left: 0px !important;\n padding-right: 6px !important;\n display: flex;\n align-items: center;\n justify-content: flex-end;\n position: relative;\n}\n:deep(.cm-lineNumbers .cm-gutterElement) {\n min-width: fit-content;\n}\n:deep(.cm-gutter + .cm-gutter :not(.cm-foldGutter) .cm-gutterElement) {\n padding-left: 0 !important;\n}\n:deep(.cm-scroller) {\n overflow: auto;\n}\n.line-wrapping:focus-within :deep(.cm-content) {\n display: inline-table;\n min-height: fit-content;\n padding: 3px 6px;\n white-space: break-spaces;\n word-break: break-all;\n}\n</style>\n<style>\n.cm-pill {\n color: var(--scalar-color-1) !important;\n padding: 0px 9px;\n border-radius: 3px;\n display: inline-block;\n border-radius: 30px;\n font-size: var(--scalar-small);\n}\n.light-mode .cm-pill {\n background: var(--scalar-background-3) !important;\n}\n.dark-mode .cm-pill {\n background: color-mix(in srgb, var(--tw-bg-base), transparent 90%) !important;\n}\n.cm-pill:first-of-type {\n margin-left: 0;\n}\n.cm-editor .cm-widgetBuffer {\n display: none;\n}\n.cm-foldPlaceholder:hover {\n color: var(--scalar-color-1);\n}\n.cm-foldGutter .cm-gutterElement {\n font-size: var(--scalar-heading-4);\n padding: 2px !important;\n}\n.cm-foldGutter .cm-gutterElement:first-of-type {\n display: none;\n}\n.cm-foldGutter .cm-gutterElement .cm-foldMarker {\n padding: 2px;\n padding-top: 2px;\n}\n.cm-foldGutter .cm-gutterElement:hover .cm-foldMarker {\n background: var(--scalar-background-2);\n border-radius: var(--scalar-radius);\n color: var(--scalar-color-1);\n}\n</style>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CodeInput.vue.script.js","names":["$attrs","$slots"],"sources":["../../../../src/v2/components/code-input/CodeInput.vue"],"sourcesContent":["<script lang=\"ts\">\nexport type CodeInputModelValue =\n | string\n | number\n | boolean\n | Array<string | number | boolean>\n | Record<string, unknown>\n\n/**\n * CodeInput\n *\n * A versatile input component that adapts its rendering based on props:\n * - Disabled mode: Read-only text display\n * - Select mode: Dropdown for enums, booleans, or examples\n * - Editor mode: CodeMirror with environment variable support\n *\n * Type `{{` to trigger environment variable autocomplete when an environment is provided.\n * It takes in any data but always will emit a string value,\n * this string should then be parsed in accordance to the schema or content type.\n *\n * @example\n * ```vue\n * <!-- Basic input with environment variables -->\n * <CodeInput v-model=\"value\" :environment=\"env\" />\n *\n * <!-- Boolean select -->\n * <CodeInput v-model=\"flag\" type=\"boolean\" />\n *\n * <!-- JSON editor with linting -->\n * <CodeInput v-model=\"data\" language=\"json\" :lint=\"true\" />\n * ```\n */\nexport default {\n inheritAttrs: false,\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { isDefined } from '@scalar/helpers/array/is-defined'\nimport {\n colorPicker as colorPickerExtension,\n useCodeMirror,\n useDropdown,\n type CodeMirrorLanguage,\n type Extension,\n} from '@scalar/use-codemirror'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { nanoid } from 'nanoid'\nimport { computed, ref, toRef, useAttrs, watch, type Ref } from 'vue'\n\nimport DataTableInputSelect from '@/v2/components/data-table/DataTableInputSelect.vue'\nimport EnvironmentVariableDropdown from '@/v2/features/environments/components/EnvironmentVariablesDropdown.vue'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nimport { backspaceCommand, pillPlugin } from './code-variable-widget'\n\ntype Props = {\n modelValue: CodeInputModelValue\n /** Environment for variable substitution. Pass undefined to disable environment variables */\n environment: XScalarEnvironment | undefined\n /** Type of the input value, affects rendering mode for booleans */\n type?: string | string[]\n /** Render as disabled text display */\n disabled?: boolean\n /** Show error styling */\n error?: boolean\n /** Layout context affects styling and behavior */\n layout?: ClientLayout\n /** Predefined enum values, triggers select mode */\n enum?: string[]\n /** Example values, triggers select mode */\n examples?: string[]\n /** Default value to show in select mode */\n default?: Props['modelValue']\n /** Allow null in boolean select options */\n nullable?: boolean\n /** Placeholder text for empty input */\n placeholder?: string\n /** Show required indicator */\n required?: boolean\n /** Enable color picker extension */\n colorPicker?: boolean\n /** Show line numbers in editor */\n lineNumbers?: boolean\n /** Enable linting */\n lint?: boolean\n /** Enable line wrapping */\n lineWrapping?: boolean\n /** CodeMirror language mode */\n language?: CodeMirrorLanguage\n /** Additional CodeMirror extensions */\n extensions?: Extension[]\n /** Disable tab key for indentation */\n disableTabIndent?: boolean\n /** Disable enter key */\n disableEnter?: boolean\n /** Disable automatic bracket closing */\n disableCloseBrackets?: boolean\n /** Emit submit event on blur */\n emitOnBlur?: boolean\n /** Enable environment variable pills */\n withVariables?: boolean\n /** Emit change event even if the value is the same */\n alwaysEmitChange?: boolean\n /** Custom change handler, prevents default emit */\n handleFieldChange?: (value: string) => void\n /** Custom submit handler, prevents default emit */\n handleFieldSubmit?: (value: string) => void\n /** Put a linethrough on the input text */\n linethrough?: boolean\n}\n\nconst {\n modelValue,\n environment,\n type,\n disabled = false,\n error = false,\n layout = 'desktop',\n enum: enumProp,\n examples,\n default: defaultProp,\n nullable = false,\n placeholder,\n required,\n colorPicker = false,\n lineNumbers = false,\n lint = false,\n lineWrapping = false,\n language,\n extensions = [],\n disableTabIndent = false,\n disableEnter = false,\n disableCloseBrackets = false,\n emitOnBlur = true,\n alwaysEmitChange = false,\n withVariables = true,\n handleFieldChange,\n handleFieldSubmit,\n} = defineProps<Props>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n 'submit': [value: string]\n 'blur': [value: string]\n 'navigate': [route: { page: 'document'; path: 'environment' }]\n}>()\n\n// ---------------------------------------------------------------------------\n// Component identity and focus state\n\nconst attrs = useAttrs() as { id?: string }\nconst componentId = attrs.id || `id-${nanoid()}`\nconst isFocused = ref(false)\n\n// ---------------------------------------------------------------------------\n// Rendering mode detection\n\n/**\n * Determines if we should render a select dropdown for boolean types.\n */\nconst isBooleanMode = computed((): boolean => {\n if (enumProp?.length) {\n return false\n }\n return type === 'boolean' || (Array.isArray(type) && type.includes('boolean'))\n})\n\n/**\n * Options for boolean select mode.\n */\nconst booleanOptions = computed((): string[] =>\n nullable ? ['true', 'false', 'null'] : ['true', 'false'],\n)\n\n/**\n * Default type when dealing with type arrays.\n * Finds the first non-null type.\n */\nconst defaultType = computed((): string | undefined => {\n if (Array.isArray(type)) {\n return type.find((t) => t !== 'null') ?? 'string'\n }\n return type\n})\n\n// ---------------------------------------------------------------------------\n// Event handlers\n\n/**\n * Handles value changes during typing.\n */\nconst handleChange = (value: string): void => {\n if (!alwaysEmitChange && value === serializeValue(modelValue)) {\n return\n }\n\n // Use custom handler or emit update\n if (handleFieldChange) {\n handleFieldChange(value)\n } else {\n emit('update:modelValue', value)\n }\n}\n\n/**\n * Handles form submission (enter key or blur with emitOnBlur).\n */\nconst handleSubmit = (value: string): void => {\n if (handleFieldSubmit) {\n handleFieldSubmit(value)\n } else {\n emit('submit', value)\n }\n}\n\n/**\n * Handles input blur event.\n */\nconst handleBlur = (value: string): void => {\n isFocused.value = false\n\n if (emitOnBlur && modelValue) {\n handleSubmit(value)\n }\n\n emit('blur', value)\n}\n\n/**\n * Handles model value updates from select components.\n */\nconst handleSelectChange = (value: string): void =>\n emit('update:modelValue', value)\n\n// ---------------------------------------------------------------------------\n// CodeMirror setup\n\n/**\n * Build extensions array.\n * Note: Extensions are not reactive after initialization.\n */\nconst buildExtensions = (): Extension[] => {\n const extensionsList: Extension[] = [...extensions]\n\n if (colorPicker) {\n extensionsList.push(colorPickerExtension)\n }\n\n return extensionsList\n}\n\n/**\n * Reactive pill plugin for environment variable visualization.\n */\nconst pillPluginExtension = computed(() =>\n pillPlugin({\n environment,\n isReadOnly: layout === 'modal',\n }),\n)\n\n/**\n * Combined extensions for CodeMirror.\n */\nconst codeMirrorExtensions = computed((): Extension[] => [\n ...buildExtensions(),\n pillPluginExtension.value,\n backspaceCommand,\n])\n\nconst codeMirrorRef: Ref<HTMLDivElement | null> = ref(null)\n\n/** Converts the model value to a string for CodeMirror */\nconst serializeValue = (value: CodeInputModelValue): string => {\n if (typeof value === 'string') {\n return value\n }\n return JSON.stringify(value)\n}\n\nconst { codeMirror } = useCodeMirror({\n content: toRef(() => serializeValue(modelValue)),\n onChange: (value) => {\n handleChange(value)\n updateDropdownVisibility()\n },\n onFocus: () => {\n isFocused.value = true\n },\n onBlur: handleBlur,\n codeMirrorRef,\n disableTabIndent: toRef(() => disableTabIndent),\n disableEnter: toRef(() => disableEnter),\n disableCloseBrackets: toRef(() => disableCloseBrackets),\n lineNumbers: toRef(() => lineNumbers),\n language: toRef(() => language),\n lint: toRef(() => lint),\n extensions: codeMirrorExtensions,\n placeholder: toRef(() => placeholder),\n})\n\n/**\n * Handle autofocus attribute.\n */\nwatch(codeMirror, () => {\n if (codeMirror.value && Object.hasOwn(attrs, 'autofocus')) {\n codeMirror.value.focus()\n }\n})\n\n// ---------------------------------------------------------------------------\n// Environment variable dropdown\n\nconst showDropdown = ref(false)\nconst dropdownQuery = ref('')\nconst dropdownPosition = ref({ left: 0, top: 0 })\nconst dropdownRef = ref<InstanceType<\n typeof EnvironmentVariableDropdown\n> | null>(null)\n\nconst { handleDropdownSelect, updateDropdownVisibility } = useDropdown({\n codeMirror,\n query: dropdownQuery,\n showDropdown,\n dropdownPosition,\n})\n\n/**\n * Determines if the environment variable dropdown should be visible.\n */\nconst displayVariablesDropdown = computed((): boolean => {\n return (\n showDropdown.value &&\n withVariables &&\n layout !== 'modal' &&\n Boolean(environment)\n )\n})\n\n// ---------------------------------------------------------------------------\n// Keyboard event handling\n\n/**\n * Handles keyboard navigation for dropdown and form submission.\n */\nconst handleKeyDown = (key: string, event: KeyboardEvent): void => {\n if (showDropdown.value) {\n if (key === 'down' || key === 'up') {\n event.preventDefault()\n dropdownRef.value?.handleArrowKey(key)\n } else if (key === 'enter') {\n event.preventDefault()\n dropdownRef.value?.handleSelect()\n }\n return\n }\n\n if (key === 'escape' && !disableTabIndent) {\n event.stopPropagation()\n }\n\n if (key === 'enter' && event.target instanceof HTMLDivElement) {\n handleSubmit(event.target.textContent ?? '')\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n\ndefineExpose({\n /**\n * Focus the codemirror element\n *\n * @param cursorAtEnd boolean place the cursor at the end of the input\n */\n focus: (position?: 'start' | 'end' | number) => {\n if (!codeMirror.value) {\n return\n }\n codeMirror.value.focus()\n\n if (!isDefined(position)) {\n return\n }\n\n const anchor = (() => {\n if (position === 'start') {\n return 0\n }\n if (position === 'end') {\n return codeMirror.value.state.doc.length\n }\n return position\n })()\n\n // Move the cursor to the specified position\n codeMirror.value.dispatch({\n selection: { anchor },\n scrollIntoView: true,\n })\n },\n isFocused,\n handleChange,\n handleSubmit,\n handleBlur,\n booleanOptions,\n codeMirror,\n modelValue,\n cursorPosition: () => codeMirror.value?.state.selection.main.head,\n serializeValue,\n})\n</script>\n\n<template>\n <!-- Disabled mode: read-only text display -->\n <div\n v-if=\"disabled\"\n class=\"text-c-2 flex cursor-default items-center justify-center\"\n :class=\"{\n 'font-code pr-2 pl-1 text-base': layout === 'modal',\n 'px-2': layout !== 'modal',\n 'line-through': linethrough,\n }\"\n data-testid=\"code-input-disabled\">\n <span class=\"whitespace-nowrap\">{{ modelValue }}</span>\n </div>\n\n <!-- Enum mode: select dropdown with predefined values -->\n <DataTableInputSelect\n v-else-if=\"enumProp?.length\"\n :default=\"defaultProp\"\n :modelValue=\"modelValue\"\n :type=\"defaultType\"\n :value=\"enumProp\"\n @update:modelValue=\"handleSelectChange\" />\n\n <!-- Boolean mode: select dropdown with true/false (and optionally null) -->\n <DataTableInputSelect\n v-else-if=\"isBooleanMode\"\n :default=\"defaultProp\"\n :modelValue=\"modelValue\"\n :value=\"booleanOptions\"\n @update:modelValue=\"handleSelectChange\" />\n\n <!-- Examples mode: select dropdown with example values -->\n <DataTableInputSelect\n v-else-if=\"examples?.length\"\n :default=\"defaultProp\"\n :modelValue=\"modelValue\"\n :value=\"examples\"\n @update:modelValue=\"handleSelectChange\" />\n\n <!-- Editor mode: CodeMirror with environment variable support -->\n <div\n v-else\n :id=\"componentId\"\n v-bind=\"$attrs\"\n ref=\"codeMirrorRef\"\n class=\"group/input group-[.alert]:outline-orange group-[.error]:outline-red font-code peer relative w-full overflow-hidden text-xs leading-[1.44] whitespace-nowrap -outline-offset-1 has-[:focus-visible]:rounded-[4px] has-[:focus-visible]:outline\"\n :class=\"{\n 'line-wrapping has-[:focus-visible]:bg-b-1 has-[:focus-visible]:absolute has-[:focus-visible]:z-1':\n lineWrapping,\n 'flow-code-input--error': error,\n 'line-through': linethrough,\n }\"\n @keydown.down.stop=\"handleKeyDown('down', $event)\"\n @keydown.enter=\"handleKeyDown('enter', $event)\"\n @keydown.escape=\"handleKeyDown('escape', $event)\"\n @keydown.up.stop=\"handleKeyDown('up', $event)\">\n <!-- Tab exit hint (shown when focused) -->\n <div\n v-if=\"!disableTabIndent\"\n class=\"z-context text-c-2 absolute right-1.5 bottom-1 hidden font-sans group-has-[:focus-visible]/input:block\"\n role=\"alert\">\n Press\n <kbd class=\"-mx-0.25 rounded border px-0.5 font-mono\">Esc</kbd> then\n <kbd class=\"-mx-0.25 rounded border px-0.5 font-mono\">Tab</kbd> to exit\n </div>\n </div>\n\n <!-- Warning slot (positioned absolutely) -->\n <div\n v-if=\"$slots.warning\"\n class=\"centered-y text-orange absolute right-7 text-xs\">\n <slot name=\"warning\" />\n </div>\n\n <!-- Icon slot (positioned absolutely) -->\n <div\n v-if=\"$slots.icon\"\n class=\"centered-y absolute right-0 flex h-full items-center p-1.5 group-has-[.cm-focused]:z-1\">\n <slot name=\"icon\" />\n </div>\n\n <!-- Required indicator -->\n <div\n v-if=\"required\"\n class=\"required centered-y text-xxs text-c-3 group-[.error]:text-red bg-b-1 pointer-events-none absolute right-0 mr-0.5 pt-px pr-2 opacity-100 shadow-[-8px_0_4px_var(--scalar-background-1)] transition-opacity duration-150 group-[.alert]:bg-transparent group-[.alert]:shadow-none group-[.error]:bg-transparent group-[.error]:shadow-none peer-has-[.cm-focused]:opacity-0\">\n Required\n </div>\n\n <!-- Environment variable autocomplete dropdown -->\n <EnvironmentVariableDropdown\n v-if=\"displayVariablesDropdown && environment\"\n ref=\"dropdownRef\"\n :dropdownPosition=\"dropdownPosition\"\n :environment=\"environment\"\n :query=\"dropdownQuery\"\n @redirect=\"emit('navigate', { page: 'document', path: 'environment' })\"\n @select=\"handleDropdownSelect\" />\n</template>\n<style scoped>\n/*\n Deep styling for customizing Codemirror\n */\n:deep(.cm-editor) {\n height: 100%;\n outline: none;\n padding: 0;\n background: transparent;\n}\n:deep(.cm-placeholder) {\n color: var(--scalar-color-3);\n}\n:deep(.cm-content) {\n font-family: var(--scalar-font-code);\n font-size: var(--scalar-small);\n max-height: 20px;\n padding: 8px 0;\n}\n/* Tooltip helper */\n:deep(.cm-tooltip) {\n background: transparent !important;\n filter: brightness(var(--scalar-lifted-brightness));\n border-radius: var(--scalar-radius);\n box-shadow: var(--scalar-shadow-2);\n border: none !important;\n outline: none !important;\n overflow: hidden !important;\n}\n:deep(.cm-tooltip-autocomplete ul li) {\n padding: 3px 6px !important;\n}\n:deep(.cm-completionIcon-type:after) {\n color: var(--scalar-color-3) !important;\n}\n:deep(.cm-tooltip-autocomplete ul li[aria-selected]) {\n background: var(--scalar-background-2) !important;\n color: var(--scalar-color-1) !important;\n}\n:deep(.cm-tooltip-autocomplete ul) {\n padding: 6px !important;\n position: relative;\n}\n:deep(.cm-tooltip-autocomplete ul li:hover) {\n border-radius: 3px;\n color: var(--scalar-color-1) !important;\n background: var(--scalar-background-3) !important;\n}\n/* Disable active line highlighting */\n:deep(.cm-activeLine),\n:deep(.cm-activeLineGutter) {\n background-color: transparent;\n}\n/* Color selection matching */\n:deep(.cm-selectionMatch),\n:deep(.cm-matchingBracket) {\n border-radius: var(--scalar-radius);\n background: var(--scalar-background-4) !important;\n}\n/* Color Picker Swatches */\n:deep(.cm-css-color-picker-wrapper) {\n display: inline-flex;\n outline: 1px solid var(--scalar-background-3);\n border-radius: 3px;\n overflow: hidden;\n}\n/* Number gutter */\n:deep(.cm-gutters) {\n background-color: transparent;\n border-right: none;\n color: var(--scalar-color-3);\n font-size: var(--scalar-small);\n line-height: 22px;\n border-radius: 0 0 0 3px;\n}\n:deep(.cm-gutters:before) {\n content: '';\n position: absolute;\n top: 2px;\n left: 2px;\n width: calc(100% - 2px);\n height: calc(100% - 4px);\n border-radius: var(--scalar-radius) 0 0 var(--scalar-radius);\n background-color: var(--scalar-background-1);\n}\n:deep(.cm-gutterElement) {\n font-family: var(--scalar-font-code) !important;\n padding-left: 0px !important;\n padding-right: 6px !important;\n display: flex;\n align-items: center;\n justify-content: flex-end;\n position: relative;\n}\n:deep(.cm-lineNumbers .cm-gutterElement) {\n min-width: fit-content;\n}\n:deep(.cm-gutter + .cm-gutter :not(.cm-foldGutter) .cm-gutterElement) {\n padding-left: 0 !important;\n}\n:deep(.cm-scroller) {\n overflow: auto;\n}\n.line-wrapping:focus-within :deep(.cm-content) {\n display: inline-table;\n min-height: fit-content;\n padding: 3px 6px;\n white-space: break-spaces;\n word-break: break-all;\n}\n</style>\n<style>\n.cm-pill {\n color: var(--scalar-color-1) !important;\n padding: 0px 9px;\n border-radius: 3px;\n display: inline-block;\n border-radius: 30px;\n font-size: var(--scalar-small);\n}\n.light-mode .cm-pill {\n background: var(--scalar-background-3) !important;\n}\n.dark-mode .cm-pill {\n background: color-mix(in srgb, var(--tw-bg-base), transparent 90%) !important;\n}\n.cm-pill:first-of-type {\n margin-left: 0;\n}\n.cm-editor .cm-widgetBuffer {\n display: none;\n}\n.cm-foldPlaceholder:hover {\n color: var(--scalar-color-1);\n}\n.cm-foldGutter .cm-gutterElement {\n font-size: var(--scalar-heading-4);\n padding: 2px !important;\n}\n.cm-foldGutter .cm-gutterElement:first-of-type {\n display: none;\n}\n.cm-foldGutter .cm-gutterElement .cm-foldMarker {\n padding: 2px;\n padding-top: 2px;\n}\n.cm-foldGutter .cm-gutterElement:hover .cm-foldMarker {\n background: var(--scalar-background-2);\n border-radius: var(--scalar-radius);\n color: var(--scalar-color-1);\n}\n</style>\n"],"mappings":"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"}
|
package/dist/v2/constants.js
CHANGED
|
@@ -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.
|
|
3
|
+
var APP_VERSION = typeof OVERRIDE_PACKAGE_VERSION !== "undefined" ? OVERRIDE_PACKAGE_VERSION : "2.39.4";
|
|
4
4
|
//#endregion
|
|
5
5
|
export { APP_VERSION };
|
|
6
6
|
|
|
@@ -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.
|
|
48
|
+
const packageVersion = "2.39.4";
|
|
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.
|
|
21
|
+
"version": "2.39.4",
|
|
22
22
|
"engines": {
|
|
23
23
|
"node": ">=22"
|
|
24
24
|
},
|
|
@@ -347,24 +347,24 @@
|
|
|
347
347
|
"whatwg-mimetype": "4.0.0",
|
|
348
348
|
"yaml": "^2.8.0",
|
|
349
349
|
"zod": "^4.3.5",
|
|
350
|
-
"@scalar/components": "0.21.
|
|
350
|
+
"@scalar/components": "0.21.2",
|
|
351
|
+
"@scalar/helpers": "0.4.2",
|
|
351
352
|
"@scalar/draggable": "0.4.1",
|
|
353
|
+
"@scalar/icons": "0.7.1",
|
|
352
354
|
"@scalar/import": "0.5.3",
|
|
353
|
-
"@scalar/helpers": "0.4.2",
|
|
354
355
|
"@scalar/json-magic": "0.12.4",
|
|
355
|
-
"@scalar/
|
|
356
|
-
"@scalar/oas-utils": "0.10.13",
|
|
357
|
-
"@scalar/openapi-types": "0.6.1",
|
|
356
|
+
"@scalar/oas-utils": "0.10.14",
|
|
358
357
|
"@scalar/object-utils": "1.3.3",
|
|
358
|
+
"@scalar/openapi-types": "0.6.1",
|
|
359
359
|
"@scalar/postman-to-openapi": "0.6.0",
|
|
360
|
-
"@scalar/sidebar": "0.8.
|
|
360
|
+
"@scalar/sidebar": "0.8.16",
|
|
361
361
|
"@scalar/snippetz": "0.7.7",
|
|
362
|
-
"@scalar/themes": "0.15.1",
|
|
363
362
|
"@scalar/types": "0.7.5",
|
|
363
|
+
"@scalar/themes": "0.15.1",
|
|
364
364
|
"@scalar/use-codemirror": "0.14.10",
|
|
365
365
|
"@scalar/use-hooks": "0.4.1",
|
|
366
|
-
"@scalar/
|
|
367
|
-
"@scalar/
|
|
366
|
+
"@scalar/use-toasts": "0.10.1",
|
|
367
|
+
"@scalar/workspace-store": "0.42.0"
|
|
368
368
|
},
|
|
369
369
|
"devDependencies": {
|
|
370
370
|
"@tailwindcss/vite": "^4.2.0",
|
|
@@ -380,7 +380,7 @@
|
|
|
380
380
|
"vite-svg-loader": "5.1.1",
|
|
381
381
|
"vitest": "4.1.0",
|
|
382
382
|
"@scalar/galaxy": "0.6.1",
|
|
383
|
-
"@scalar/pre-post-request-scripts": "0.3.
|
|
383
|
+
"@scalar/pre-post-request-scripts": "0.3.16"
|
|
384
384
|
},
|
|
385
385
|
"scripts": {
|
|
386
386
|
"build": "vite build && vue-tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|