@scalar/api-client 3.21.5 → 3.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/hooks/use-file-dialog.js +1 -1
  3. package/dist/hooks/use-file-dialog.js.map +1 -1
  4. package/dist/style.css +1226 -69
  5. package/dist/styles/tailwind.config.css +1 -0
  6. package/dist/v2/blocks/operation-block/helpers/persist-response-cookies.d.ts +3 -3
  7. package/dist/v2/blocks/operation-block/helpers/persist-response-cookies.d.ts.map +1 -1
  8. package/dist/v2/blocks/operation-block/helpers/persist-response-cookies.js +4 -4
  9. package/dist/v2/blocks/operation-block/helpers/persist-response-cookies.js.map +1 -1
  10. package/dist/v2/blocks/operation-block/helpers/validate-path-parameters.js +1 -1
  11. package/dist/v2/blocks/operation-block/helpers/validate-path-parameters.js.map +1 -1
  12. package/dist/v2/blocks/request-block/RequestBlock.vue.d.ts.map +1 -1
  13. package/dist/v2/blocks/request-block/RequestBlock.vue.js +1 -1
  14. package/dist/v2/blocks/request-block/RequestBlock.vue.js.map +1 -1
  15. package/dist/v2/blocks/request-block/RequestBlock.vue.script.js +13 -8
  16. package/dist/v2/blocks/request-block/RequestBlock.vue.script.js.map +1 -1
  17. package/dist/v2/blocks/request-block/components/RequestBody.vue.d.ts.map +1 -1
  18. package/dist/v2/blocks/request-block/components/RequestBody.vue.js +1 -1
  19. package/dist/v2/blocks/request-block/components/RequestBody.vue.js.map +1 -1
  20. package/dist/v2/blocks/request-block/components/RequestBody.vue.script.js +64 -13
  21. package/dist/v2/blocks/request-block/components/RequestBody.vue.script.js.map +1 -1
  22. package/dist/v2/blocks/request-block/components/RequestBodyForm.vue.d.ts +2 -0
  23. package/dist/v2/blocks/request-block/components/RequestBodyForm.vue.d.ts.map +1 -1
  24. package/dist/v2/blocks/request-block/components/RequestBodyForm.vue.js.map +1 -1
  25. package/dist/v2/blocks/request-block/components/RequestBodyForm.vue.script.js +5 -3
  26. package/dist/v2/blocks/request-block/components/RequestBodyForm.vue.script.js.map +1 -1
  27. package/dist/v2/blocks/request-block/components/RequestBodyViewToggle.vue.d.ts +9 -3
  28. package/dist/v2/blocks/request-block/components/RequestBodyViewToggle.vue.d.ts.map +1 -1
  29. package/dist/v2/blocks/request-block/components/RequestBodyViewToggle.vue.js.map +1 -1
  30. package/dist/v2/blocks/request-block/components/RequestBodyViewToggle.vue.script.js +44 -16
  31. package/dist/v2/blocks/request-block/components/RequestBodyViewToggle.vue.script.js.map +1 -1
  32. package/dist/v2/blocks/request-block/components/RequestParams.vue.d.ts +12 -0
  33. package/dist/v2/blocks/request-block/components/RequestParams.vue.d.ts.map +1 -1
  34. package/dist/v2/blocks/request-block/components/RequestParams.vue.js.map +1 -1
  35. package/dist/v2/blocks/request-block/components/RequestParams.vue.script.js +132 -32
  36. package/dist/v2/blocks/request-block/components/RequestParams.vue.script.js.map +1 -1
  37. package/dist/v2/blocks/request-block/components/RequestTable.vue.d.ts +3 -1
  38. package/dist/v2/blocks/request-block/components/RequestTable.vue.d.ts.map +1 -1
  39. package/dist/v2/blocks/request-block/components/RequestTable.vue.js +1 -1
  40. package/dist/v2/blocks/request-block/components/RequestTable.vue.js.map +1 -1
  41. package/dist/v2/blocks/request-block/components/RequestTable.vue.script.js +13 -2
  42. package/dist/v2/blocks/request-block/components/RequestTable.vue.script.js.map +1 -1
  43. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.d.ts +3 -1
  44. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.d.ts.map +1 -1
  45. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.js.map +1 -1
  46. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.script.js +6 -2
  47. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.script.js.map +1 -1
  48. package/dist/v2/blocks/request-block/helpers/create-parameter-handlers.d.ts.map +1 -1
  49. package/dist/v2/blocks/request-block/helpers/create-parameter-handlers.js +10 -3
  50. package/dist/v2/blocks/request-block/helpers/create-parameter-handlers.js.map +1 -1
  51. package/dist/v2/blocks/request-block/helpers/create-parameter-rows.d.ts.map +1 -1
  52. package/dist/v2/blocks/request-block/helpers/create-parameter-rows.js +10 -1
  53. package/dist/v2/blocks/request-block/helpers/create-parameter-rows.js.map +1 -1
  54. package/dist/v2/blocks/request-block/helpers/get-form-body-rows.d.ts +3 -2
  55. package/dist/v2/blocks/request-block/helpers/get-form-body-rows.d.ts.map +1 -1
  56. package/dist/v2/blocks/request-block/helpers/get-form-body-rows.js +14 -11
  57. package/dist/v2/blocks/request-block/helpers/get-form-body-rows.js.map +1 -1
  58. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBarHistory.vue.d.ts.map +1 -1
  59. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBarHistory.vue.js +1 -1
  60. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBarHistory.vue.js.map +1 -1
  61. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBarHistory.vue.script.js +3 -3
  62. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBarHistory.vue.script.js.map +1 -1
  63. package/dist/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue.script.js.map +1 -1
  64. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.d.ts.map +1 -1
  65. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.js.map +1 -1
  66. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.script.js +55 -16
  67. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.script.js.map +1 -1
  68. package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthDataTableInput.vue.d.ts +3 -3
  69. package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthDataTableInput.vue.d.ts.map +1 -1
  70. package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthDataTableInput.vue.js.map +1 -1
  71. package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthDataTableInput.vue.script.js +20 -7
  72. package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthDataTableInput.vue.script.js.map +1 -1
  73. package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthTab.vue.d.ts.map +1 -1
  74. package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthTab.vue.js.map +1 -1
  75. package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthTab.vue.script.js +32 -27
  76. package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthTab.vue.script.js.map +1 -1
  77. package/dist/v2/blocks/scalar-auth-selector-block/helpers/openid-discovery-to-flows.d.ts.map +1 -1
  78. package/dist/v2/blocks/scalar-auth-selector-block/helpers/openid-discovery-to-flows.js +2 -1
  79. package/dist/v2/blocks/scalar-auth-selector-block/helpers/openid-discovery-to-flows.js.map +1 -1
  80. package/dist/v2/components/code-input/CodeInput.vue.d.ts.map +1 -1
  81. package/dist/v2/components/code-input/CodeInput.vue.js +1 -1
  82. package/dist/v2/components/code-input/CodeInput.vue.js.map +1 -1
  83. package/dist/v2/components/code-input/CodeInput.vue.script.js.map +1 -1
  84. package/dist/v2/components/code-input/PillTooltipHost.vue.d.ts.map +1 -1
  85. package/dist/v2/components/code-input/PillTooltipHost.vue.js.map +1 -1
  86. package/dist/v2/components/code-input/PillTooltipHost.vue.script.js +4 -1
  87. package/dist/v2/components/code-input/PillTooltipHost.vue.script.js.map +1 -1
  88. package/dist/v2/components/code-input/code-variable-widget.js +1 -1
  89. package/dist/v2/components/code-input/code-variable-widget.js.map +1 -1
  90. package/dist/v2/components/data-table/DataTableInput.vue.d.ts +3 -1
  91. package/dist/v2/components/data-table/DataTableInput.vue.d.ts.map +1 -1
  92. package/dist/v2/components/data-table/DataTableInput.vue.js +1 -1
  93. package/dist/v2/components/data-table/DataTableInput.vue.js.map +1 -1
  94. package/dist/v2/components/data-table/DataTableInput.vue.script.js +46 -15
  95. package/dist/v2/components/data-table/DataTableInput.vue.script.js.map +1 -1
  96. package/dist/v2/components/server/ServerDropdown.vue.d.ts.map +1 -1
  97. package/dist/v2/components/server/ServerDropdown.vue.js.map +1 -1
  98. package/dist/v2/components/server/ServerDropdown.vue.script.js +7 -9
  99. package/dist/v2/components/server/ServerDropdown.vue.script.js.map +1 -1
  100. package/dist/v2/constants.js +1 -1
  101. package/dist/v2/features/environments/components/EnvironmentVariablesDropdown.vue.d.ts.map +1 -1
  102. package/dist/v2/features/environments/components/EnvironmentVariablesDropdown.vue.js.map +1 -1
  103. package/dist/v2/features/environments/components/EnvironmentVariablesDropdown.vue.script.js +27 -31
  104. package/dist/v2/features/environments/components/EnvironmentVariablesDropdown.vue.script.js.map +1 -1
  105. package/dist/v2/features/localization/index.d.ts.map +1 -1
  106. package/dist/v2/features/localization/index.js +2 -0
  107. package/dist/v2/features/localization/index.js.map +1 -1
  108. package/dist/v2/features/localization/locales/ar.d.ts +4 -0
  109. package/dist/v2/features/localization/locales/ar.d.ts.map +1 -1
  110. package/dist/v2/features/localization/locales/ar.js +4 -0
  111. package/dist/v2/features/localization/locales/ar.js.map +1 -1
  112. package/dist/v2/features/localization/locales/de.d.ts +4 -0
  113. package/dist/v2/features/localization/locales/de.d.ts.map +1 -1
  114. package/dist/v2/features/localization/locales/de.js +4 -0
  115. package/dist/v2/features/localization/locales/de.js.map +1 -1
  116. package/dist/v2/features/localization/locales/es.d.ts +4 -0
  117. package/dist/v2/features/localization/locales/es.d.ts.map +1 -1
  118. package/dist/v2/features/localization/locales/es.js +4 -0
  119. package/dist/v2/features/localization/locales/es.js.map +1 -1
  120. package/dist/v2/features/localization/locales/fr.d.ts +4 -0
  121. package/dist/v2/features/localization/locales/fr.d.ts.map +1 -1
  122. package/dist/v2/features/localization/locales/fr.js +4 -0
  123. package/dist/v2/features/localization/locales/fr.js.map +1 -1
  124. package/dist/v2/features/localization/locales/pt.d.ts +4 -0
  125. package/dist/v2/features/localization/locales/pt.d.ts.map +1 -1
  126. package/dist/v2/features/localization/locales/pt.js +4 -0
  127. package/dist/v2/features/localization/locales/pt.js.map +1 -1
  128. package/dist/v2/features/localization/locales/ru.d.ts +4 -0
  129. package/dist/v2/features/localization/locales/ru.d.ts.map +1 -1
  130. package/dist/v2/features/localization/locales/ru.js +4 -0
  131. package/dist/v2/features/localization/locales/ru.js.map +1 -1
  132. package/dist/v2/features/localization/locales/zh-cn.d.ts +4 -0
  133. package/dist/v2/features/localization/locales/zh-cn.d.ts.map +1 -1
  134. package/dist/v2/features/localization/locales/zh-cn.js +4 -0
  135. package/dist/v2/features/localization/locales/zh-cn.js.map +1 -1
  136. package/dist/v2/features/localization/locales/zh-tw.d.ts +398 -0
  137. package/dist/v2/features/localization/locales/zh-tw.d.ts.map +1 -0
  138. package/dist/v2/features/localization/locales/zh-tw.js +360 -0
  139. package/dist/v2/features/localization/locales/zh-tw.js.map +1 -0
  140. package/dist/v2/features/localization/translations.d.ts +4 -0
  141. package/dist/v2/features/localization/translations.d.ts.map +1 -1
  142. package/dist/v2/features/localization/translations.js +4 -0
  143. package/dist/v2/features/localization/translations.js.map +1 -1
  144. package/dist/v2/features/modal/index.d.ts +1 -1
  145. package/dist/v2/features/modal/index.d.ts.map +1 -1
  146. package/dist/v2/helpers/handle-hotkeys.d.ts.map +1 -1
  147. package/dist/v2/helpers/handle-hotkeys.js +4 -1
  148. package/dist/v2/helpers/handle-hotkeys.js.map +1 -1
  149. package/dist/vue-styles.css +39 -40
  150. package/package.json +13 -13
