@scalar/api-reference
Version:
Generate beautiful API references from OpenAPI documents
181 lines (180 loc) • 8.03 kB
JavaScript
import { REQUEST_BODY_COMPOSITION_INDEX_SYMBOL } from "../../../features/Operation/request-body-composition-index.js";
import { getSchemaType } from "./helpers/get-schema-type.js";
import { mergeAllOfSchemas } from "./helpers/merge-all-of-schemas.js";
import { getModelNameFromSchema } from "./helpers/schema-name.js";
import Schema_default from "./Schema.vue.js";
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, inject, normalizeClass, openBlock, ref, toDisplayString, unref, watch, withCtx } from "vue";
import { ScalarListbox } from "@scalar/components";
import { ScalarIconCaretDown } from "@scalar/icons";
import { resolve } from "@scalar/workspace-store/resolve";
import { isDefined } from "@scalar/helpers/array/is-defined";
//#region src/components/Content/Schema/SchemaComposition.vue?vue&type=script&setup=true&lang.ts
var _hoisted_1 = { class: "property-rule" };
var _hoisted_2 = {
class: "composition-selector bg-b-1.5 hover:bg-b-2 flex w-full cursor-pointer items-center gap-1 rounded-t-lg border px-2.5 py-2.5 pr-3 text-left",
type: "button"
};
var _hoisted_3 = { class: "text-c-2" };
var _hoisted_4 = {
key: 0,
class: "text-red"
};
var _hoisted_5 = { class: "composition-panel" };
var SchemaComposition_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
__name: "SchemaComposition",
props: {
composition: {},
discriminator: {},
name: {},
schema: {},
level: {},
compact: {
type: Boolean,
default: false
},
hideHeading: {
type: Boolean,
default: false
},
hideModelNames: { type: Boolean },
breadcrumb: {},
eventBus: {},
options: {},
schemaContext: {},
compositionPath: {}
},
setup(__props) {
const props = __props;
/** The current composition */
const composition = computed(() => [props.schema[props.composition]].flat().map((schema) => ({
value: resolve.schema(schema),
original: schema
})).filter((it) => isDefined(it.value)));
/**
* Generate listbox options for the composition selector.
* Each option represents a schema in the composition with a human-readable label.
* Prefers schema title/name over structural type when present.
*/
const listboxOptions = computed(() => composition.value.map((schema, index) => {
const resolved = resolve.schema(schema.original);
const label = (getModelNameFromSchema(resolved)?.label ?? getSchemaType(resolved)) || "Schema";
return {
id: String(index),
label
};
}));
const compositionSelectionKey = computed(() => props.compositionPath?.length ? [...props.compositionPath, props.composition].join(".") : "");
/** When this composition is in the request body, sync selection with the example snippet */
const requestBodyCompositionSelectionRef = inject(REQUEST_BODY_COMPOSITION_INDEX_SYMBOL, void 0);
const initialSelectedIndex = computed(() => {
if (props.schemaContext !== "requestBody" || !requestBodyCompositionSelectionRef?.value || !compositionSelectionKey.value) return 0;
const selectedIndex = requestBodyCompositionSelectionRef.value[compositionSelectionKey.value];
if (typeof selectedIndex !== "number" || Number.isNaN(selectedIndex)) return 0;
return Math.max(0, Math.min(selectedIndex, listboxOptions.value.length - 1));
});
/**
* Two-way computed property for the selected option.
* Handles conversion between the selected index and the listbox option format.
*/
const selectedOption = ref();
watch([listboxOptions, initialSelectedIndex], ([options, selectedIndex]) => {
if (!selectedOption.value || !options.some((option) => option.id === selectedOption.value?.id)) selectedOption.value = options[selectedIndex] ?? options[0];
}, { immediate: true });
/**
* Humanize composition keyword name for display.
* Converts camelCase to Title Case (e.g., oneOf -> One of).
*/
const humanizeType = (type) => type.replace(/([A-Z])/g, " $1").replace(/^./, (str) => str.toUpperCase()).toLowerCase().replace(/^(\w)/, (c) => c.toUpperCase());
/** Inside the currently selected composition */
const selectedComposition = computed(() => composition.value[Number(selectedOption.value?.id ?? "0")]?.value);
/** Controls whether the nested schema is displayed */
const showNestedSchema = ref(false);
if (requestBodyCompositionSelectionRef && props.schemaContext === "requestBody" && compositionSelectionKey.value) watch(selectedOption, (option) => {
const index = option ? Number(option.id) : 0;
if (!Number.isNaN(index)) requestBodyCompositionSelectionRef.value = {
...requestBodyCompositionSelectionRef.value,
[compositionSelectionKey.value]: index
};
}, { immediate: true });
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", _hoisted_1, [props.composition === "allOf" ? (openBlock(), createBlock(Schema_default, {
key: 0,
breadcrumb: __props.breadcrumb,
compact: __props.compact,
compositionPath: __props.compositionPath,
discriminator: __props.discriminator,
eventBus: __props.eventBus,
hideHeading: __props.hideHeading,
hideModelNames: __props.hideModelNames,
level: __props.level + 1,
name: __props.name,
noncollapsible: true,
options: __props.options,
schema: unref(mergeAllOfSchemas)(__props.schema),
schemaContext: __props.schemaContext
}, null, 8, [
"breadcrumb",
"compact",
"compositionPath",
"discriminator",
"eventBus",
"hideHeading",
"hideModelNames",
"level",
"name",
"options",
"schema",
"schemaContext"
])) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createVNode(unref(ScalarListbox), {
modelValue: selectedOption.value,
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => selectedOption.value = $event),
options: listboxOptions.value,
resize: ""
}, {
default: withCtx(() => [createElementVNode("button", _hoisted_2, [
createElementVNode("span", _hoisted_3, toDisplayString(humanizeType(props.composition)), 1),
createElementVNode("span", { class: normalizeClass(["composition-selector-label text-c-1", { "line-through": selectedComposition.value?.deprecated }]) }, toDisplayString(selectedOption.value?.label || "Schema"), 3),
selectedComposition.value?.deprecated ? (openBlock(), createElementBlock("div", _hoisted_4, " deprecated ")) : createCommentVNode("", true),
createVNode(unref(ScalarIconCaretDown))
])]),
_: 1
}, 8, ["modelValue", "options"]), createElementVNode("div", _hoisted_5, [!showNestedSchema.value && __props.level > 2 ? (openBlock(), createElementBlock("button", {
key: 0,
class: "bg-b-1 hover:bg-b-2 text-c-1 flex w-full items-center justify-center gap-2 rounded-b-lg border border-t-0 px-2 py-2 text-sm font-medium transition-colors",
type: "button",
onClick: _cache[1] || (_cache[1] = ($event) => showNestedSchema.value = true)
}, [_cache[2] || (_cache[2] = createTextVNode(" Show Schema Details ", -1)), createVNode(unref(ScalarIconCaretDown), { class: "h-3 w-3" })])) : (openBlock(), createBlock(Schema_default, {
key: 1,
breadcrumb: __props.breadcrumb,
compact: __props.compact,
compositionPath: __props.compositionPath,
discriminator: __props.discriminator,
eventBus: __props.eventBus,
hideHeading: __props.hideHeading,
hideModelNames: __props.hideModelNames,
level: __props.level + 1,
name: __props.name,
noncollapsible: true,
options: __props.options,
schema: selectedComposition.value,
schemaContext: __props.schemaContext
}, null, 8, [
"breadcrumb",
"compact",
"compositionPath",
"discriminator",
"eventBus",
"hideHeading",
"hideModelNames",
"level",
"name",
"options",
"schema",
"schemaContext"
]))])], 64))]);
};
}
});
//#endregion
export { SchemaComposition_vue_vue_type_script_setup_true_lang_default as default };
//# sourceMappingURL=SchemaComposition.vue.script.js.map