@@ -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 autocomplete for environment variables and runtime context functions\n * (for example `{{$guid}}`) 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 { ScalarIconButton } from '@scalar/components/icon-button'\nimport { isDefined } from '@scalar/helpers/array/is-defined'\nimport { ScalarIconArrowElbowDownLeft } from '@scalar/icons'\nimport {\n colorPicker as colorPickerExtension,\n EditorView,\n useCodeMirror,\n useDropdown,\n type CodeMirrorLanguage,\n type Extension,\n} from '@scalar/use-codemirror'\nimport {\n CONTEXT_FUNCTION_NAMES,\n getContextFunctionComment,\n isContextFunctionName,\n} from '@scalar/workspace-store/request-example'\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 { useLocalization } from '@/v2/features/localization'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nimport { backspaceCommand, pillPlugin } from './code-variable-widget'\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 withFakeData = false,\n handleFieldChange,\n handleFieldSubmit,\n} = defineProps<Props>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n 'submit': [value: string, event: KeyboardEvent | FocusEvent]\n 'navigate': [route: { page: 'document'; path: 'environment' }]\n 'blur': [value: string, event: FocusEvent]\n}>()\n\nconst { translate } = useLocalization()\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 /** Enable fake data suggestions like $guid, $timestamp, etc. Should only be enabled for parameters and request bodies */\n withFakeData?: 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\n// ---------------------------------------------------------------------------\n// Component identity and focus state\n\nconst attrs = useAttrs()\nconst componentId =\n (typeof attrs.id === 'string' && 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 = (\n value: string,\n event: KeyboardEvent | FocusEvent,\n): void => {\n if (handleFieldSubmit) {\n handleFieldSubmit(value)\n } else {\n emit('submit', value, event)\n }\n}\n\n/**\n * Handles input blur event.\n */\nconst handleBlur = (value: string, event: FocusEvent): void => {\n isFocused.value = false\n\n if (emitOnBlur && modelValue) {\n handleSubmit(value, event)\n }\n\n emit('blur', value, event)\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 contextFunctionDropdownItems = computed(() =>\n withFakeData\n ? CONTEXT_FUNCTION_NAMES.map((key) => ({\n key,\n description: getContextFunctionComment(key),\n }))\n : [],\n)\n\nconst pillPluginExtension = computed(() =>\n pillPlugin({\n environment,\n isContextFunctionName,\n isReadOnly: layout === 'modal',\n translate,\n }),\n)\n\nconst isLineWrapping = ref(lineWrapping)\n\nwatch(\n () => lineWrapping,\n (val) => {\n isLineWrapping.value = val\n },\n)\n\nconst toggleLineWrapping = (): void => {\n isLineWrapping.value = !isLineWrapping.value\n}\n\nconst lineWrappingExtension = computed(() =>\n isLineWrapping.value ? [EditorView.lineWrapping] : [],\n)\n\n/**\n * Combined extensions for CodeMirror.\n */\nconst codeMirrorExtensions = computed((): Extension[] => [\n ...buildExtensions(),\n ...lineWrappingExtension.value,\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, setCodeMirrorContent } = 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 * Shows when environment is defined (for env vars) or withFakeData is true (for context functions)\n */\nconst displayVariablesDropdown = computed((): boolean => {\n return (\n showDropdown.value &&\n withVariables &&\n layout !== 'modal' &&\n (Boolean(environment) || withFakeData)\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(codeMirror.value?.state.doc.toString() ?? '', event)\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 codeMirrorRef,\n modelValue,\n setCodeMirrorContent,\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 <!-- Wrap toggle button for multi-line editor (e.g. Request Body) -->\n <div\n v-if=\"lineNumbers\"\n class=\"absolute top-2 right-2 z-10 flex items-center opacity-0 transition-opacity duration-150 group-hover/input:opacity-100 group-has-focus-visible/input:opacity-100\">\n <ScalarIconButton\n class=\"bg-b-2 text-c-2 hover:text-c-1\"\n :class=\"{ '!bg-b-3 !text-c-1': isLineWrapping }\"\n :icon=\"ScalarIconArrowElbowDownLeft\"\n :aria-pressed=\"isLineWrapping\"\n :aria-label=\"isLineWrapping ? 'Disable line wrap' : 'Wrap lines'\"\n :label=\"isLineWrapping ? 'Disable line wrap' : 'Wrap lines'\"\n size=\"sm\"\n tooltip\n variant=\"ghost\"\n @click.stop=\"toggleLineWrapping\" />\n </div>\n\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 {{\n translate('apiClient.codeInput.exitHint', { escape: 'Esc', tab: 'Tab' })\n }}\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 {{ translate('apiClient.codeInput.required') }}\n </div>\n\n <!-- Environment variable autocomplete dropdown -->\n <EnvironmentVariableDropdown\n v-if=\"displayVariablesDropdown\"\n ref=\"dropdownRef\"\n :contextFunctionItems=\"contextFunctionDropdownItems\"\n :dropdownPosition=\"dropdownPosition\"\n :environment=\"environment\"\n :query=\"dropdownQuery\"\n @close=\"showDropdown = false\"\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 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:deep(.cm-lineWrapping .cm-line) {\n word-break: break-all;\n}\n:deep(.cm-content.cm-lineWrapping) {\n white-space: pre-wrap;\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 display: inline-block;\n border-radius: var(--scalar-radius-full);\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--context-fn {\n border: 1px dashed color-mix(in srgb, var(--scalar-color-3), transparent 35%);\n padding: 0px 8px;\n}\n.light-mode .cm-pill--context-fn {\n background: color-mix(\n in srgb,\n var(--scalar-background-3),\n transparent 40%\n ) !important;\n}\n.dark-mode .cm-pill--context-fn {\n background: color-mix(\n in srgb,\n var(--scalar-background-3),\n transparent 55%\n ) !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 autocomplete for environment variables and runtime context functions\n * (for example `{{$guid}}`) 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 { ScalarIconButton } from '@scalar/components/icon-button'\nimport { isDefined } from '@scalar/helpers/array/is-defined'\nimport { ScalarIconArrowElbowDownLeft } from '@scalar/icons'\nimport {\n colorPicker as colorPickerExtension,\n EditorView,\n useCodeMirror,\n useDropdown,\n type CodeMirrorLanguage,\n type Extension,\n} from '@scalar/use-codemirror'\nimport {\n CONTEXT_FUNCTION_NAMES,\n getContextFunctionComment,\n isContextFunctionName,\n} from '@scalar/workspace-store/request-example'\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 { useLocalization } from '@/v2/features/localization'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nimport { backspaceCommand, pillPlugin } from './code-variable-widget'\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 withFakeData = false,\n handleFieldChange,\n handleFieldSubmit,\n} = defineProps<Props>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n 'submit': [value: string, event: KeyboardEvent | FocusEvent]\n 'navigate': [route: { page: 'document'; path: 'environment' }]\n 'blur': [value: string, event: FocusEvent]\n}>()\n\nconst { translate } = useLocalization()\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 /** Enable fake data suggestions like $guid, $timestamp, etc. Should only be enabled for parameters and request bodies */\n withFakeData?: 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\n// ---------------------------------------------------------------------------\n// Component identity and focus state\n\nconst attrs = useAttrs()\nconst componentId =\n (typeof attrs.id === 'string' && 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 = (\n value: string,\n event: KeyboardEvent | FocusEvent,\n): void => {\n if (handleFieldSubmit) {\n handleFieldSubmit(value)\n } else {\n emit('submit', value, event)\n }\n}\n\n/**\n * Handles input blur event.\n */\nconst handleBlur = (value: string, event: FocusEvent): void => {\n isFocused.value = false\n\n if (emitOnBlur && modelValue) {\n handleSubmit(value, event)\n }\n\n emit('blur', value, event)\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 contextFunctionDropdownItems = computed(() =>\n withFakeData\n ? CONTEXT_FUNCTION_NAMES.map((key) => ({\n key,\n description: getContextFunctionComment(key),\n }))\n : [],\n)\n\nconst pillPluginExtension = computed(() =>\n pillPlugin({\n environment,\n isContextFunctionName,\n isReadOnly: layout === 'modal',\n translate,\n }),\n)\n\nconst isLineWrapping = ref(lineWrapping)\n\nwatch(\n () => lineWrapping,\n (val) => {\n isLineWrapping.value = val\n },\n)\n\nconst toggleLineWrapping = (): void => {\n isLineWrapping.value = !isLineWrapping.value\n}\n\nconst lineWrappingExtension = computed(() =>\n isLineWrapping.value ? [EditorView.lineWrapping] : [],\n)\n\n/**\n * Combined extensions for CodeMirror.\n */\nconst codeMirrorExtensions = computed((): Extension[] => [\n ...buildExtensions(),\n ...lineWrappingExtension.value,\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, setCodeMirrorContent } = 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 * Shows when environment is defined (for env vars) or withFakeData is true (for context functions)\n */\nconst displayVariablesDropdown = computed((): boolean => {\n return (\n showDropdown.value &&\n withVariables &&\n layout !== 'modal' &&\n (Boolean(environment) || withFakeData)\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(codeMirror.value?.state.doc.toString() ?? '', event)\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 codeMirrorRef,\n modelValue,\n setCodeMirrorContent,\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 <!-- Wrap toggle button for multi-line editor (e.g. Request Body) -->\n <div\n v-if=\"lineNumbers\"\n class=\"absolute top-2 right-2 z-10 flex items-center opacity-0 transition-opacity duration-150 group-hover/input:opacity-100 group-has-focus-visible/input:opacity-100\">\n <ScalarIconButton\n class=\"bg-b-2 text-c-2 hover:text-c-1\"\n :class=\"{ '!bg-b-3 !text-c-1': isLineWrapping }\"\n :icon=\"ScalarIconArrowElbowDownLeft\"\n :aria-pressed=\"isLineWrapping\"\n :aria-label=\"isLineWrapping ? 'Disable line wrap' : 'Wrap lines'\"\n :label=\"isLineWrapping ? 'Disable line wrap' : 'Wrap lines'\"\n size=\"sm\"\n tooltip\n variant=\"ghost\"\n @click.stop=\"toggleLineWrapping\" />\n </div>\n\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 {{\n translate('apiClient.codeInput.exitHint', { escape: 'Esc', tab: 'Tab' })\n }}\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 {{ translate('apiClient.codeInput.required') }}\n </div>\n\n <!-- Environment variable autocomplete dropdown -->\n <EnvironmentVariableDropdown\n v-if=\"displayVariablesDropdown\"\n ref=\"dropdownRef\"\n :contextFunctionItems=\"contextFunctionDropdownItems\"\n :dropdownPosition=\"dropdownPosition\"\n :environment=\"environment\"\n :query=\"dropdownQuery\"\n @close=\"showDropdown = false\"\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 padding: 8px 0;\n}\n/* Tooltip helper */\n:deep(.cm-tooltip) {\n background: var(--scalar-background-1) !important;\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:deep(.cm-lineWrapping .cm-line) {\n word-break: break-all;\n}\n:deep(.cm-content.cm-lineWrapping) {\n white-space: pre-wrap;\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 display: inline-block;\n border-radius: var(--scalar-radius-full);\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--context-fn {\n border: 1px dashed color-mix(in srgb, var(--scalar-color-3), transparent 35%);\n padding: 0px 8px;\n}\n.light-mode .cm-pill--context-fn {\n background: color-mix(\n in srgb,\n var(--scalar-background-3),\n transparent 40%\n ) !important;\n}\n.dark-mode .cm-pill--context-fn {\n background: color-mix(\n in srgb,\n var(--scalar-background-3),\n transparent 55%\n ) !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 +1 @@
1
- {"version":3,"file":"PillTooltipHost.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/components/code-input/PillTooltipHost.vue"],"names":[],"mappings":"AA2GA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAGvD,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,4BAA4B,CAAA;AAEnC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAEjD,KAAK,WAAW,GAAG;IACjB,uEAAuE;IACvE,OAAO,EAAE,WAAW,CAAA;IACpB,gDAAgD;IAChD,MAAM,EAAE,WAAW,CAAA;IACnB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,WAAW,CAAC,uBAAuB,CAAC,CAAA;CACjD,CAAC;AAmEF,QAAA,MAAM,YAAY,kSAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
1
+ {"version":3,"file":"PillTooltipHost.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/components/code-input/PillTooltipHost.vue"],"names":[],"mappings":"AA4GA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAGvD,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,4BAA4B,CAAA;AAEnC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAEjD,KAAK,WAAW,GAAG;IACjB,uEAAuE;IACvE,OAAO,EAAE,WAAW,CAAA;IACpB,gDAAgD;IAChD,MAAM,EAAE,WAAW,CAAA;IACnB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,WAAW,CAAC,uBAAuB,CAAC,CAAA;CACjD,CAAC;AAoEF,QAAA,MAAM,YAAY,kSAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
@@ -1 +1 @@
1
- {"version":3,"file":"PillTooltipHost.vue.js","names":[],"sources":["../../../../src/v2/components/code-input/PillTooltipHost.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * PillTooltipHost\n *\n * Renderless adapter that attaches a tooltip to an existing DOM element.\n * Both the legacy CodeMirror widget pipeline and the new `CodeInputLite`\n * overlay mount one of these per pill via `createApp` — they keep ownership\n * of the pill DOM (text, classes, styles) and we only attach hover/focus\n * behaviour through `useTooltip`.\n *\n * The component renders nothing of its own; pass the pill element via the\n * `target` prop and `useTooltip` will wire mouseenter/mouseleave/focus/blur\n * listeners onto it directly.\n */\nimport { useTooltip } from '@scalar/components/tooltip'\nimport type { TranslateFn } from '@scalar/localization'\nimport { computed, h, ref, render } from 'vue'\n\nimport {\n useLocalization,\n type ApiClientTranslationKey,\n} from '@/v2/features/localization'\n\nimport type { PillContext } from './pill-context'\n\nconst props = defineProps<{\n /** Tooltip data — environment value or context-function description */\n context: PillContext\n /** The pill element to attach the tooltip to */\n target: HTMLElement\n /** Carry the owning editor's locale into this separately mounted Vue app. */\n translate?: TranslateFn<ApiClientTranslationKey>\n}>()\n\nconst { translate: fallbackTranslate } = useLocalization()\n\ndefineOptions({ name: 'PillTooltipHost' })\n\nconst translate = props.translate ?? fallbackTranslate\n\nconst isContextFn = props.context.type === 'contextFunction'\n\n/** Two-line HTML body for context-function tooltips. */\nconst contextTooltipHtml = computed(() => {\n if (\n !isContextFn ||\n typeof document === 'undefined' ||\n props.context.type !== 'contextFunction'\n ) {\n return ''\n }\n const el = document.createElement('div')\n render(\n h('div', { class: 'flex flex-col gap-1.5 text-left' }, [\n h('span', {}, props.context.details),\n h(\n 'div',\n { class: 'text-[color:var(--scalar-color-3)] text-[10px] font-normal' },\n translate('apiClient.pillTooltipHost.computedAtExecution'),\n ),\n ]),\n el,\n )\n return el.innerHTML\n})\n\nconst environmentTooltipText = computed(() =>\n props.context.type === 'environment'\n ? props.context.isDefined\n ? props.context.value\n : translate('apiClient.pillTooltipHost.noValue')\n : '',\n)\n\nconst targetRef = ref<HTMLElement>(props.target)\n\nuseTooltip({\n content: isContextFn ? contextTooltipHtml : environmentTooltipText,\n contentTarget: isContextFn ? 'innerHTML' : 'textContent',\n delay: 0,\n placement: 'bottom-start',\n offset: 6,\n targetRef,\n})\n</script>\n\n<!-- eslint-disable vue/valid-template-root -- Renderless: the tooltip attaches to the supplied target. -->\n<template>\n <!-- Renderless: behaviour attaches to props.target via useTooltip -->\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"PillTooltipHost.vue.js","names":[],"sources":["../../../../src/v2/components/code-input/PillTooltipHost.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * PillTooltipHost\n *\n * Renderless adapter that attaches a tooltip to an existing DOM element.\n * Both the legacy CodeMirror widget pipeline and the new `CodeInputLite`\n * overlay mount one of these per pill via `createApp` — they keep ownership\n * of the pill DOM (text, classes, styles) and we only attach hover/focus\n * behaviour through `useTooltip`.\n *\n * The component renders nothing of its own; pass the pill element via the\n * `target` prop and `useTooltip` will wire mouseenter/mouseleave/focus/blur\n * listeners onto it directly.\n */\nimport { useTooltip } from '@scalar/components/tooltip'\nimport type { TranslateFn } from '@scalar/localization'\nimport { computed, h, ref, render } from 'vue'\n\nimport {\n useLocalization,\n type ApiClientTranslationKey,\n} from '@/v2/features/localization'\n\nimport type { PillContext } from './pill-context'\n\nconst props = defineProps<{\n /** Tooltip data — environment value or context-function description */\n context: PillContext\n /** The pill element to attach the tooltip to */\n target: HTMLElement\n /** Carry the owning editor's locale into this separately mounted Vue app. */\n translate?: TranslateFn<ApiClientTranslationKey>\n}>()\n\nconst { translate: fallbackTranslate } = useLocalization()\n\ndefineOptions({ name: 'PillTooltipHost' })\n\nconst translate = props.translate ?? fallbackTranslate\n\nconst isContextFn = props.context.type === 'contextFunction'\n\n/** Two-line HTML body for context-function tooltips. */\nconst contextTooltipHtml = computed(() => {\n if (\n !isContextFn ||\n typeof document === 'undefined' ||\n props.context.type !== 'contextFunction'\n ) {\n return ''\n }\n const el = document.createElement('div')\n render(\n h('div', { class: 'flex flex-col gap-1.5 text-left' }, [\n h('span', {}, props.context.details),\n h(\n 'div',\n { class: 'text-[color:var(--scalar-color-3)] text-[10px] font-normal' },\n translate('apiClient.pillTooltipHost.computedAtExecution'),\n ),\n ]),\n el,\n )\n return el.innerHTML\n})\n\nconst environmentTooltipText = computed(() => {\n if (props.context.type !== 'environment') {\n return ''\n }\n return props.context.isDefined\n ? props.context.value\n : translate('apiClient.pillTooltipHost.noValue')\n})\n\nconst targetRef = ref<HTMLElement>(props.target)\n\nuseTooltip({\n content: isContextFn ? contextTooltipHtml : environmentTooltipText,\n contentTarget: isContextFn ? 'innerHTML' : 'textContent',\n delay: 0,\n placement: 'bottom-start',\n offset: 6,\n targetRef,\n})\n</script>\n\n<!-- eslint-disable vue/valid-template-root -- Renderless: the tooltip attaches to the supplied target. -->\n<template>\n <!-- Renderless: behaviour attaches to props.target via useTooltip -->\n</template>\n"],"mappings":""}
@@ -35,7 +35,10 @@ var PillTooltipHost_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
35
35
  render(h("div", { class: "flex flex-col gap-1.5 text-left" }, [h("span", {}, props.context.details), h("div", { class: "text-[color:var(--scalar-color-3)] text-[10px] font-normal" }, translate("apiClient.pillTooltipHost.computedAtExecution"))]), el);
36
36
  return el.innerHTML;
37
37
  });
38
- const environmentTooltipText = computed(() => props.context.type === "environment" ? props.context.isDefined ? props.context.value : translate("apiClient.pillTooltipHost.noValue") : "");
38
+ const environmentTooltipText = computed(() => {
39
+ if (props.context.type !== "environment") return "";
40
+ return props.context.isDefined ? props.context.value : translate("apiClient.pillTooltipHost.noValue");
41
+ });
39
42
  const targetRef = ref(props.target);
40
43
  useTooltip({
41
44
  content: isContextFn ? contextTooltipHtml : environmentTooltipText,
@@ -1 +1 @@
1
- {"version":3,"file":"PillTooltipHost.vue.script.js","names":[],"sources":["../../../../src/v2/components/code-input/PillTooltipHost.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * PillTooltipHost\n *\n * Renderless adapter that attaches a tooltip to an existing DOM element.\n * Both the legacy CodeMirror widget pipeline and the new `CodeInputLite`\n * overlay mount one of these per pill via `createApp` — they keep ownership\n * of the pill DOM (text, classes, styles) and we only attach hover/focus\n * behaviour through `useTooltip`.\n *\n * The component renders nothing of its own; pass the pill element via the\n * `target` prop and `useTooltip` will wire mouseenter/mouseleave/focus/blur\n * listeners onto it directly.\n */\nimport { useTooltip } from '@scalar/components/tooltip'\nimport type { TranslateFn } from '@scalar/localization'\nimport { computed, h, ref, render } from 'vue'\n\nimport {\n useLocalization,\n type ApiClientTranslationKey,\n} from '@/v2/features/localization'\n\nimport type { PillContext } from './pill-context'\n\nconst props = defineProps<{\n /** Tooltip data — environment value or context-function description */\n context: PillContext\n /** The pill element to attach the tooltip to */\n target: HTMLElement\n /** Carry the owning editor's locale into this separately mounted Vue app. */\n translate?: TranslateFn<ApiClientTranslationKey>\n}>()\n\nconst { translate: fallbackTranslate } = useLocalization()\n\ndefineOptions({ name: 'PillTooltipHost' })\n\nconst translate = props.translate ?? fallbackTranslate\n\nconst isContextFn = props.context.type === 'contextFunction'\n\n/** Two-line HTML body for context-function tooltips. */\nconst contextTooltipHtml = computed(() => {\n if (\n !isContextFn ||\n typeof document === 'undefined' ||\n props.context.type !== 'contextFunction'\n ) {\n return ''\n }\n const el = document.createElement('div')\n render(\n h('div', { class: 'flex flex-col gap-1.5 text-left' }, [\n h('span', {}, props.context.details),\n h(\n 'div',\n { class: 'text-[color:var(--scalar-color-3)] text-[10px] font-normal' },\n translate('apiClient.pillTooltipHost.computedAtExecution'),\n ),\n ]),\n el,\n )\n return el.innerHTML\n})\n\nconst environmentTooltipText = computed(() =>\n props.context.type === 'environment'\n ? props.context.isDefined\n ? props.context.value\n : translate('apiClient.pillTooltipHost.noValue')\n : '',\n)\n\nconst targetRef = ref<HTMLElement>(props.target)\n\nuseTooltip({\n content: isContextFn ? contextTooltipHtml : environmentTooltipText,\n contentTarget: isContextFn ? 'innerHTML' : 'textContent',\n delay: 0,\n placement: 'bottom-start',\n offset: 6,\n targetRef,\n})\n</script>\n\n<!-- eslint-disable vue/valid-template-root -- Renderless: the tooltip attaches to the supplied target. -->\n<template>\n <!-- Renderless: behaviour attaches to props.target via useTooltip -->\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;EAyBA,MAAM,QAAQ;EASd,MAAM,EAAE,WAAW,sBAAsB,gBAAgB;EAIzD,MAAM,YAAY,MAAM,aAAa;EAErC,MAAM,cAAc,MAAM,QAAQ,SAAS;;EAG3C,MAAM,qBAAqB,eAAe;GACxC,IACE,CAAC,eACD,OAAO,aAAa,eACpB,MAAM,QAAQ,SAAS,mBAEvB,OAAO;GAET,MAAM,KAAK,SAAS,cAAc,KAAK;GACvC,OACE,EAAE,OAAO,EAAE,OAAO,kCAAkC,GAAG,CACrD,EAAE,QAAQ,CAAC,GAAG,MAAM,QAAQ,OAAO,GACnC,EACE,OACA,EAAE,OAAO,6DAA6D,GACtE,UAAU,+CAA+C,CAC3D,CACF,CAAC,GACD,EACF;GACA,OAAO,GAAG;EACZ,CAAC;EAED,MAAM,yBAAyB,eAC7B,MAAM,QAAQ,SAAS,gBACnB,MAAM,QAAQ,YACZ,MAAM,QAAQ,QACd,UAAU,mCAAmC,IAC/C,EACN;EAEA,MAAM,YAAY,IAAiB,MAAM,MAAM;EAE/C,WAAW;GACT,SAAS,cAAc,qBAAqB;GAC5C,eAAe,cAAc,cAAc;GAC3C,OAAO;GACP,WAAW;GACX,QAAQ;GACR;EACF,CAAC"}
1
+ {"version":3,"file":"PillTooltipHost.vue.script.js","names":[],"sources":["../../../../src/v2/components/code-input/PillTooltipHost.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * PillTooltipHost\n *\n * Renderless adapter that attaches a tooltip to an existing DOM element.\n * Both the legacy CodeMirror widget pipeline and the new `CodeInputLite`\n * overlay mount one of these per pill via `createApp` — they keep ownership\n * of the pill DOM (text, classes, styles) and we only attach hover/focus\n * behaviour through `useTooltip`.\n *\n * The component renders nothing of its own; pass the pill element via the\n * `target` prop and `useTooltip` will wire mouseenter/mouseleave/focus/blur\n * listeners onto it directly.\n */\nimport { useTooltip } from '@scalar/components/tooltip'\nimport type { TranslateFn } from '@scalar/localization'\nimport { computed, h, ref, render } from 'vue'\n\nimport {\n useLocalization,\n type ApiClientTranslationKey,\n} from '@/v2/features/localization'\n\nimport type { PillContext } from './pill-context'\n\nconst props = defineProps<{\n /** Tooltip data — environment value or context-function description */\n context: PillContext\n /** The pill element to attach the tooltip to */\n target: HTMLElement\n /** Carry the owning editor's locale into this separately mounted Vue app. */\n translate?: TranslateFn<ApiClientTranslationKey>\n}>()\n\nconst { translate: fallbackTranslate } = useLocalization()\n\ndefineOptions({ name: 'PillTooltipHost' })\n\nconst translate = props.translate ?? fallbackTranslate\n\nconst isContextFn = props.context.type === 'contextFunction'\n\n/** Two-line HTML body for context-function tooltips. */\nconst contextTooltipHtml = computed(() => {\n if (\n !isContextFn ||\n typeof document === 'undefined' ||\n props.context.type !== 'contextFunction'\n ) {\n return ''\n }\n const el = document.createElement('div')\n render(\n h('div', { class: 'flex flex-col gap-1.5 text-left' }, [\n h('span', {}, props.context.details),\n h(\n 'div',\n { class: 'text-[color:var(--scalar-color-3)] text-[10px] font-normal' },\n translate('apiClient.pillTooltipHost.computedAtExecution'),\n ),\n ]),\n el,\n )\n return el.innerHTML\n})\n\nconst environmentTooltipText = computed(() => {\n if (props.context.type !== 'environment') {\n return ''\n }\n return props.context.isDefined\n ? props.context.value\n : translate('apiClient.pillTooltipHost.noValue')\n})\n\nconst targetRef = ref<HTMLElement>(props.target)\n\nuseTooltip({\n content: isContextFn ? contextTooltipHtml : environmentTooltipText,\n contentTarget: isContextFn ? 'innerHTML' : 'textContent',\n delay: 0,\n placement: 'bottom-start',\n offset: 6,\n targetRef,\n})\n</script>\n\n<!-- eslint-disable vue/valid-template-root -- Renderless: the tooltip attaches to the supplied target. -->\n<template>\n <!-- Renderless: behaviour attaches to props.target via useTooltip -->\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;EAyBA,MAAM,QAAQ;EASd,MAAM,EAAE,WAAW,sBAAsB,gBAAgB;EAIzD,MAAM,YAAY,MAAM,aAAa;EAErC,MAAM,cAAc,MAAM,QAAQ,SAAS;;EAG3C,MAAM,qBAAqB,eAAe;GACxC,IACE,CAAC,eACD,OAAO,aAAa,eACpB,MAAM,QAAQ,SAAS,mBAEvB,OAAO;GAET,MAAM,KAAK,SAAS,cAAc,KAAK;GACvC,OACE,EAAE,OAAO,EAAE,OAAO,kCAAkC,GAAG,CACrD,EAAE,QAAQ,CAAC,GAAG,MAAM,QAAQ,OAAO,GACnC,EACE,OACA,EAAE,OAAO,6DAA6D,GACtE,UAAU,+CAA+C,CAC3D,CACF,CAAC,GACD,EACF;GACA,OAAO,GAAG;EACZ,CAAC;EAED,MAAM,yBAAyB,eAAe;GAC5C,IAAI,MAAM,QAAQ,SAAS,eACzB,OAAO;GAET,OAAO,MAAM,QAAQ,YACjB,MAAM,QAAQ,QACd,UAAU,mCAAmC;EACnD,CAAC;EAED,MAAM,YAAY,IAAiB,MAAM,MAAM;EAE/C,WAAW;GACT,SAAS,cAAc,qBAAqB;GAC5C,eAAe,cAAc,cAAc;GAC3C,OAAO;GACP,WAAW;GACX,QAAQ;GACR;EACF,CAAC"}
@@ -29,7 +29,7 @@ var PillWidget = class PillWidget extends WidgetType {
29
29
  }
30
30
  this.pillColor = environment?.color || "var(--scalar-color-1)";
31
31
  const variable = environment?.variables?.find((v) => v.name === variableName);
32
- const value = variable ? typeof variable.value === "string" ? variable.value : variable.value?.default : void 0;
32
+ const value = typeof variable?.value === "string" ? variable.value : variable?.value?.default;
33
33
  this.variableInfo = {
34
34
  type: "environment",
35
35
  name: variableName,
@@ -1 +1 @@
1
- {"version":3,"file":"code-variable-widget.js","names":[],"sources":["../../../../src/v2/components/code-input/code-variable-widget.ts"],"sourcesContent":["import { REGEX } from '@scalar/helpers/regex/regex-helpers'\nimport type { TranslateFn } from '@scalar/localization'\nimport {\n Decoration,\n type DecorationSet,\n EditorView,\n RangeSetBuilder,\n ViewPlugin,\n type ViewUpdate,\n WidgetType,\n} from '@scalar/use-codemirror'\nimport { type ContextFunctionName, getContextFunctionComment } from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { createApp } from 'vue'\n\nimport type { ApiClientTranslationKey } from '@/v2/features/localization'\n\nimport PillTooltipHost from './PillTooltipHost.vue'\nimport type { PillContext } from './pill-context'\n\n/**\n * Displays `{{name}}` as a pill: environment variables show the resolved value;\n * context functions (e.g. `{{$guid}}`) show that the value is generated at send time.\n */\nclass PillWidget extends WidgetType {\n private app: any\n private readonly pillColor: string\n private readonly variableInfo: PillContext\n\n constructor(\n private readonly variableName: string,\n environment: XScalarEnvironment | undefined,\n variant: PillContext['type'],\n private readonly translate?: TranslateFn<ApiClientTranslationKey>,\n ) {\n super()\n if (variant === 'contextFunction') {\n this.pillColor = 'var(--scalar-color-3)'\n this.variableInfo = {\n type: 'contextFunction',\n identifier: variableName,\n details: getContextFunctionComment(variableName as ContextFunctionName),\n }\n return\n }\n\n this.pillColor = environment?.color || 'var(--scalar-color-1)'\n\n const variable = environment?.variables?.find((v) => v.name === variableName)\n const value = variable ? (typeof variable.value === 'string' ? variable.value : variable.value?.default) : undefined\n this.variableInfo = {\n type: 'environment',\n name: variableName,\n value: value || 'No value',\n isDefined: Boolean(value),\n }\n }\n\n toDOM(): HTMLElement {\n const span = document.createElement('span')\n span.className = this.variableInfo.type === 'contextFunction' ? 'cm-pill cm-pill--context-fn' : 'cm-pill'\n span.textContent = this.variableName\n\n span.style.setProperty('--tw-bg-base', this.pillColor)\n\n if (this.variableInfo.type === 'environment') {\n span.style.opacity = this.variableInfo.isDefined ? '1' : '0.5'\n }\n\n // PillTooltipHost is renderless and attaches `useTooltip` listeners to\n // `target` directly — mount onto a throwaway container so the pill DOM\n // we just built is preserved.\n this.app = createApp(PillTooltipHost, {\n context: this.variableInfo,\n target: span,\n translate: this.translate,\n })\n this.app.mount(document.createElement('div'))\n\n return span\n }\n\n override destroy(): void {\n if (this.app) {\n this.app.unmount()\n this.app = null\n }\n }\n\n override eq(other: WidgetType): boolean {\n if (!(other instanceof PillWidget)) {\n return false\n }\n if (\n other.variableName !== this.variableName ||\n other.pillColor !== this.pillColor ||\n other.variableInfo.type !== this.variableInfo.type\n ) {\n return false\n }\n const a = other.variableInfo\n const b = this.variableInfo\n if (a.type !== b.type) {\n return false\n }\n if (a.type === 'environment' && b.type === 'environment') {\n return a.name === b.name && a.value === b.value && a.isDefined === b.isDefined\n }\n if (a.type === 'contextFunction' && b.type === 'contextFunction') {\n return a.identifier === b.identifier && a.details === b.details\n }\n return false\n }\n\n override ignoreEvent(): boolean {\n return false\n }\n}\n\n/**\n * Styles the active environment variable pill.\n * This plugin creates decorations for environment variables in the editor.\n */\nexport const pillPlugin = (props: {\n environment: XScalarEnvironment | undefined\n isReadOnly: boolean | undefined\n isContextFunctionName?: (name: string) => boolean\n translate?: TranslateFn<ApiClientTranslationKey>\n}) =>\n ViewPlugin.fromClass(\n class {\n decorations: DecorationSet\n lastEnvironment: XScalarEnvironment | undefined\n\n constructor(view: EditorView) {\n this.lastEnvironment = props.environment\n this.decorations = this.buildDecorations(view)\n }\n\n update(update: ViewUpdate): void {\n // Rebuild decorations if environment changed\n if (props.environment !== this.lastEnvironment) {\n this.lastEnvironment = props.environment\n this.decorations = this.buildDecorations(update.view)\n return\n }\n\n // Only rebuild decorations if document or viewport changed\n if (update.docChanged || update.viewportChanged) {\n this.decorations = this.buildDecorations(update.view)\n }\n }\n\n buildDecorations(view: EditorView): DecorationSet {\n const builder = new RangeSetBuilder<Decoration>()\n const isContextFn = props.isContextFunctionName ?? (() => false)\n\n for (const { from, to } of view.visibleRanges) {\n const text = view.state.doc.sliceString(from, to)\n\n // Create a new regex instance to ensure lastIndex is reset\n const regex = new RegExp(REGEX.VARIABLES.source, REGEX.VARIABLES.flags)\n let match: RegExpExecArray | null\n\n while ((match = regex.exec(text)) !== null) {\n const start = from + match.index\n const end = start + match[0].length\n const variableName = match[1] ?? ''\n\n // Skip decorations that span line breaks as CodeMirror does not allow them\n const matchedText = view.state.doc.sliceString(start, end)\n if (matchedText.includes('\\n')) {\n continue\n }\n\n const variant: PillContext['type'] = isContextFn(variableName) ? 'contextFunction' : 'environment'\n\n builder.add(\n start,\n end,\n Decoration.widget({\n widget: new PillWidget(variableName, props.environment, variant, props.translate),\n side: 1,\n }),\n )\n }\n }\n\n return builder.finish()\n }\n },\n {\n decorations: (v) => v.decorations,\n },\n )\n\n/**\n * Custom backspace handler for the editor.\n * Handles special cases like removing entire variable syntax and clearing all content.\n */\nexport const backspaceCommand = EditorView.domEventHandlers({\n keydown(event, view): boolean {\n if (event.key !== 'Backspace') {\n return false\n }\n\n const { state } = view\n const { from, to } = state.selection.main\n\n // When selecting all content and pressing backspace,\n // prevent breaking line content addition on pill removal\n if (from === 0 && to === state.doc.length) {\n view.dispatch({\n changes: { from: 0, to: state.doc.length },\n selection: { anchor: 0 },\n })\n event.preventDefault()\n return true\n }\n\n // When cursor is after a variable closing bracket (}}),\n // remove the entire closing syntax at once\n if (from === to && from >= 2) {\n const before = state.doc.sliceString(from - 2, from)\n if (before === '}}') {\n view.dispatch({\n changes: { from: from - 2, to: from },\n selection: { anchor: from - 2 },\n })\n event.preventDefault()\n return true\n }\n }\n\n return false\n },\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"code-variable-widget.js","names":[],"sources":["../../../../src/v2/components/code-input/code-variable-widget.ts"],"sourcesContent":["import { REGEX } from '@scalar/helpers/regex/regex-helpers'\nimport type { TranslateFn } from '@scalar/localization'\nimport {\n Decoration,\n type DecorationSet,\n EditorView,\n RangeSetBuilder,\n ViewPlugin,\n type ViewUpdate,\n WidgetType,\n} from '@scalar/use-codemirror'\nimport { type ContextFunctionName, getContextFunctionComment } from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { createApp } from 'vue'\n\nimport type { ApiClientTranslationKey } from '@/v2/features/localization'\n\nimport PillTooltipHost from './PillTooltipHost.vue'\nimport type { PillContext } from './pill-context'\n\n/**\n * Displays `{{name}}` as a pill: environment variables show the resolved value;\n * context functions (e.g. `{{$guid}}`) show that the value is generated at send time.\n */\nclass PillWidget extends WidgetType {\n private app: any\n private readonly pillColor: string\n private readonly variableInfo: PillContext\n\n constructor(\n private readonly variableName: string,\n environment: XScalarEnvironment | undefined,\n variant: PillContext['type'],\n private readonly translate?: TranslateFn<ApiClientTranslationKey>,\n ) {\n super()\n if (variant === 'contextFunction') {\n this.pillColor = 'var(--scalar-color-3)'\n this.variableInfo = {\n type: 'contextFunction',\n identifier: variableName,\n details: getContextFunctionComment(variableName as ContextFunctionName),\n }\n return\n }\n\n this.pillColor = environment?.color || 'var(--scalar-color-1)'\n\n const variable = environment?.variables?.find((v) => v.name === variableName)\n const value = typeof variable?.value === 'string' ? variable.value : variable?.value?.default\n this.variableInfo = {\n type: 'environment',\n name: variableName,\n value: value || 'No value',\n isDefined: Boolean(value),\n }\n }\n\n toDOM(): HTMLElement {\n const span = document.createElement('span')\n span.className = this.variableInfo.type === 'contextFunction' ? 'cm-pill cm-pill--context-fn' : 'cm-pill'\n span.textContent = this.variableName\n\n span.style.setProperty('--tw-bg-base', this.pillColor)\n\n if (this.variableInfo.type === 'environment') {\n span.style.opacity = this.variableInfo.isDefined ? '1' : '0.5'\n }\n\n // PillTooltipHost is renderless and attaches `useTooltip` listeners to\n // `target` directly — mount onto a throwaway container so the pill DOM\n // we just built is preserved.\n this.app = createApp(PillTooltipHost, {\n context: this.variableInfo,\n target: span,\n translate: this.translate,\n })\n this.app.mount(document.createElement('div'))\n\n return span\n }\n\n override destroy(): void {\n if (this.app) {\n this.app.unmount()\n this.app = null\n }\n }\n\n override eq(other: WidgetType): boolean {\n if (!(other instanceof PillWidget)) {\n return false\n }\n if (\n other.variableName !== this.variableName ||\n other.pillColor !== this.pillColor ||\n other.variableInfo.type !== this.variableInfo.type\n ) {\n return false\n }\n const a = other.variableInfo\n const b = this.variableInfo\n if (a.type !== b.type) {\n return false\n }\n if (a.type === 'environment' && b.type === 'environment') {\n return a.name === b.name && a.value === b.value && a.isDefined === b.isDefined\n }\n if (a.type === 'contextFunction' && b.type === 'contextFunction') {\n return a.identifier === b.identifier && a.details === b.details\n }\n return false\n }\n\n override ignoreEvent(): boolean {\n return false\n }\n}\n\n/**\n * Styles the active environment variable pill.\n * This plugin creates decorations for environment variables in the editor.\n */\nexport const pillPlugin = (props: {\n environment: XScalarEnvironment | undefined\n isReadOnly: boolean | undefined\n isContextFunctionName?: (name: string) => boolean\n translate?: TranslateFn<ApiClientTranslationKey>\n}) =>\n ViewPlugin.fromClass(\n class {\n decorations: DecorationSet\n lastEnvironment: XScalarEnvironment | undefined\n\n constructor(view: EditorView) {\n this.lastEnvironment = props.environment\n this.decorations = this.buildDecorations(view)\n }\n\n update(update: ViewUpdate): void {\n // Rebuild decorations if environment changed\n if (props.environment !== this.lastEnvironment) {\n this.lastEnvironment = props.environment\n this.decorations = this.buildDecorations(update.view)\n return\n }\n\n // Only rebuild decorations if document or viewport changed\n if (update.docChanged || update.viewportChanged) {\n this.decorations = this.buildDecorations(update.view)\n }\n }\n\n buildDecorations(view: EditorView): DecorationSet {\n const builder = new RangeSetBuilder<Decoration>()\n const isContextFn = props.isContextFunctionName ?? (() => false)\n\n for (const { from, to } of view.visibleRanges) {\n const text = view.state.doc.sliceString(from, to)\n\n // Create a new regex instance to ensure lastIndex is reset\n const regex = new RegExp(REGEX.VARIABLES.source, REGEX.VARIABLES.flags)\n let match: RegExpExecArray | null\n\n while ((match = regex.exec(text)) !== null) {\n const start = from + match.index\n const end = start + match[0].length\n const variableName = match[1] ?? ''\n\n // Skip decorations that span line breaks as CodeMirror does not allow them\n const matchedText = view.state.doc.sliceString(start, end)\n if (matchedText.includes('\\n')) {\n continue\n }\n\n const variant: PillContext['type'] = isContextFn(variableName) ? 'contextFunction' : 'environment'\n\n builder.add(\n start,\n end,\n Decoration.widget({\n widget: new PillWidget(variableName, props.environment, variant, props.translate),\n side: 1,\n }),\n )\n }\n }\n\n return builder.finish()\n }\n },\n {\n decorations: (v) => v.decorations,\n },\n )\n\n/**\n * Custom backspace handler for the editor.\n * Handles special cases like removing entire variable syntax and clearing all content.\n */\nexport const backspaceCommand = EditorView.domEventHandlers({\n keydown(event, view): boolean {\n if (event.key !== 'Backspace') {\n return false\n }\n\n const { state } = view\n const { from, to } = state.selection.main\n\n // When selecting all content and pressing backspace,\n // prevent breaking line content addition on pill removal\n if (from === 0 && to === state.doc.length) {\n view.dispatch({\n changes: { from: 0, to: state.doc.length },\n selection: { anchor: 0 },\n })\n event.preventDefault()\n return true\n }\n\n // When cursor is after a variable closing bracket (}}),\n // remove the entire closing syntax at once\n if (from === to && from >= 2) {\n const before = state.doc.sliceString(from - 2, from)\n if (before === '}}') {\n view.dispatch({\n changes: { from: from - 2, to: from },\n selection: { anchor: from - 2 },\n })\n event.preventDefault()\n return true\n }\n }\n\n return false\n },\n})\n"],"mappings":"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"}
@@ -24,7 +24,9 @@ type __VLS_Slots = {} & {
24
24
  } & {
25
25
  icon?: (props: typeof __VLS_30) => any;
26
26
  };
27
- declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
27
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
28
+ focus: () => void;
29
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
28
30
  "update:modelValue": (v: string | number) => any;
29
31
  selectVariable: (value: string) => any;
30
32
  inputFocus: () => any;
@@ -1 +1 @@
1
- {"version":3,"file":"DataTableInput.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/components/data-table/DataTableInput.vue"],"names":[],"mappings":"AAyLA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AAGnH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAO/C,KAAK,WAAW,GAAG;IACf,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,sEAAsE;IACtE,cAAc,CAAC,EAAE,YAAY,GAAG,SAAS,CAAA;IACzC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,0EAA0E;IAC1E,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,WAAW,EAAE,kBAAkB,CAAA;IAC/B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAChC,4FAA4F;IAC5F,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB,CAAC;AA6VJ,QAAA,IAAI,OAAO,IAAU,EAAuB,QAAQ,IAAW,EAAE,QAAQ,IAAY,CAAE;AACvF,KAAK,WAAW,GAAG,EAAE,GACnB;IAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,CAAA;CAAE,GAC5C;IAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,QAAQ,KAAK,GAAG,CAAA;CAAE,GAC7C;IAAE,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,QAAQ,KAAK,GAAG,CAAA;CAAE,CAAC;AAQ7C,QAAA,MAAM,UAAU;;;;;;;;;;;cAnXD,OAAO;kBASH,OAAO;cALX,OAAO;2BADM,OAAO;6EAoXjC,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AAWzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
1
+ {"version":3,"file":"DataTableInput.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/components/data-table/DataTableInput.vue"],"names":[],"mappings":"AA4OA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AAGnH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAO/C,KAAK,WAAW,GAAG;IACf,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,sEAAsE;IACtE,cAAc,CAAC,EAAE,YAAY,GAAG,SAAS,CAAA;IACzC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,0EAA0E;IAC1E,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,WAAW,EAAE,kBAAkB,CAAA;IAC/B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAChC,4FAA4F;IAC5F,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB,CAAC;AAmZJ,QAAA,IAAI,OAAO,IAAU,EAAuB,QAAQ,IAAW,EAAE,QAAQ,IAAY,CAAE;AACvF,KAAK,WAAW,GAAG,EAAE,GACnB;IAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,CAAA;CAAE,GAC5C;IAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,QAAQ,KAAK,GAAG,CAAA;CAAE,GAC7C;IAAE,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,QAAQ,KAAK,GAAG,CAAA;CAAE,CAAC;AAQ7C,QAAA,MAAM,UAAU;iBA9VE,IAAI;;;;;;;;;;;;cA3EP,OAAO;kBASH,OAAO;cALX,OAAO;2BADM,OAAO;6EA2ajC,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AAWzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
@@ -2,7 +2,7 @@ import _plugin_vue_export_helper_default from "../../../_virtual/_plugin-vue_exp
2
2
  import DataTableInput_vue_vue_type_script_setup_true_lang_default from "./DataTableInput.vue.script.js";
3
3
  /* empty css */
4
4
  //#region src/v2/components/data-table/DataTableInput.vue
5
- var DataTableInput_default = /*#__PURE__*/ _plugin_vue_export_helper_default(DataTableInput_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-ce270af2"]]);
5
+ var DataTableInput_default = /*#__PURE__*/ _plugin_vue_export_helper_default(DataTableInput_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-029a43f5"]]);
6
6
  //#endregion
7
7
  export { DataTableInput_default as default };
8
8
 
@@ -1 +1 @@
1
- {"version":3,"file":"DataTableInput.vue.js","names":[],"sources":["../../../../src/v2/components/data-table/DataTableInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarIconButton } from '@scalar/components/icon-button'\nimport { ScalarIconEye, ScalarIconEyeSlash, ScalarIconX } from '@scalar/icons'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { computed, ref, useTemplateRef } from 'vue'\n\nimport type { VueClassProp } from '@/types/vue'\nimport { CodeInputLite } from '@/v2/components/code-input'\nimport { useLocalization } from '@/v2/features/localization'\n\nimport DataTableCell from './DataTableCell.vue'\nimport DataTableInputSelect from './DataTableInputSelect.vue'\n\nconst props = withDefaults(\n defineProps<{\n id?: string\n type?: string | undefined\n /** Class for the wrapping cell because attrs is bound to the input */\n containerClass?: VueClassProp | undefined\n required?: boolean\n modelValue: string\n /** Allows adding a custom value to the enum dropdown, defaults to true */\n canAddCustomEnumValue?: boolean\n readOnly?: boolean\n enum?: string[]\n environment: XScalarEnvironment\n description?: string | undefined\n /** Whether to show context function suggestions like $guid, $timestamp. Defaults to true */\n withFakeData?: boolean\n }>(),\n {\n canAddCustomEnumValue: true,\n required: false,\n readOnly: false,\n withFakeData: true,\n },\n)\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', v: string | number): void\n (e: 'inputFocus'): void\n (e: 'inputBlur'): void\n (e: 'selectVariable', value: string): void\n}>()\n\nconst { translate } = useLocalization()\n\ndefineOptions({ inheritAttrs: false })\n\nconst mask = ref(true)\nconst interactingWithDropdown = ref(false)\nconst codeInput = useTemplateRef('codeInput')\nconst maskedInput = useTemplateRef('maskedInput')\n\nconst handleBlur = () => !interactingWithDropdown.value && emit('inputBlur')\n\nconst inputType = computed(() =>\n props.type === 'password' ? 'text' : (props.type ?? 'text'),\n)\n\n// If not an enum nor read only, focus the code input or masked input\nconst handleLabelClick = () => {\n if (!props.enum?.length && !props.readOnly) {\n codeInput.value?.focus()\n maskedInput.value?.focus()\n }\n}\n</script>\n<template>\n <DataTableCell\n class=\"relative flex\"\n :class=\"containerClass\">\n <div\n v-if=\"$slots.default\"\n class=\"text-c-1 flex items-center pr-0 pl-3\"\n @click=\"handleLabelClick\">\n <slot />:\n </div>\n <div class=\"relative flex min-w-0 flex-1\">\n <template v-if=\"props.enum && props.enum.length\">\n <DataTableInputSelect\n :canAddCustomValue=\"props.canAddCustomEnumValue\"\n :modelValue=\"props.modelValue\"\n :value=\"props.enum\"\n @update:modelValue=\"emit('update:modelValue', $event)\" />\n </template>\n <template v-else>\n <input\n v-if=\"mask && type === 'password'\"\n v-bind=\"id ? { ...$attrs, id: id } : $attrs\"\n ref=\"maskedInput\"\n autocomplete=\"off\"\n class=\"text-c-1 disabled:text-c-2 peer w-full min-w-0 border-none px-2 py-1.25 -outline-offset-1\"\n :class=\"{ 'scalar-password-input': type === 'password' }\"\n data-1p-ignore\n :readOnly=\"readOnly\"\n spellcheck=\"false\"\n :type=\"inputType\"\n :value=\"modelValue\"\n @input=\"\n emit(\n 'update:modelValue',\n ($event.target as HTMLInputElement).value ?? '',\n )\n \" />\n <CodeInputLite\n v-else\n v-bind=\"$attrs\"\n :id=\"id\"\n ref=\"codeInput\"\n class=\"text-c-1 disabled:text-c-2 peer w-full min-w-0 border-none -outline-offset-1\"\n :class=\"[\n type === 'password' && description && 'pr-12',\n description && 'pr-8',\n type === 'password' && 'scalar-password-input',\n ]\"\n :environment=\"environment\"\n :modelValue=\"modelValue ?? ''\"\n :readOnly=\"readOnly\"\n :required=\"Boolean(required)\"\n :type=\"inputType\"\n :withFakeData=\"withFakeData\"\n @blur=\"handleBlur\"\n @focus=\"emit('inputFocus')\"\n @update:modelValue=\"(value) => emit('update:modelValue', value)\" />\n </template>\n </div>\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 <slot name=\"icon\" />\n <!-- Clear -->\n <ScalarIconButton\n v-if=\"modelValue && !readOnly\"\n class=\"-ml-.25 h-6 w-6 self-center p-1.25\"\n :icon=\"ScalarIconX\"\n :label=\"translate('apiClient.dataTableInput.clearValue')\"\n @click=\"emit('update:modelValue', '')\" />\n <!-- Toggle Visibility -->\n <!-- A toggle button keeps one name and reports its state, so the label\n stays \"Show Password\" while `aria-pressed` says whether the value is\n revealed. Flipping the name instead leaves screen readers silent,\n because activating a button does not re-announce its name. -->\n <ScalarIconButton\n v-if=\"type === 'password'\"\n :aria-pressed=\"!mask\"\n class=\"-ml-.5 mr-1.25 h-6 w-6 self-center p-1.25\"\n data-testid=\"data-table-password-toggle\"\n :icon=\"mask ? ScalarIconEye : ScalarIconEyeSlash\"\n :label=\"translate('apiClient.dataTableInput.showPassword')\"\n @click=\"mask = !mask\" />\n </DataTableCell>\n</template>\n\n<style scoped>\n:deep(.code-input-lite__editor) {\n background-color: transparent;\n font-family: var(--scalar-font);\n font-size: var(--scalar-small);\n padding: 5px 8px;\n}\n:deep(.scalar-pill:not(:last-of-type)) {\n margin-right: 0.15em;\n}\n:deep(.scalar-pill:not(:first-of-type)) {\n margin-left: 0.5px;\n}\n/* Tailwind placeholder is busted */\ninput::placeholder {\n color: var(--scalar-color-3);\n}\n/* we want our inputs to look like a password input but not be one */\n.scalar-password-input {\n text-security: disc;\n -webkit-text-security: disc;\n -moz-text-security: disc;\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"DataTableInput.vue.js","names":[],"sources":["../../../../src/v2/components/data-table/DataTableInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarIconButton } from '@scalar/components/icon-button'\nimport { ScalarIconEye, ScalarIconEyeSlash, ScalarIconX } from '@scalar/icons'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { computed, nextTick, ref, useTemplateRef, watch } from 'vue'\n\nimport type { VueClassProp } from '@/types/vue'\nimport { CodeInputLite } from '@/v2/components/code-input'\nimport { useLocalization } from '@/v2/features/localization'\n\nimport DataTableCell from './DataTableCell.vue'\nimport DataTableInputSelect from './DataTableInputSelect.vue'\n\nconst props = withDefaults(\n defineProps<{\n id?: string\n type?: string | undefined\n /** Class for the wrapping cell because attrs is bound to the input */\n containerClass?: VueClassProp | undefined\n required?: boolean\n modelValue: string\n /** Allows adding a custom value to the enum dropdown, defaults to true */\n canAddCustomEnumValue?: boolean\n readOnly?: boolean\n enum?: string[]\n environment: XScalarEnvironment\n description?: string | undefined\n /** Whether to show context function suggestions like $guid, $timestamp. Defaults to true */\n withFakeData?: boolean\n }>(),\n {\n canAddCustomEnumValue: true,\n required: false,\n readOnly: false,\n withFakeData: true,\n },\n)\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', v: string | number): void\n (e: 'inputFocus'): void\n (e: 'inputBlur'): void\n (e: 'selectVariable', value: string): void\n}>()\n\nconst { translate } = useLocalization()\n\ndefineOptions({ inheritAttrs: false })\n\nconst mask = ref(true)\nconst interactingWithDropdown = ref(false)\nconst codeInput = useTemplateRef('codeInput')\nconst maskedInput = useTemplateRef('maskedInput')\n\n/**\n * Whether focus is inside the field. Tracked with focusin and focusout on the wrapper because the\n * revealed editor does not report its own focus, and swapping it out mid-typing would drop focus.\n */\nconst fieldFocused = ref(false)\n\n/** There is nothing to reveal in an empty field, so the toggle only shows once it has a value */\nconst showVisibilityToggle = computed(\n () => props.type === 'password' && Boolean(props.modelValue),\n)\n\n// An emptied secret goes back to masked, so whatever is typed or pasted next stays hidden\nwatch(\n () => props.modelValue,\n (value) => {\n if (!value && !fieldFocused.value) {\n mask.value = true\n }\n },\n)\n\n/** A field emptied while typing in the revealed editor masks once focus leaves it */\nconst handleFieldFocusOut = (): void => {\n fieldFocused.value = false\n\n if (!props.modelValue) {\n mask.value = true\n }\n}\n\nconst handleBlur = () => !interactingWithDropdown.value && emit('inputBlur')\n\nconst inputType = computed(() =>\n props.type === 'password' ? 'text' : (props.type ?? 'text'),\n)\n\n/** Focus whichever editor is showing, the masked input or the code input */\nconst focus = (): void => {\n codeInput.value?.focus()\n maskedInput.value?.focus()\n}\n\n// If not an enum nor read only, focus the code input or masked input\nconst handleLabelClick = () => {\n if (!props.enum?.length && !props.readOnly) {\n focus()\n }\n}\n\n/**\n * The clear button disappears once the field is empty, so focus moves to the field instead of\n * falling back to the page. A cleared secret is masked again so the next one is not shown.\n */\nconst clearValue = async (): Promise<void> => {\n mask.value = true\n emit('update:modelValue', '')\n await nextTick()\n focus()\n}\n\ndefineExpose({ focus })\n</script>\n<template>\n <DataTableCell\n class=\"relative flex\"\n :class=\"containerClass\">\n <div\n v-if=\"$slots.default\"\n class=\"text-c-1 flex items-center pr-0 pl-3\"\n @click=\"handleLabelClick\">\n <slot />:\n </div>\n <div\n class=\"relative flex min-w-0 flex-1\"\n @focusin=\"fieldFocused = true\"\n @focusout=\"handleFieldFocusOut\">\n <template v-if=\"props.enum && props.enum.length\">\n <DataTableInputSelect\n :canAddCustomValue=\"props.canAddCustomEnumValue\"\n :modelValue=\"props.modelValue\"\n :value=\"props.enum\"\n @update:modelValue=\"emit('update:modelValue', $event)\" />\n </template>\n <template v-else>\n <input\n v-if=\"mask && type === 'password'\"\n v-bind=\"id ? { ...$attrs, id: id } : $attrs\"\n ref=\"maskedInput\"\n autocomplete=\"off\"\n class=\"text-c-1 disabled:text-c-2 peer w-full min-w-0 border-none px-2 py-1.25 -outline-offset-1\"\n :class=\"{ 'scalar-password-input': type === 'password' }\"\n data-1p-ignore\n :readOnly=\"readOnly\"\n spellcheck=\"false\"\n :type=\"inputType\"\n :value=\"modelValue\"\n @input=\"\n emit(\n 'update:modelValue',\n ($event.target as HTMLInputElement).value ?? '',\n )\n \" />\n <CodeInputLite\n v-else\n v-bind=\"$attrs\"\n :id=\"id\"\n ref=\"codeInput\"\n class=\"text-c-1 disabled:text-c-2 peer w-full min-w-0 border-none -outline-offset-1\"\n :class=\"[\n type === 'password' && description && 'pr-12',\n description && 'pr-8',\n type === 'password' && 'scalar-password-input',\n ]\"\n :environment=\"environment\"\n :modelValue=\"modelValue ?? ''\"\n :readOnly=\"readOnly\"\n :required=\"Boolean(required)\"\n :type=\"inputType\"\n :withFakeData=\"withFakeData\"\n @blur=\"handleBlur\"\n @focus=\"emit('inputFocus')\"\n @update:modelValue=\"(value) => emit('update:modelValue', value)\" />\n </template>\n </div>\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 <slot name=\"icon\" />\n <!-- Clear -->\n <ScalarIconButton\n v-if=\"modelValue && !readOnly\"\n class=\"-ml-.25 h-6 w-6 self-center p-1.25\"\n :icon=\"ScalarIconX\"\n :label=\"translate('apiClient.dataTableInput.clearValue')\"\n @click=\"clearValue\" />\n <!-- Toggle Visibility -->\n <!-- A toggle button keeps one name and reports its state, so the label\n stays \"Show Password\" while `aria-pressed` says whether the value is\n revealed. Flipping the name instead leaves screen readers silent,\n because activating a button does not re-announce its name. -->\n <ScalarIconButton\n v-if=\"showVisibilityToggle\"\n :aria-pressed=\"!mask\"\n class=\"-ml-.5 mr-1.25 h-6 w-6 self-center p-1.25\"\n data-testid=\"data-table-password-toggle\"\n :icon=\"mask ? ScalarIconEye : ScalarIconEyeSlash\"\n :label=\"translate('apiClient.dataTableInput.showPassword')\"\n @click=\"mask = !mask\" />\n </DataTableCell>\n</template>\n\n<style scoped>\n:deep(.code-input-lite__editor) {\n background-color: transparent;\n font-family: var(--scalar-font);\n font-size: var(--scalar-small);\n padding: 5px 8px;\n}\n:deep(.scalar-pill:not(:last-of-type)) {\n margin-right: 0.15em;\n}\n:deep(.scalar-pill:not(:first-of-type)) {\n margin-left: 0.5px;\n}\n/* Tailwind placeholder is busted */\ninput::placeholder {\n color: var(--scalar-color-3);\n}\n/* we want our inputs to look like a password input but not be one */\n.scalar-password-input {\n text-security: disc;\n -webkit-text-security: disc;\n -moz-text-security: disc;\n}\n</style>\n"],"mappings":""}
@@ -2,17 +2,16 @@ import { useLocalization } from "../../features/localization/index.js";
2
2
  import DataTableInputSelect_default from "./DataTableInputSelect.vue.js";
3
3
  import CodeInputLite_default from "../code-input/CodeInputLite.vue.js";
4
4
  import DataTableCell_default from "./DataTableCell.vue.js";
5
- import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, defineComponent, mergeProps, normalizeClass, openBlock, ref, renderSlot, unref, useTemplateRef, withCtx } from "vue";
5
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, defineComponent, mergeProps, nextTick, normalizeClass, openBlock, ref, renderSlot, unref, useTemplateRef, watch, withCtx } from "vue";
6
6
  import { ScalarIconEye, ScalarIconEyeSlash, ScalarIconX } from "@scalar/icons";
7
7
  import { ScalarIconButton } from "@scalar/components/icon-button";
8
8
  //#region src/v2/components/data-table/DataTableInput.vue?vue&type=script&setup=true&lang.ts
9
- var _hoisted_1 = { class: "relative flex min-w-0 flex-1" };
10
- var _hoisted_2 = [
9
+ var _hoisted_1 = [
11
10
  "readOnly",
12
11
  "type",
13
12
  "value"
14
13
  ];
15
- var _hoisted_3 = {
14
+ var _hoisted_2 = {
16
15
  key: 1,
17
16
  class: "centered-y text-orange absolute right-7 text-xs"
18
17
  };
@@ -50,7 +49,7 @@ var DataTableInput_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
50
49
  "inputBlur",
51
50
  "selectVariable"
52
51
  ],
53
- setup(__props, { emit: __emit }) {
52
+ setup(__props, { expose: __expose, emit: __emit }) {
54
53
  const props = __props;
55
54
  const emit = __emit;
56
55
  const { translate } = useLocalization();
@@ -58,14 +57,42 @@ var DataTableInput_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
58
57
  const interactingWithDropdown = ref(false);
59
58
  const codeInput = useTemplateRef("codeInput");
60
59
  const maskedInput = useTemplateRef("maskedInput");
60
+ /**
61
+ * Whether focus is inside the field. Tracked with focusin and focusout on the wrapper because the
62
+ * revealed editor does not report its own focus, and swapping it out mid-typing would drop focus.
63
+ */
64
+ const fieldFocused = ref(false);
65
+ /** There is nothing to reveal in an empty field, so the toggle only shows once it has a value */
66
+ const showVisibilityToggle = computed(() => props.type === "password" && Boolean(props.modelValue));
67
+ watch(() => props.modelValue, (value) => {
68
+ if (!value && !fieldFocused.value) mask.value = true;
69
+ });
70
+ /** A field emptied while typing in the revealed editor masks once focus leaves it */
71
+ const handleFieldFocusOut = () => {
72
+ fieldFocused.value = false;
73
+ if (!props.modelValue) mask.value = true;
74
+ };
61
75
  const handleBlur = () => !interactingWithDropdown.value && emit("inputBlur");
62
76
  const inputType = computed(() => props.type === "password" ? "text" : props.type ?? "text");
77
+ /** Focus whichever editor is showing, the masked input or the code input */
78
+ const focus = () => {
79
+ codeInput.value?.focus();
80
+ maskedInput.value?.focus();
81
+ };
63
82
  const handleLabelClick = () => {
64
- if (!props.enum?.length && !props.readOnly) {
65
- codeInput.value?.focus();
66
- maskedInput.value?.focus();
67
- }
83
+ if (!props.enum?.length && !props.readOnly) focus();
84
+ };
85
+ /**
86
+ * The clear button disappears once the field is empty, so focus moves to the field instead of
87
+ * falling back to the page. A cleared secret is masked again so the next one is not shown.
88
+ */
89
+ const clearValue = async () => {
90
+ mask.value = true;
91
+ emit("update:modelValue", "");
92
+ await nextTick();
93
+ focus();
68
94
  };
95
+ __expose({ focus });
69
96
  return (_ctx, _cache) => {
70
97
  return openBlock(), createBlock(DataTableCell_default, { class: normalizeClass(["relative flex", __props.containerClass]) }, {
71
98
  default: withCtx(() => [
@@ -74,7 +101,11 @@ var DataTableInput_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
74
101
  class: "text-c-1 flex items-center pr-0 pl-3",
75
102
  onClick: handleLabelClick
76
103
  }, [renderSlot(_ctx.$slots, "default", {}, void 0, true), _cache[6] || (_cache[6] = createTextVNode(": ", -1))])) : createCommentVNode("", true),
77
- createElementVNode("div", _hoisted_1, [props.enum && props.enum.length ? (openBlock(), createBlock(DataTableInputSelect_default, {
104
+ createElementVNode("div", {
105
+ class: "relative flex min-w-0 flex-1",
106
+ onFocusin: _cache[4] || (_cache[4] = ($event) => fieldFocused.value = true),
107
+ onFocusout: handleFieldFocusOut
108
+ }, [props.enum && props.enum.length ? (openBlock(), createBlock(DataTableInputSelect_default, {
78
109
  key: 0,
79
110
  canAddCustomValue: props.canAddCustomEnumValue,
80
111
  modelValue: props.modelValue,
@@ -98,7 +129,7 @@ var DataTableInput_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
98
129
  type: inputType.value,
99
130
  value: __props.modelValue,
100
131
  onInput: _cache[1] || (_cache[1] = ($event) => emit("update:modelValue", $event.target.value ?? ""))
101
- }), null, 16, _hoisted_2)) : (openBlock(), createBlock(unref(CodeInputLite_default), mergeProps({ key: 1 }, _ctx.$attrs, {
132
+ }), null, 16, _hoisted_1)) : (openBlock(), createBlock(unref(CodeInputLite_default), mergeProps({ key: 1 }, _ctx.$attrs, {
102
133
  id: __props.id,
103
134
  ref_key: "codeInput",
104
135
  ref: codeInput,
@@ -125,17 +156,17 @@ var DataTableInput_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
125
156
  "required",
126
157
  "type",
127
158
  "withFakeData"
128
- ]))], 64))]),
129
- _ctx.$slots.warning ? (openBlock(), createElementBlock("div", _hoisted_3, [renderSlot(_ctx.$slots, "warning", {}, void 0, true)])) : createCommentVNode("", true),
159
+ ]))], 64))], 32),
160
+ _ctx.$slots.warning ? (openBlock(), createElementBlock("div", _hoisted_2, [renderSlot(_ctx.$slots, "warning", {}, void 0, true)])) : createCommentVNode("", true),
130
161
  renderSlot(_ctx.$slots, "icon", {}, void 0, true),
131
162
  __props.modelValue && !__props.readOnly ? (openBlock(), createBlock(unref(ScalarIconButton), {
132
163
  key: 2,
133
164
  class: "-ml-.25 h-6 w-6 self-center p-1.25",
134
165
  icon: unref(ScalarIconX),
135
166
  label: unref(translate)("apiClient.dataTableInput.clearValue"),
136
- onClick: _cache[4] || (_cache[4] = ($event) => emit("update:modelValue", ""))
167
+ onClick: clearValue
137
168
  }, null, 8, ["icon", "label"])) : createCommentVNode("", true),
138
- __props.type === "password" ? (openBlock(), createBlock(unref(ScalarIconButton), {
169
+ showVisibilityToggle.value ? (openBlock(), createBlock(unref(ScalarIconButton), {
139
170
  key: 3,
140
171
  "aria-pressed": !mask.value,
141
172
  class: "-ml-.5 mr-1.25 h-6 w-6 self-center p-1.25",
@@ -1 +1 @@
1
- {"version":3,"file":"DataTableInput.vue.script.js","names":["$slots","$attrs"],"sources":["../../../../src/v2/components/data-table/DataTableInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarIconButton } from '@scalar/components/icon-button'\nimport { ScalarIconEye, ScalarIconEyeSlash, ScalarIconX } from '@scalar/icons'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { computed, ref, useTemplateRef } from 'vue'\n\nimport type { VueClassProp } from '@/types/vue'\nimport { CodeInputLite } from '@/v2/components/code-input'\nimport { useLocalization } from '@/v2/features/localization'\n\nimport DataTableCell from './DataTableCell.vue'\nimport DataTableInputSelect from './DataTableInputSelect.vue'\n\nconst props = withDefaults(\n defineProps<{\n id?: string\n type?: string | undefined\n /** Class for the wrapping cell because attrs is bound to the input */\n containerClass?: VueClassProp | undefined\n required?: boolean\n modelValue: string\n /** Allows adding a custom value to the enum dropdown, defaults to true */\n canAddCustomEnumValue?: boolean\n readOnly?: boolean\n enum?: string[]\n environment: XScalarEnvironment\n description?: string | undefined\n /** Whether to show context function suggestions like $guid, $timestamp. Defaults to true */\n withFakeData?: boolean\n }>(),\n {\n canAddCustomEnumValue: true,\n required: false,\n readOnly: false,\n withFakeData: true,\n },\n)\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', v: string | number): void\n (e: 'inputFocus'): void\n (e: 'inputBlur'): void\n (e: 'selectVariable', value: string): void\n}>()\n\nconst { translate } = useLocalization()\n\ndefineOptions({ inheritAttrs: false })\n\nconst mask = ref(true)\nconst interactingWithDropdown = ref(false)\nconst codeInput = useTemplateRef('codeInput')\nconst maskedInput = useTemplateRef('maskedInput')\n\nconst handleBlur = () => !interactingWithDropdown.value && emit('inputBlur')\n\nconst inputType = computed(() =>\n props.type === 'password' ? 'text' : (props.type ?? 'text'),\n)\n\n// If not an enum nor read only, focus the code input or masked input\nconst handleLabelClick = () => {\n if (!props.enum?.length && !props.readOnly) {\n codeInput.value?.focus()\n maskedInput.value?.focus()\n }\n}\n</script>\n<template>\n <DataTableCell\n class=\"relative flex\"\n :class=\"containerClass\">\n <div\n v-if=\"$slots.default\"\n class=\"text-c-1 flex items-center pr-0 pl-3\"\n @click=\"handleLabelClick\">\n <slot />:\n </div>\n <div class=\"relative flex min-w-0 flex-1\">\n <template v-if=\"props.enum && props.enum.length\">\n <DataTableInputSelect\n :canAddCustomValue=\"props.canAddCustomEnumValue\"\n :modelValue=\"props.modelValue\"\n :value=\"props.enum\"\n @update:modelValue=\"emit('update:modelValue', $event)\" />\n </template>\n <template v-else>\n <input\n v-if=\"mask && type === 'password'\"\n v-bind=\"id ? { ...$attrs, id: id } : $attrs\"\n ref=\"maskedInput\"\n autocomplete=\"off\"\n class=\"text-c-1 disabled:text-c-2 peer w-full min-w-0 border-none px-2 py-1.25 -outline-offset-1\"\n :class=\"{ 'scalar-password-input': type === 'password' }\"\n data-1p-ignore\n :readOnly=\"readOnly\"\n spellcheck=\"false\"\n :type=\"inputType\"\n :value=\"modelValue\"\n @input=\"\n emit(\n 'update:modelValue',\n ($event.target as HTMLInputElement).value ?? '',\n )\n \" />\n <CodeInputLite\n v-else\n v-bind=\"$attrs\"\n :id=\"id\"\n ref=\"codeInput\"\n class=\"text-c-1 disabled:text-c-2 peer w-full min-w-0 border-none -outline-offset-1\"\n :class=\"[\n type === 'password' && description && 'pr-12',\n description && 'pr-8',\n type === 'password' && 'scalar-password-input',\n ]\"\n :environment=\"environment\"\n :modelValue=\"modelValue ?? ''\"\n :readOnly=\"readOnly\"\n :required=\"Boolean(required)\"\n :type=\"inputType\"\n :withFakeData=\"withFakeData\"\n @blur=\"handleBlur\"\n @focus=\"emit('inputFocus')\"\n @update:modelValue=\"(value) => emit('update:modelValue', value)\" />\n </template>\n </div>\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 <slot name=\"icon\" />\n <!-- Clear -->\n <ScalarIconButton\n v-if=\"modelValue && !readOnly\"\n class=\"-ml-.25 h-6 w-6 self-center p-1.25\"\n :icon=\"ScalarIconX\"\n :label=\"translate('apiClient.dataTableInput.clearValue')\"\n @click=\"emit('update:modelValue', '')\" />\n <!-- Toggle Visibility -->\n <!-- A toggle button keeps one name and reports its state, so the label\n stays \"Show Password\" while `aria-pressed` says whether the value is\n revealed. Flipping the name instead leaves screen readers silent,\n because activating a button does not re-announce its name. -->\n <ScalarIconButton\n v-if=\"type === 'password'\"\n :aria-pressed=\"!mask\"\n class=\"-ml-.5 mr-1.25 h-6 w-6 self-center p-1.25\"\n data-testid=\"data-table-password-toggle\"\n :icon=\"mask ? ScalarIconEye : ScalarIconEyeSlash\"\n :label=\"translate('apiClient.dataTableInput.showPassword')\"\n @click=\"mask = !mask\" />\n </DataTableCell>\n</template>\n\n<style scoped>\n:deep(.code-input-lite__editor) {\n background-color: transparent;\n font-family: var(--scalar-font);\n font-size: var(--scalar-small);\n padding: 5px 8px;\n}\n:deep(.scalar-pill:not(:last-of-type)) {\n margin-right: 0.15em;\n}\n:deep(.scalar-pill:not(:first-of-type)) {\n margin-left: 0.5px;\n}\n/* Tailwind placeholder is busted */\ninput::placeholder {\n color: var(--scalar-color-3);\n}\n/* we want our inputs to look like a password input but not be one */\n.scalar-password-input {\n text-security: disc;\n -webkit-text-security: disc;\n -moz-text-security: disc;\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAaA,MAAM,QAAQ;EAyBd,MAAM,OAAO;EAOb,MAAM,EAAE,cAAc,gBAAgB;EAItC,MAAM,OAAO,IAAI,IAAI;EACrB,MAAM,0BAA0B,IAAI,KAAK;EACzC,MAAM,YAAY,eAAe,WAAW;EAC5C,MAAM,cAAc,eAAe,aAAa;EAEhD,MAAM,mBAAmB,CAAC,wBAAwB,SAAS,KAAK,WAAW;EAE3E,MAAM,YAAY,eAChB,MAAM,SAAS,aAAa,SAAU,MAAM,QAAQ,MACtD;EAGA,MAAM,yBAAyB;GAC7B,IAAI,CAAC,MAAM,MAAM,UAAU,CAAC,MAAM,UAAU;IAC1C,UAAU,OAAO,MAAM;IACvB,YAAY,OAAO,MAAM;GAC3B;EACF;;uBAGE,YAoFgB,uBAAA,EAnFd,OAAK,eAAA,CAAC,iBACE,QAAA,cAAc,CAAA,EAAA,GAAA;2BAMhB;KAJEA,KAAAA,OAAO,WAAA,UAAA,GADf,mBAKM,OAAA;;MAHJ,OAAM;MACL,SAAO;SACR,WAAQ,KAAA,QAAA,WAAA,CAAA,GAAA,KAAA,GAAA,IAAA,GAAA,OAAA,OAAA,OAAA,KAAA,gBAAA,MACV,EAAA,EAAA,CAAA,KAAA,mBAAA,IAAA,IAAA;KACA,mBAgDM,OAhDN,YAgDM,CA/CY,MAAM,QAAQ,MAAM,KAAK,UAAA,UAAA,GACvC,YAI2D,8BAAA;;MAHxD,mBAAmB,MAAM;MACzB,YAAY,MAAM;MAClB,OAAO,MAAM;MACb,uBAAiB,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,qBAAsB,MAAM;;;;;yBAExD,mBAuCW,UAAA,EAAA,KAAA,EAAA,GAAA,CArCD,KAAA,SAAQ,QAAA,SAAI,cAAA,UAAA,GADpB,mBAiBM,SAjBN,WAiBM,EAAA,KAAA,EAAA,GAfI,QAAA,KAAE;MAAA,GAAQC,KAAAA;MAAM,IAAM,QAAA;KAAE,IAAKA,KAAAA,QAAM;eACvC;MAAJ,KAAI;MACJ,cAAa;MACb,OAAK,CAAC,6FAA2F,EAAA,yBAC9D,QAAA,SAAI,WAAA,CAAA;MACvC,kBAAA;MACC,UAAU,QAAA;MACX,YAAW;MACV,MAAM,UAAA;MACN,OAAO,QAAA;MACP,SAAK,OAAA,OAAA,OAAA,MAAA,WAAe,KAAA,qBAAwD,OAAO,OAA4B,SAAK,EAAA;gDAMvH,YAmBqE,MAAA,qBAAA,GAnBrE,WAmBqE,EAAA,KAAA,EAAA,GAjB3DA,KAAAA,QAAM;MACb,IAAI,QAAA;eACD;MAAJ,KAAI;MACJ,OAAK,CAAC,gFAA8E;OAC9D,QAAA,SAAI,cAAmB,QAAA,eAAW;OAAyB,QAAA,eAAW;OAAwB,QAAA,SAAI,cAAA;;MAKvH,aAAa,QAAA;MACb,YAAY,QAAA,cAAU;MACtB,UAAU,QAAA;MACV,UAAU,QAAQ,QAAA,QAAQ;MAC1B,MAAM,UAAA;MACN,cAAc,QAAA;MACd,QAAM;MACN,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,YAAA;MACX,uBAAiB,OAAA,OAAA,OAAA,MAAG,UAAU,KAAI,qBAAsB,KAAK;;;;;;;;;;;KAI5DD,KAAAA,OAAO,WAAA,UAAA,GADf,mBAIM,OAJN,YAIM,CADJ,WAAuB,KAAA,QAAA,WAAA,CAAA,GAAA,KAAA,GAAA,IAAA,CAAA,CAAA,KAAA,mBAAA,IAAA,IAAA;KAEzB,WAAoB,KAAA,QAAA,QAAA,CAAA,GAAA,KAAA,GAAA,IAAA;KAGZ,QAAA,cAAU,CAAK,QAAA,YAAA,UAAA,GADvB,YAK2C,MAAA,gBAAA,GAAA;;MAHzC,OAAM;MACL,MAAM,MAAA,WAAA;MACN,OAAO,MAAA,SAAA,CAAS,CAAA,qCAAA;MAChB,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,qBAAA,EAAA;;KAON,QAAA,SAAI,cAAA,UAAA,GADZ,YAO0B,MAAA,gBAAA,GAAA;;MALvB,gBAAY,CAAG,KAAA;MAChB,OAAM;MACN,eAAY;MACX,MAAM,KAAA,QAAO,MAAA,aAAA,IAAgB,MAAA,kBAAA;MAC7B,OAAO,MAAA,SAAA,CAAS,CAAA,uCAAA;MAChB,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,KAAA,QAAI,CAAI,KAAA"}
1
+ {"version":3,"file":"DataTableInput.vue.script.js","names":["$slots","$attrs"],"sources":["../../../../src/v2/components/data-table/DataTableInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarIconButton } from '@scalar/components/icon-button'\nimport { ScalarIconEye, ScalarIconEyeSlash, ScalarIconX } from '@scalar/icons'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { computed, nextTick, ref, useTemplateRef, watch } from 'vue'\n\nimport type { VueClassProp } from '@/types/vue'\nimport { CodeInputLite } from '@/v2/components/code-input'\nimport { useLocalization } from '@/v2/features/localization'\n\nimport DataTableCell from './DataTableCell.vue'\nimport DataTableInputSelect from './DataTableInputSelect.vue'\n\nconst props = withDefaults(\n defineProps<{\n id?: string\n type?: string | undefined\n /** Class for the wrapping cell because attrs is bound to the input */\n containerClass?: VueClassProp | undefined\n required?: boolean\n modelValue: string\n /** Allows adding a custom value to the enum dropdown, defaults to true */\n canAddCustomEnumValue?: boolean\n readOnly?: boolean\n enum?: string[]\n environment: XScalarEnvironment\n description?: string | undefined\n /** Whether to show context function suggestions like $guid, $timestamp. Defaults to true */\n withFakeData?: boolean\n }>(),\n {\n canAddCustomEnumValue: true,\n required: false,\n readOnly: false,\n withFakeData: true,\n },\n)\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', v: string | number): void\n (e: 'inputFocus'): void\n (e: 'inputBlur'): void\n (e: 'selectVariable', value: string): void\n}>()\n\nconst { translate } = useLocalization()\n\ndefineOptions({ inheritAttrs: false })\n\nconst mask = ref(true)\nconst interactingWithDropdown = ref(false)\nconst codeInput = useTemplateRef('codeInput')\nconst maskedInput = useTemplateRef('maskedInput')\n\n/**\n * Whether focus is inside the field. Tracked with focusin and focusout on the wrapper because the\n * revealed editor does not report its own focus, and swapping it out mid-typing would drop focus.\n */\nconst fieldFocused = ref(false)\n\n/** There is nothing to reveal in an empty field, so the toggle only shows once it has a value */\nconst showVisibilityToggle = computed(\n () => props.type === 'password' && Boolean(props.modelValue),\n)\n\n// An emptied secret goes back to masked, so whatever is typed or pasted next stays hidden\nwatch(\n () => props.modelValue,\n (value) => {\n if (!value && !fieldFocused.value) {\n mask.value = true\n }\n },\n)\n\n/** A field emptied while typing in the revealed editor masks once focus leaves it */\nconst handleFieldFocusOut = (): void => {\n fieldFocused.value = false\n\n if (!props.modelValue) {\n mask.value = true\n }\n}\n\nconst handleBlur = () => !interactingWithDropdown.value && emit('inputBlur')\n\nconst inputType = computed(() =>\n props.type === 'password' ? 'text' : (props.type ?? 'text'),\n)\n\n/** Focus whichever editor is showing, the masked input or the code input */\nconst focus = (): void => {\n codeInput.value?.focus()\n maskedInput.value?.focus()\n}\n\n// If not an enum nor read only, focus the code input or masked input\nconst handleLabelClick = () => {\n if (!props.enum?.length && !props.readOnly) {\n focus()\n }\n}\n\n/**\n * The clear button disappears once the field is empty, so focus moves to the field instead of\n * falling back to the page. A cleared secret is masked again so the next one is not shown.\n */\nconst clearValue = async (): Promise<void> => {\n mask.value = true\n emit('update:modelValue', '')\n await nextTick()\n focus()\n}\n\ndefineExpose({ focus })\n</script>\n<template>\n <DataTableCell\n class=\"relative flex\"\n :class=\"containerClass\">\n <div\n v-if=\"$slots.default\"\n class=\"text-c-1 flex items-center pr-0 pl-3\"\n @click=\"handleLabelClick\">\n <slot />:\n </div>\n <div\n class=\"relative flex min-w-0 flex-1\"\n @focusin=\"fieldFocused = true\"\n @focusout=\"handleFieldFocusOut\">\n <template v-if=\"props.enum && props.enum.length\">\n <DataTableInputSelect\n :canAddCustomValue=\"props.canAddCustomEnumValue\"\n :modelValue=\"props.modelValue\"\n :value=\"props.enum\"\n @update:modelValue=\"emit('update:modelValue', $event)\" />\n </template>\n <template v-else>\n <input\n v-if=\"mask && type === 'password'\"\n v-bind=\"id ? { ...$attrs, id: id } : $attrs\"\n ref=\"maskedInput\"\n autocomplete=\"off\"\n class=\"text-c-1 disabled:text-c-2 peer w-full min-w-0 border-none px-2 py-1.25 -outline-offset-1\"\n :class=\"{ 'scalar-password-input': type === 'password' }\"\n data-1p-ignore\n :readOnly=\"readOnly\"\n spellcheck=\"false\"\n :type=\"inputType\"\n :value=\"modelValue\"\n @input=\"\n emit(\n 'update:modelValue',\n ($event.target as HTMLInputElement).value ?? '',\n )\n \" />\n <CodeInputLite\n v-else\n v-bind=\"$attrs\"\n :id=\"id\"\n ref=\"codeInput\"\n class=\"text-c-1 disabled:text-c-2 peer w-full min-w-0 border-none -outline-offset-1\"\n :class=\"[\n type === 'password' && description && 'pr-12',\n description && 'pr-8',\n type === 'password' && 'scalar-password-input',\n ]\"\n :environment=\"environment\"\n :modelValue=\"modelValue ?? ''\"\n :readOnly=\"readOnly\"\n :required=\"Boolean(required)\"\n :type=\"inputType\"\n :withFakeData=\"withFakeData\"\n @blur=\"handleBlur\"\n @focus=\"emit('inputFocus')\"\n @update:modelValue=\"(value) => emit('update:modelValue', value)\" />\n </template>\n </div>\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 <slot name=\"icon\" />\n <!-- Clear -->\n <ScalarIconButton\n v-if=\"modelValue && !readOnly\"\n class=\"-ml-.25 h-6 w-6 self-center p-1.25\"\n :icon=\"ScalarIconX\"\n :label=\"translate('apiClient.dataTableInput.clearValue')\"\n @click=\"clearValue\" />\n <!-- Toggle Visibility -->\n <!-- A toggle button keeps one name and reports its state, so the label\n stays \"Show Password\" while `aria-pressed` says whether the value is\n revealed. Flipping the name instead leaves screen readers silent,\n because activating a button does not re-announce its name. -->\n <ScalarIconButton\n v-if=\"showVisibilityToggle\"\n :aria-pressed=\"!mask\"\n class=\"-ml-.5 mr-1.25 h-6 w-6 self-center p-1.25\"\n data-testid=\"data-table-password-toggle\"\n :icon=\"mask ? ScalarIconEye : ScalarIconEyeSlash\"\n :label=\"translate('apiClient.dataTableInput.showPassword')\"\n @click=\"mask = !mask\" />\n </DataTableCell>\n</template>\n\n<style scoped>\n:deep(.code-input-lite__editor) {\n background-color: transparent;\n font-family: var(--scalar-font);\n font-size: var(--scalar-small);\n padding: 5px 8px;\n}\n:deep(.scalar-pill:not(:last-of-type)) {\n margin-right: 0.15em;\n}\n:deep(.scalar-pill:not(:first-of-type)) {\n margin-left: 0.5px;\n}\n/* Tailwind placeholder is busted */\ninput::placeholder {\n color: var(--scalar-color-3);\n}\n/* we want our inputs to look like a password input but not be one */\n.scalar-password-input {\n text-security: disc;\n -webkit-text-security: disc;\n -moz-text-security: disc;\n}\n</style>\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ServerDropdown.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/components/server/ServerDropdown.vue"],"names":[],"mappings":"AA0JA,OAAO,KAAK,EAEV,UAAU,EACX,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8DAA8D,CAAA;AAKhG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAKrD;;;GAGG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAMzC,MAAM,MAAM,mBAAmB,GAAG;IAChC,0CAA0C;IAC1C,IAAI,EAAE,UAAU,CAAA;IAChB,0EAA0E;IAC1E,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,gCAAgC;IAChC,MAAM,EAAE,YAAY,GAAG,IAAI,CAAA;IAC3B,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAA;IACd,oBAAoB;IACpB,MAAM,EAAE,YAAY,CAAA;CACrB,CAAA;AACD,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;kFAoTd,CAAC"}
1
+ {"version":3,"file":"ServerDropdown.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/components/server/ServerDropdown.vue"],"names":[],"mappings":"AAmJA,OAAO,KAAK,EAEV,UAAU,EACX,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8DAA8D,CAAA;AAKhG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAKrD;;;GAGG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAMzC,MAAM,MAAM,mBAAmB,GAAG;IAChC,0CAA0C;IAC1C,IAAI,EAAE,UAAU,CAAA;IAChB,0EAA0E;IAC1E,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,gCAAgC;IAChC,MAAM,EAAE,YAAY,GAAG,IAAI,CAAA;IAC3B,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAA;IACd,oBAAoB;IACpB,MAAM,EAAE,YAAY,CAAA;CACrB,CAAA;AACD,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;kFAmSd,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ServerDropdown.vue.js","names":[],"sources":["../../../../src/v2/components/server/ServerDropdown.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * ServerDropdown component\n * This component is used to display the server dropdown for the operation block\n */\nexport default {\n name: 'ServerDropdown',\n}\n\nexport type ServerDropdownProps = {\n /** The meta information for the server */\n meta: ServerMeta\n /** List of servers that are available for the operation/document level */\n servers: ServerObject[]\n /** Currently selected server */\n server: ServerObject | null\n /** The id of the target to use for the popover (e.g. address bar) */\n target: string\n /** Client layout */\n layout: ClientLayout\n}\n</script>\n<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarFloatingBackdrop } from '@scalar/components/floating'\nimport { ScalarPopover } from '@scalar/components/popover'\nimport { ScalarIconPencilSimple, ScalarIconPlus } from '@scalar/icons'\nimport type {\n ApiReferenceEvents,\n ServerMeta,\n} from '@scalar/workspace-store/events'\nimport type { ServerObject } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { computed } from 'vue'\n\nimport ValueEmitter from '@/v2/components/layout/ValueEmitter.vue'\nimport { useLocalization } from '@/v2/features/localization'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nimport ServerDropdownItem from './ServerDropdownItem.vue'\n\nconst { target, server, servers, meta } = defineProps<ServerDropdownProps>()\n\nconst emit = defineEmits<{\n /** Update a server variable for the selected server */\n (\n e: 'update:selectedServer',\n payload: ApiReferenceEvents['server:update:selected'],\n ): void\n (\n e: 'update:variable',\n payload: ApiReferenceEvents['server:update:variables'],\n ): void\n (e: 'update:servers'): void\n /** Update the open state of the server dropdown */\n (e: 'update:open', value: boolean): void\n}>()\n\nconst { translate } = useLocalization()\n\nconst requestServerOptions = computed(() =>\n servers.map((s) => ({\n id: s.url,\n // Prefer the server name (OpenAPI 3.2) as a friendly label, falling back to the URL\n label:\n s.name || s.url || translate('apiClient.serverDropdown.unknownServer'),\n })),\n)\n\nconst serverUrlWithoutTrailingSlash = computed(() => {\n if (server?.url?.endsWith('/')) {\n return server.url.slice(0, -1)\n }\n return server?.url || ''\n})\n</script>\n<template>\n <ScalarPopover\n class=\"max-h-[inherit] p-0 text-base\"\n focus\n :offset=\"0\"\n placement=\"bottom\"\n resize\n :target=\"target\"\n :teleport=\"`#${target}`\">\n <ScalarButton\n class=\"hover:bg-b-2 font-code text-c-2 h-auto gap-0.75 rounded border px-1.5 text-base whitespace-nowrap @3xl:ml-0.75\"\n variant=\"ghost\">\n <template v-if=\"server\">\n <span class=\"sr-only\">{{\n translate('apiClient.serverDropdown.server')\n }}</span>\n {{ serverUrlWithoutTrailingSlash }}\n </template>\n <template v-else>\n <span class=\"sr-only\">{{\n translate('apiClient.serverDropdown.addServer')\n }}</span>\n <ScalarIconPlus class=\"size-3\" />\n </template>\n </ScalarButton>\n\n <template #popover=\"{ close }\">\n <div\n class=\"custom-scroll flex max-h-[inherit] flex-col gap-1 p-1\"\n @click=\"close\">\n <!-- Request -->\n <ServerDropdownItem\n v-for=\"(serverOption, index) in requestServerOptions\"\n :key=\"serverOption.id\"\n :server=\"server\"\n :serverOption=\"serverOption\"\n type=\"request\"\n @update:selectedServer=\"\n emit('update:selectedServer', { url: serverOption.id, meta })\n \"\n @update:variable=\"\n (key, value) => emit('update:variable', { index, key, value, meta })\n \" />\n\n <!-- Add Server -->\n <template v-if=\"layout !== 'modal'\">\n <button\n class=\"text-xxs hover:bg-b-2 flex cursor-pointer items-center gap-1.5 rounded p-1.75\"\n type=\"button\"\n @click=\"emit('update:servers')\">\n <div class=\"flex items-center justify-center\">\n <ScalarIconPencilSimple class=\"size-4\" />\n </div>\n <span>{{\n translate('apiClient.serverDropdown.updateServers')\n }}</span>\n </button>\n </template>\n </div>\n </template>\n <template #backdrop=\"{ open }\">\n <!-- Emit the slot value back out the parent -->\n <ValueEmitter\n :value=\"open\"\n @change=\"(value) => emit('update:open', value)\"\n @unmount=\"emit('update:open', false)\" />\n\n <ScalarFloatingBackdrop\n class=\"rounded-none rounded-b-lg border border-t-0 after:hidden\" />\n </template>\n </ScalarPopover>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"ServerDropdown.vue.js","names":[],"sources":["../../../../src/v2/components/server/ServerDropdown.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * ServerDropdown component\n * This component is used to display the server dropdown for the operation block\n */\nexport default {\n name: 'ServerDropdown',\n}\n\nexport type ServerDropdownProps = {\n /** The meta information for the server */\n meta: ServerMeta\n /** List of servers that are available for the operation/document level */\n servers: ServerObject[]\n /** Currently selected server */\n server: ServerObject | null\n /** The id of the target to use for the popover (e.g. address bar) */\n target: string\n /** Client layout */\n layout: ClientLayout\n}\n</script>\n<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarPopover } from '@scalar/components/popover'\nimport { ScalarIconPencilSimple, ScalarIconPlus } from '@scalar/icons'\nimport type {\n ApiReferenceEvents,\n ServerMeta,\n} from '@scalar/workspace-store/events'\nimport type { ServerObject } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { computed } from 'vue'\n\nimport ValueEmitter from '@/v2/components/layout/ValueEmitter.vue'\nimport { useLocalization } from '@/v2/features/localization'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nimport ServerDropdownItem from './ServerDropdownItem.vue'\n\nconst { target, server, servers, meta } = defineProps<ServerDropdownProps>()\n\nconst emit = defineEmits<{\n /** Update a server variable for the selected server */\n (\n e: 'update:selectedServer',\n payload: ApiReferenceEvents['server:update:selected'],\n ): void\n (\n e: 'update:variable',\n payload: ApiReferenceEvents['server:update:variables'],\n ): void\n (e: 'update:servers'): void\n /** Update the open state of the server dropdown */\n (e: 'update:open', value: boolean): void\n}>()\n\nconst { translate } = useLocalization()\n\nconst requestServerOptions = computed(() =>\n servers.map((s) => ({\n id: s.url,\n // Prefer the server name (OpenAPI 3.2) as a friendly label, falling back to the URL\n label:\n s.name || s.url || translate('apiClient.serverDropdown.unknownServer'),\n })),\n)\n\nconst serverUrlWithoutTrailingSlash = computed(() => {\n if (server?.url?.endsWith('/')) {\n return server.url.slice(0, -1)\n }\n return server?.url || ''\n})\n</script>\n<template>\n <ScalarPopover\n class=\"max-h-[inherit] rounded-none rounded-b-lg border border-t-0 p-0 text-base inset-shadow-none\"\n focus\n :offset=\"0\"\n placement=\"bottom\"\n resize\n :target=\"target\"\n :teleport=\"`#${target}`\">\n <ScalarButton\n class=\"hover:bg-b-2 font-code text-c-2 h-auto gap-0.75 rounded border px-1.5 text-base whitespace-nowrap @3xl:ml-0.75\"\n variant=\"ghost\">\n <template v-if=\"server\">\n <span class=\"sr-only\">{{\n translate('apiClient.serverDropdown.server')\n }}</span>\n {{ serverUrlWithoutTrailingSlash }}\n </template>\n <template v-else>\n <span class=\"sr-only\">{{\n translate('apiClient.serverDropdown.addServer')\n }}</span>\n <ScalarIconPlus class=\"size-3\" />\n </template>\n </ScalarButton>\n\n <template #popover=\"{ close, open }\">\n <!-- Emit the slot value back out the parent -->\n <ValueEmitter\n :value=\"open\"\n @change=\"(value) => emit('update:open', value)\"\n @unmount=\"emit('update:open', false)\" />\n <div\n class=\"custom-scroll flex max-h-[inherit] flex-col gap-1 p-1\"\n @click=\"close\">\n <!-- Request -->\n <ServerDropdownItem\n v-for=\"(serverOption, index) in requestServerOptions\"\n :key=\"serverOption.id\"\n :server=\"server\"\n :serverOption=\"serverOption\"\n type=\"request\"\n @update:selectedServer=\"\n emit('update:selectedServer', { url: serverOption.id, meta })\n \"\n @update:variable=\"\n (key, value) => emit('update:variable', { index, key, value, meta })\n \" />\n\n <!-- Add Server -->\n <template v-if=\"layout !== 'modal'\">\n <button\n class=\"text-xxs hover:bg-b-2 flex cursor-pointer items-center gap-1.5 rounded p-1.75\"\n type=\"button\"\n @click=\"emit('update:servers')\">\n <div class=\"flex items-center justify-center\">\n <ScalarIconPencilSimple class=\"size-4\" />\n </div>\n <span>{{\n translate('apiClient.serverDropdown.updateServers')\n }}</span>\n </button>\n </template>\n </div>\n </template>\n </ScalarPopover>\n</template>\n"],"mappings":""}