@scalar/blocks 0.5.2 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/code-example/helpers/operation-to-har/process-body.d.ts.map +1 -1
  3. package/dist/code-example/helpers/operation-to-har/process-body.js +42 -42
  4. package/dist/code-example/helpers/operation-to-har/process-body.js.map +1 -1
  5. package/dist/constants.js +1 -1
  6. package/dist/schema/Schema.vue.d.ts.map +1 -1
  7. package/dist/schema/Schema.vue.js +1 -1
  8. package/dist/schema/Schema.vue.js.map +1 -1
  9. package/dist/schema/Schema.vue.script.js +122 -116
  10. package/dist/schema/Schema.vue.script.js.map +1 -1
  11. package/dist/schema/SchemaComposition.vue.d.ts.map +1 -1
  12. package/dist/schema/SchemaComposition.vue.js +1 -1
  13. package/dist/schema/SchemaComposition.vue.js.map +1 -1
  14. package/dist/schema/SchemaComposition.vue.script.js +110 -106
  15. package/dist/schema/SchemaComposition.vue.script.js.map +1 -1
  16. package/dist/schema/SchemaEnumPropertyItem.vue.js.map +1 -1
  17. package/dist/schema/SchemaEnumPropertyItem.vue.script.js +2 -2
  18. package/dist/schema/SchemaEnumPropertyItem.vue.script.js.map +1 -1
  19. package/dist/schema/SchemaProperty.vue.d.ts +1 -1
  20. package/dist/schema/SchemaProperty.vue.d.ts.map +1 -1
  21. package/dist/schema/SchemaProperty.vue.js +1 -1
  22. package/dist/schema/SchemaProperty.vue.js.map +1 -1
  23. package/dist/schema/SchemaProperty.vue.script.js +179 -167
  24. package/dist/schema/SchemaProperty.vue.script.js.map +1 -1
  25. package/dist/schema/SchemaPropertyHeading.vue.d.ts +5 -3
  26. package/dist/schema/SchemaPropertyHeading.vue.d.ts.map +1 -1
  27. package/dist/schema/SchemaPropertyHeading.vue.js +1 -1
  28. package/dist/schema/SchemaPropertyHeading.vue.js.map +1 -1
  29. package/dist/schema/SchemaPropertyHeading.vue.script.js +122 -117
  30. package/dist/schema/SchemaPropertyHeading.vue.script.js.map +1 -1
  31. package/dist/schema/SchemaPropertyPattern.vue.js +1 -1
  32. package/dist/schema/SchemaPropertyPattern.vue.js.map +1 -1
  33. package/dist/schema/SchemaPropertyPattern.vue.script.js +1 -1
  34. package/dist/schema/SchemaPropertyPattern.vue.script.js.map +1 -1
  35. package/dist/schema/discriminator-metadata.d.ts +13 -0
  36. package/dist/schema/discriminator-metadata.d.ts.map +1 -0
  37. package/dist/schema/discriminator-metadata.js +6 -0
  38. package/dist/schema/discriminator-metadata.js.map +1 -0
  39. package/dist/schema/helpers/get-compositions-to-render.d.ts +3 -1
  40. package/dist/schema/helpers/get-compositions-to-render.d.ts.map +1 -1
  41. package/dist/schema/helpers/get-compositions-to-render.js +25 -24
  42. package/dist/schema/helpers/get-compositions-to-render.js.map +1 -1
  43. package/dist/schema/helpers/get-property-description.d.ts +6 -3
  44. package/dist/schema/helpers/get-property-description.d.ts.map +1 -1
  45. package/dist/schema/helpers/get-property-description.js +10 -10
  46. package/dist/schema/helpers/get-property-description.js.map +1 -1
  47. package/dist/schema/helpers/optimize-value-for-display.d.ts.map +1 -1
  48. package/dist/schema/helpers/optimize-value-for-display.js +34 -33
  49. package/dist/schema/helpers/optimize-value-for-display.js.map +1 -1
  50. package/dist/schema/index.d.ts +2 -0
  51. package/dist/schema/index.d.ts.map +1 -1
  52. package/dist/schema/index.js +13 -11
  53. package/dist/schema/localization/index.d.ts +11 -1
  54. package/dist/schema/localization/index.d.ts.map +1 -1
  55. package/dist/schema/localization/locales/ar.d.ts +10 -0
  56. package/dist/schema/localization/locales/ar.d.ts.map +1 -1
  57. package/dist/schema/localization/locales/ar.js +11 -1
  58. package/dist/schema/localization/locales/ar.js.map +1 -1
  59. package/dist/schema/localization/locales/de.d.ts +10 -0
  60. package/dist/schema/localization/locales/de.d.ts.map +1 -1
  61. package/dist/schema/localization/locales/de.js +11 -1
  62. package/dist/schema/localization/locales/de.js.map +1 -1
  63. package/dist/schema/localization/locales/en.d.ts +10 -0
  64. package/dist/schema/localization/locales/en.d.ts.map +1 -1
  65. package/dist/schema/localization/locales/en.js +11 -1
  66. package/dist/schema/localization/locales/en.js.map +1 -1
  67. package/dist/schema/localization/locales/es.d.ts +10 -0
  68. package/dist/schema/localization/locales/es.d.ts.map +1 -1
  69. package/dist/schema/localization/locales/es.js +11 -1
  70. package/dist/schema/localization/locales/es.js.map +1 -1
  71. package/dist/schema/localization/locales/fr.d.ts +10 -0
  72. package/dist/schema/localization/locales/fr.d.ts.map +1 -1
  73. package/dist/schema/localization/locales/fr.js +11 -1
  74. package/dist/schema/localization/locales/fr.js.map +1 -1
  75. package/dist/schema/localization/locales/pt.d.ts +10 -0
  76. package/dist/schema/localization/locales/pt.d.ts.map +1 -1
  77. package/dist/schema/localization/locales/pt.js +11 -1
  78. package/dist/schema/localization/locales/pt.js.map +1 -1
  79. package/dist/schema/localization/locales/ru.d.ts +10 -0
  80. package/dist/schema/localization/locales/ru.d.ts.map +1 -1
  81. package/dist/schema/localization/locales/ru.js +11 -1
  82. package/dist/schema/localization/locales/ru.js.map +1 -1
  83. package/dist/schema/localization/locales/zh-cn.d.ts +10 -0
  84. package/dist/schema/localization/locales/zh-cn.d.ts.map +1 -1
  85. package/dist/schema/localization/locales/zh-cn.js +11 -1
  86. package/dist/schema/localization/locales/zh-cn.js.map +1 -1
  87. package/dist/schema/localization/locales/zh-tw.d.ts +10 -0
  88. package/dist/schema/localization/locales/zh-tw.d.ts.map +1 -1
  89. package/dist/schema/localization/locales/zh-tw.js +11 -1
  90. package/dist/schema/localization/locales/zh-tw.js.map +1 -1
  91. package/dist/schema/localization/translations.d.ts +90 -0
  92. package/dist/schema/localization/translations.d.ts.map +1 -1
  93. package/dist/shared/ExternalDocs.vue.d.ts +9 -0
  94. package/dist/shared/ExternalDocs.vue.d.ts.map +1 -0
  95. package/dist/shared/ExternalDocs.vue.js +7 -0
  96. package/dist/shared/ExternalDocs.vue.js.map +1 -0
  97. package/dist/shared/ExternalDocs.vue.script.js +46 -0
  98. package/dist/shared/ExternalDocs.vue.script.js.map +1 -0
  99. package/dist/shared/index.d.ts +1 -0
  100. package/dist/shared/index.d.ts.map +1 -1
  101. package/dist/shared/index.js +4 -3
  102. package/dist/style.css +55 -10
  103. package/dist/vue-styles.css +1 -1
  104. package/package.json +10 -10
@@ -1 +1 @@
1
- {"version":3,"file":"SchemaProperty.vue.script.js","names":[],"sources":["../../src/schema/SchemaProperty.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * The `v-on` binding a row without a disclosure gets. Module scope, and frozen\n * so it cannot be written through: an inline `{}` in the template is a fresh\n * object on every render of every row, and this component renders once per\n * property on the page.\n */\nconst NO_LISTENERS = Object.freeze({})\n</script>\n\n<script lang=\"ts\" setup>\nimport { ScalarMarkdown } from '@scalar/components/markdown'\nimport { ScalarWrappingText } from '@scalar/components/wrapping-text'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport {\n isDynamicRef,\n resolveDynamicRef,\n} from '@scalar/workspace-store/helpers/dynamic-ref'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type {\n DiscriminatorObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { isArraySchema } from '@scalar/workspace-store/schemas/v3.2/strict/type-guards'\nimport {\n computed,\n inject,\n onBeforeUnmount,\n onScopeDispose,\n ref,\n toRef,\n useId,\n useTemplateRef,\n watch,\n type Component,\n} from 'vue'\n\nimport CopyLinkButton from './components/CopyLinkButton.vue'\nimport WithBreadcrumb from './components/WithBreadcrumb.vue'\nimport { resolveDynamicSchema, useDynamicScope } from './helpers/dynamic-scope'\nimport {\n getCompositionsToRender,\n inferDiscriminatorMappingComposition,\n} from './helpers/get-compositions-to-render'\nimport { getEnumValues } from './helpers/get-enum-values'\nimport { getPropertyDescription } from './helpers/get-property-description'\nimport { getRefName } from './helpers/get-ref-name'\nimport { typeSignatureInlinesEnum } from './helpers/get-type-signature-tokens'\nimport { hasComplexArrayItems } from './helpers/has-complex-array-items'\nimport { isTypeObject } from './helpers/is-type-object'\nimport { normalizeObjectComposition } from './helpers/normalize-object-composition'\nimport { optimizeValueForDisplay } from './helpers/optimize-value-for-display'\nimport { partitionAllOfCompositions } from './helpers/partition-all-of-compositions'\nimport type { CompositionKeyword } from './helpers/schema-composition'\nimport { getCycleKey, SCHEMA_ANCESTORS_SYMBOL } from './helpers/schema-cycle'\nimport { toNodeKey, useSchemaExpansion } from './helpers/schema-expansion'\nimport { shouldDisplayDescription } from './helpers/should-display-description'\nimport { shouldDisplayHeading } from './helpers/should-display-heading'\nimport { sortPropertyNames } from './helpers/sort-property-names'\nimport { unwrapForRead } from './helpers/unwrap-for-read'\nimport { useLocalization } from './localization'\nimport Schema from './Schema.vue'\nimport SchemaCollapsedPreview from './SchemaCollapsedPreview.vue'\nimport SchemaComposition from './SchemaComposition.vue'\nimport SchemaEnums from './SchemaEnums.vue'\nimport SchemaGutterToggle from './SchemaGutterToggle.vue'\nimport SchemaPropertyHeading from './SchemaPropertyHeading.vue'\nimport SchemaRailPanel from './SchemaRailPanel.vue'\nimport type { SchemaOptions, SchemaRenderingProps } from './types'\n\nconst props = withDefaults(\n defineProps<\n {\n is?: string | Component\n schema: SchemaObject | undefined\n /** Extensions on the containing parameter or header; schema values take precedence. */\n extensionSource?: Record<string, unknown>\n noncollapsible?: boolean\n level?: number\n /**\n * Real nesting depth. Its own counter because `level` advances by a\n * different stride per edge (object +2, composition +1).\n */\n depth?: number\n name?: string\n required?: boolean\n compact?: boolean\n discriminator?: DiscriminatorObject\n description?: string\n hideModelNames?: boolean\n hideHeading?: boolean\n /** When the root schema was resolved from a $ref, pass the ref name for display (e.g. \"Data\"). */\n modelName?: string | null\n variant?: 'additionalProperties' | 'patternProperties'\n breadcrumb?: string[]\n eventBus: WorkspaceEventBus | null\n options: SchemaOptions\n /** Enum values for property names (from JSON Schema propertyNames keyword). */\n propertyNamesEnum?: string[]\n /** Resolved propertyNames schema, used to show key constraints like `format`. */\n propertyNamesSchema?: SchemaObject\n /** When \"requestBody\", composition selection is synced with the example snippet */\n schemaContext?: string\n /** Internal path used to sync nested request body compositions with the code sample */\n compositionPath?: string[]\n /** Internal path segment for this property when building nested composition keys */\n compositionPathSegment?: string\n /** Stable identity of this property's schema, used for cycle detection. */\n cycleKey?: unknown\n } & SchemaRenderingProps\n >(),\n {\n level: 0,\n depth: 0,\n required: false,\n compact: false,\n hideModelNames: false,\n },\n)\n\n/**\n * Note: We're taking in a prop called `value` which should be a JSON Schema.\n *\n * We're using `optimizeValueForDisplay` to merge null types in compositions (anyOf, allOf, oneOf, not).\n * So you should basically use the optimizedValue everywhere in the component.\n */\n\n/** Composition keywords that hold a list of schemas and can be flattened when they contain a single member. */\nconst SINGLE_ITEM_COMPOSITIONS = ['oneOf', 'anyOf', 'allOf'] as const\n\n/** The dynamic scope inherited from the enclosing schema resources, used to bind `$dynamicRef`s. */\nconst dynamicScope = useDynamicScope()\n\n/**\n * Simplified composition with `null` type.\n *\n * A top-level `$dynamicRef` (e.g. a linked-list `next` node) is bound to its concrete type via the\n * dynamic scope first; for ordinary schemas this is a no-op.\n *\n * The value is unwrapped here as well as at the `Schema` root, because callers such as\n * `ParameterListItem` and `Headers` hand a schema in below a root and would otherwise leave the\n * whole subtree on the reactive and detect-changes proxies. See {@link unwrapForRead}.\n */\nconst optimizedValue = computed(() =>\n normalizeObjectComposition(\n optimizeValueForDisplay(\n resolveDynamicSchema(unwrapForRead(props.schema), dynamicScope),\n ),\n props.name,\n ),\n)\n\n/** Mixed object/choice compositions still belong inside their named property's panel. */\nconst hasObjectComposition = computed((): boolean => {\n const { name } = props\n const value = optimizedValue.value\n return (\n !!name &&\n !!value?.allOf &&\n partitionAllOfCompositions(value).segments.some(\n (segment) => segment.kind === 'object' && isTypeObject(segment.schema),\n )\n )\n})\n\nconst childBreadcrumb = computed<string[] | undefined>(() =>\n props.breadcrumb\n ? // A named property extends the breadcrumb with its own name. A nameless\n // container (e.g. a response object, rendered without a name to avoid a\n // duplicate heading) passes its breadcrumb straight through so its\n // properties stay linkable.\n props.name\n ? [...props.breadcrumb, props.name]\n : props.breadcrumb\n : undefined,\n)\n\nconst currentCompositionPath = computed<string[]>(() =>\n props.compositionPathSegment\n ? [...(props.compositionPath ?? []), props.compositionPathSegment]\n : (props.compositionPath ?? []),\n)\n\nconst arrayItemsCompositionPath = computed<string[]>(() => [\n ...currentCompositionPath.value,\n 'items',\n])\n\nconst shouldHaveLink = computed((): boolean => {\n const target = props.options.linkablePropertyPath\n const path = childBreadcrumb.value\n return (\n props.level <= 2 ||\n Boolean(\n target &&\n path &&\n target.length === path.length &&\n target.every((segment, index) => segment === path[index]),\n )\n )\n})\n\n/**\n * Whether the name gets a deep link (an anchor id and a trailing copy button).\n *\n * Mirrors the condition `WithBreadcrumb` renders its anchor under. Without a link that\n * component only passes its slot through, yet every named row still paid to mount it\n * (a localization inject and an unread label computed), and most rows have no link: any\n * row deeper than level 2, and every row on surfaces that pass no breadcrumb at all\n * (models, the classic layout, AsyncAPI). So the template mounts `WithBreadcrumb` only\n * for linked rows and renders the same name span directly for the rest. Both branches\n * carry an identical copy of the span, comments included: the template comments are\n * DOM nodes in development builds, so the two copies must stay byte-for-byte in step.\n */\nconst hasBreadcrumbLink = computed(\n (): boolean =>\n shouldHaveLink.value && (childBreadcrumb.value?.length ?? 0) > 0,\n)\n\n/**\n * The array schema used for item inspection, with a `$dynamicRef` item bound to its concrete type.\n *\n * Returns the schema unchanged unless `items` is a `$dynamicRef` that resolves against the dynamic\n * scope, so ordinary arrays (including `$ref` items) keep their existing behavior exactly.\n */\nconst arrayValueWithBoundItems = computed(() => {\n const value = optimizedValue.value\n if (!value || !isArraySchema(value) || !isDynamicRef(value.items)) {\n return value\n }\n\n const bound = resolveDynamicRef(value.items.$dynamicRef, dynamicScope)\n return bound ? ({ ...value, items: bound } as SchemaObject) : value\n})\n\n/** Checks if array items have complex structure */\nconst hasComplexArrayItemsComputed = computed(() =>\n hasComplexArrayItems(arrayValueWithBoundItems.value),\n)\n\n/** Check if enum should be displayed (from value schema or from propertyNames) */\nconst hasEnum = computed(() => enumValues.value.length > 0)\n\n/**\n * The `oneOf` inferred from a bare `discriminator.mapping`, or `null` when there\n * is nothing to infer. Computed once and shared: `shouldRenderObjectProperties`\n * uses it to suppress the duplicate base object block, and `compositionsToRender`\n * passes it on so the inference does not run twice per render.\n */\nconst inferredDiscriminatorComposition = computed(() =>\n optimizedValue.value\n ? inferDiscriminatorMappingComposition(\n optimizedValue.value,\n props.options.document,\n )\n : null,\n)\n\n/** Determine if object properties should be displayed */\nconst shouldRenderObjectProperties = computed(() => {\n const value = optimizedValue.value\n if (!value) {\n return false\n }\n\n if (!('properties' in value || 'additionalProperties' in value)) {\n return false\n }\n\n // `allOf` already merges the factored-out sibling `properties` into its\n // rendered result (see `mergeAllOfSchemas`), so rendering a separate object\n // block here would show those properties twice. Let the composition handle it.\n if ('allOf' in value) {\n return false\n }\n\n // A *plain* bare `discriminator.mapping` base (no explicit `oneOf`/`anyOf` and\n // no `allOf` of its own) is rendered as an inferred `oneOf` composition below,\n // whose variants `allOf` back to this base type and therefore already include\n // its properties (including the discriminator property). Rendering the base\n // object block here as well would show those properties a second time, outside\n // the selector. `Schema.vue` renders the two mutually exclusively; mirror that\n // here so the property and the model render the base identically.\n // See https://github.com/scalar/scalar/issues/9861\n //\n // This intentionally shows the base only through its variants, matching the\n // discriminator contract that each mapped variant extends the base. A malformed\n // mapping whose variants do not include the base (or a base carrying only\n // `additionalProperties`/`patternProperties`) would surface those fields solely\n // via the variants — the same behavior `Schema.vue` already has for the model.\n //\n // A base that composes itself via `allOf` is excluded: `optimizeValueForDisplay`\n // flattens its members up into `properties`, and those contribute fields the\n // inferred variants do not carry, so the block must still render them. The check\n // reads the raw `props.schema` because the flattening has already erased `allOf`\n // from the optimized `value`.\n const composesWithAllOf =\n !!props.schema &&\n typeof props.schema === 'object' &&\n 'allOf' in props.schema\n if (!composesWithAllOf && inferredDiscriminatorComposition.value) {\n return false\n }\n\n // A schema may factor its common `properties` out to the top level alongside\n // a composition keyword (anyOf/oneOf/not), as described in the JSON Schema\n // \"factoring schemas\" guide. `isTypeObject` deliberately rejects such schemas\n // so the composition is rendered, but the factored-out properties must still\n // show. Unlike `allOf`, these compositions do not merge sibling properties.\n // Render them unless the schema is an explicit non-object (scalar or array)\n // type. See https://github.com/scalar/scalar/issues/8593\n const type = 'type' in value ? value.type : undefined\n const isExplicitNonObject = typeof type === 'string' && type !== 'object'\n\n return isTypeObject(value) || !isExplicitNonObject\n})\n\n/** Determine if array of objects should be rendered */\nconst shouldRenderArrayOfObjects = computed(() => {\n const value = optimizedValue.value\n if (!value || !isArraySchema(value) || value.items === undefined) {\n return false\n }\n\n return hasComplexArrayItemsComputed.value\n})\n\n/** Extract enum values from schema or array items */\nconst enumValues = computed(() => getEnumValues(optimizedValue.value))\n\n/** Generate property description from type/format */\nconst propertyDescription = computed(() =>\n getPropertyDescription(optimizedValue.value),\n)\n\n/** Determine if description should be displayed */\nconst displayDescription = computed(() =>\n shouldDisplayDescription(optimizedValue.value, props.description),\n)\n\n/**\n * The schema used to render the object's own properties.\n *\n * Composition keywords are stripped so the nested object renders only its\n * properties. The compositions are rendered separately below; leaving them here\n * would route the nested `Schema` back through `SchemaProperty` and recurse.\n *\n * The `discriminator` is stripped too: its variant selector is part of the\n * composition rendered below (including the one inferred from a bare\n * `discriminator.mapping`), so keeping it here would make the nested `Schema`\n * infer and render a second, identical selector.\n *\n * When the property already renders the description, we also drop it to avoid\n * repeating it in the nested object schema card.\n */\nconst objectSchemaForChildren = computed(() => {\n const value = optimizedValue.value\n if (!value) {\n return value\n }\n\n const {\n oneOf: _oneOf,\n anyOf: _anyOf,\n allOf: _allOf,\n not: _not,\n discriminator: _discriminator,\n ...objectSchema\n } = value\n\n if (displayDescription.value && 'description' in objectSchema) {\n const { description: _description, ...schemaWithoutDescription } =\n objectSchema\n return schemaWithoutDescription\n }\n\n return objectSchema\n})\n\n/** Determine if property heading should be displayed */\nconst shouldDisplayHeadingComputed = computed(() =>\n shouldDisplayHeading(optimizedValue.value, props.name, props.required),\n)\n\n/** Computes which compositions should be rendered and with which values */\nconst compositionsToRender = computed(() =>\n isCyclicProperty.value || hasObjectComposition.value\n ? []\n : getCompositionsToRender(\n optimizedValue.value,\n props.options.document,\n inferredDiscriminatorComposition.value,\n ),\n)\n\n/**\n * Whether the schema carries any `x-` key at all.\n *\n * `SpecificationExtension` renders nothing for a schema without extensions, but mounting\n * it still costs a plugin-manager inject, two computeds and a key scan per row, and almost\n * no row has an extension. This cheap scan gates the mount instead: it is a superset of the\n * component's own condition, so a row with an `x-` key still mounts it and any extension a\n * plugin registers still renders. `optimizedValue` is a plain shallow copy, so the loop\n * reads no reactive proxy.\n */\nconst extensionValue = computed(() =>\n props.extensionSource\n ? { ...props.extensionSource, ...optimizedValue.value }\n : optimizedValue.value,\n)\n\nconst hasSpecificationExtensions = computed((): boolean => {\n const value = extensionValue.value\n\n if (!value || typeof value !== 'object') {\n return false\n }\n\n for (const key in value) {\n if (key.startsWith('x-')) {\n return true\n }\n }\n\n return false\n})\nconst getCompositionDiscriminator = (\n composition: CompositionKeyword,\n): DiscriminatorObject | undefined =>\n composition === 'allOf'\n ? (props.schema?.discriminator ?? props.discriminator)\n : props.schema?.discriminator\n\n/**\n * Get resolved array items for rendering (with any `$dynamicRef` bound to the concrete type).\n *\n * When the items are wrapped in a single-item composition (e.g. `items: { allOf: [{ type: 'object', ... }] }`), we\n * flatten that wrapper into its plain form. A composition with a single member is equivalent to that member, so\n * keeping the composition keyword only makes the items render through an extra schema layer, which adds an\n * unnecessary level of nesting and duplicates the item description. See https://github.com/scalar/scalar/issues/5900\n */\nconst resolvedArrayItems = computed(() => {\n const value = arrayValueWithBoundItems.value\n if (!value || !isArraySchema(value) || value.items === undefined) {\n return undefined\n }\n\n const items = resolve.schema(value.items)\n const hasSingleItemComposition = SINGLE_ITEM_COMPOSITIONS.some(\n (keyword) =>\n Array.isArray(items?.[keyword]) && items[keyword]?.length === 1,\n )\n\n return hasSingleItemComposition ? optimizeValueForDisplay(items) : items\n})\n\n/**\n * Cycle key for the array items schema, derived from the raw (unresolved) items\n * so a self-referential array element is detected as a cycle.\n */\nconst arrayItemsCycleKey = computed(() => {\n const value = optimizedValue.value\n if (!value || !isArraySchema(value)) {\n return undefined\n }\n return getCycleKey(value.items)\n})\n\n/**\n * Props for a child `<Schema>`, derived once instead of at every call site.\n *\n * A row's children render in two places — an open panel and a nameless\n * container — and each used to spell out both branches in full: four\n * invocations of thirteen near-identical props. All but one belong to the row\n * rather than the site, so they live here; the sites still pass `depth` (the\n * panel steps it, the container does not).\n */\nconst sharedChildProps = computed(() => ({\n compact: props.compact,\n eventBus: props.eventBus,\n hideModelNames: hideModelNames.value,\n level: props.level + 1,\n name: props.name,\n options: props.options,\n schemaContext: props.schemaContext,\n}))\n\n/** The object branch: this row's own properties, under this row's anchor path. */\nconst objectChildProps = computed(() =>\n shouldRenderObjectProperties.value\n ? {\n ...sharedChildProps.value,\n breadcrumb: childBreadcrumb.value,\n compositionPath: currentCompositionPath.value,\n cycleKey: props.cycleKey,\n schema: objectSchemaForChildren.value,\n }\n : null,\n)\n\n/**\n * The array branch: the items schema. Deliberately no breadcrumb — items are\n * not a named property, so they extend no anchor path.\n */\nconst arrayChildProps = computed(() =>\n shouldRenderArrayOfObjects.value && resolvedArrayItems.value\n ? {\n ...sharedChildProps.value,\n compositionPath: arrayItemsCompositionPath.value,\n cycleKey: arrayItemsCycleKey.value,\n schema: resolve.schema(resolvedArrayItems.value),\n }\n : null,\n)\n\n/**\n * What a site renders: the branches tried object-first. They are derived\n * separately above because a schema can satisfy both, and the row has to know\n * which one it draws — see `rendersArrayBranch`.\n */\nconst treeChildProps = computed(() => {\n const { cycleKey } = props\n return hasObjectComposition.value\n ? {\n ...sharedChildProps.value,\n breadcrumb: childBreadcrumb.value,\n compositionPath: currentCompositionPath.value,\n cycleKey,\n schema: optimizedValue.value,\n }\n : (objectChildProps.value ?? arrayChildProps.value)\n})\n\n/**\n * Whether a row draws its ARRAY branch, which is the object branch's\n * first-match complement rather than `shouldRenderArrayOfObjects` on its own.\n * The two branches are not exclusive: `isArraySchema` accepts a type LIST, so\n * a schema typed `['array', 'object']` carrying both `items` and `properties`\n * satisfies both, and `treeChildProps` renders the object one. Everything a\n * row says about its children — the cycle key, the count, the preview — has to\n * describe the branch the panel actually draws.\n */\nconst rendersArrayBranch = computed(\n (): boolean => !objectChildProps.value && !!arrayChildProps.value,\n)\n\n/** Check if discriminator matches current property */\nconst isDiscriminatorProperty = computed(() =>\n Boolean(props.name && props.discriminator?.propertyName === props.name),\n)\n\n// ---------------------------------------------------------------------------\n// The disclosure belongs to the property row itself — a gutter control on\n// this <li>, a rail down its children, and the child Schema rendered flat\n// (noncollapsible) inside the panel.\n// ---------------------------------------------------------------------------\n\n/*\n * THE INDENTATION MODEL. Read this before touching any offset.\n *\n * A row NEVER indents itself: it is a single-column grid, so its text starts\n * where its container puts it. Indentation is created in ONE place —\n * SchemaRailPanel (.property-children) pads its children by one gutter.\n * Floating controls hang in the margin at fixed offsets (the 24px toggle at\n * -28px, an 18px puck at -25px), both centred 16px left of the text: the\n * parent's rail line inside a panel, the open margin at the root. Never\n * reserve a gutter column per row and cancel it elsewhere; each cancellation\n * is one refactor away from re-indenting the first level.\n *\n * Every layout style is a utility in the template. The semantic classes\n * (`property--tree`, `property-children`, ...) stay as hooks for consumers.\n */\n\nconst { translate } = useLocalization()\n\nconst hideModelNames = computed(\n (): boolean => props.hideModelNames || !!props.options.hideModelNames,\n)\n\n/** Whether this property has children to put behind a toggle. */\nconst isExpandable = computed(\n (): boolean =>\n hasObjectComposition.value ||\n shouldRenderObjectProperties.value ||\n shouldRenderArrayOfObjects.value,\n)\n\n/**\n * Whether this property loops back onto an ancestor schema. A cycle renders\n * as a leaf row whose signature line says `recursive`.\n */\nconst ancestors = inject(SCHEMA_ANCESTORS_SYMBOL, undefined)\n\nconst treeCycleKey = computed(() =>\n rendersArrayBranch.value ? arrayItemsCycleKey.value : props.cycleKey,\n)\n\nconst isCyclicProperty = computed(\n (): boolean =>\n treeCycleKey.value != null && !!ancestors?.has(treeCycleKey.value),\n)\n\n/**\n * The schema the cycle returns to, which is what the row names. The cycle key\n * for a `$ref` node is the ref string, so the model name falls out of it;\n * naming this row instead would describe the wrong end of the loop.\n */\nconst cycleTargetName = computed((): string => {\n const key = treeCycleKey.value\n\n if (typeof key === 'string') {\n const refName = getRefName(key)\n\n if (refName) {\n return refName\n }\n }\n\n return props.modelName || props.name || translate('schema.schema')\n})\n\nconst expansion =\n props.expansion ?? useSchemaExpansion(toRef(() => props.scrollTargetId ?? ''))\n\n/** See Schema.vue — surfaces without breadcrumbs keep per-instance state. */\nconst anonymousTreeKey = useId()\n\n/**\n * This row's identity in the expansion store: deliberately the plain anchor\n * path, identical to the string the row's own anchor uses, so `commitPath`\n * can open it for a deep link. A structural marker would not be a prefix of\n * any anchor, and bridging that gap (an alias registry, an anchorPath hint)\n * expanded unrelated siblings and clobbered the reader's explicit collapse.\n */\nconst treeNodeKey = computed(\n (): string =>\n toNodeKey(childBreadcrumb.value) || `~anonymous-${anonymousTreeKey}`,\n)\n\n/**\n * Whether this property renders as a collapsible tree row. A nameless container\n * has no heading to hang a control on, so it renders its children directly.\n */\nconst isTreeRow = computed(\n (): boolean =>\n isExpandable.value &&\n !props.noncollapsible &&\n shouldDisplayHeadingComputed.value &&\n !isCyclicProperty.value,\n)\n\n/** Named, always-open rows still own an indented child panel, without a toggle. */\nconst isStaticTreeRow = computed(\n (): boolean =>\n isExpandable.value &&\n !!props.noncollapsible &&\n !!props.name &&\n shouldDisplayHeadingComputed.value &&\n !isCyclicProperty.value,\n)\n\nconst isTreeOpen = computed(\n (): boolean =>\n isTreeRow.value &&\n expansion.isExpanded(treeNodeKey.value, {\n cyclic: isCyclicProperty.value,\n defaultOpen: !!props.options.expandAllSchemaProperties,\n }),\n)\n\n/**\n * Mount policy, three states. Never opened: not rendered, which is the render\n * guard that stops a `$ref` cycle from recursing. Open: rendered. Opened then\n * closed: kept under `hidden=\"until-found\"` so find-in-page can reach it,\n * against a budget the whole reference shares, so hundreds of closed rows across\n * every tree on the page do not pile up as hidden DOM.\n * Past the cap, and in Safari where `until-found` is inert, closed panels unmount.\n */\nconst keepClosedPanelMounted = ref(false)\n\nwatch(isTreeOpen, (open, wasOpen) => {\n if (open) {\n if (keepClosedPanelMounted.value) {\n expansion.untilFound.release()\n keepClosedPanelMounted.value = false\n }\n return\n }\n\n if (wasOpen) {\n keepClosedPanelMounted.value =\n supportsUntilFound() && expansion.untilFound.acquire()\n }\n})\n\n/*\n * A row can leave the tree while still holding a slot (a composition picker\n * remounts its subtree on every variant change), and a leaked slot drains the\n * shared budget until find-in-page retention fails silently page-wide.\n */\nonScopeDispose(() => {\n if (keepClosedPanelMounted.value) {\n expansion.untilFound.release()\n keepClosedPanelMounted.value = false\n }\n})\n\n/** `hidden=\"until-found\"` support — Safari is the lone engine without it. */\nconst supportsUntilFound = (): boolean =>\n typeof document !== 'undefined' && 'onbeforematch' in document.body\n\nconst isTreePanelRendered = computed(\n (): boolean =>\n isStaticTreeRow.value ||\n (isTreeRow.value && (isTreeOpen.value || keepClosedPanelMounted.value)),\n)\n\nconst treePanelHidden = computed(() =>\n isStaticTreeRow.value || isTreeOpen.value ? undefined : 'until-found',\n)\n\n/** Nameless containers add no nesting level of their own. */\nconst rendersFlatChildren = computed(\n (): boolean =>\n isExpandable.value &&\n !isCyclicProperty.value &&\n !isTreeRow.value &&\n !isStaticTreeRow.value,\n)\n\nconst treePanelId = useId()\nconst treeNameId = useId()\nconst treeCountId = useId()\n\n/** The rail panel is a component, so the DOM node is reached through `$el`. */\nconst treePanelRef = useTemplateRef<{ $el: HTMLElement }>('treePanel')\nconst treeToggleRef = useTemplateRef<{ $el: HTMLElement } | HTMLElement>(\n 'treeToggle',\n)\n\n/**\n * Hovering the heading lights this row's puck, because the heading toggles the\n * row on click too. The state is a `data-heading-hovered` attribute on the row,\n * written by pointer events, rather than the former\n * `.property--tree:has(> .property-heading:hover)` selector: a `:has()` anchor\n * on every expandable row made each element inserted under it restyle the\n * whole open subtree. The attribute exists only while hovering and says exactly\n * what `:hover` said (see tailwind.config.css). Bound on tree rows only, so\n * leaf rows carry no listener and their DOM is untouched.\n */\nlet headingHoveredRow: HTMLElement | null = null\n\nconst clearHeadingHover = (): void => {\n headingHoveredRow?.removeAttribute('data-heading-hovered')\n headingHoveredRow = null\n}\n\nconst treeHeadingHoverListeners = {\n pointerenter: (event: Event): void => {\n clearHeadingHover()\n\n const row =\n event.currentTarget instanceof HTMLElement\n ? event.currentTarget.parentElement\n : null\n\n if (!row) {\n return\n }\n\n row.setAttribute('data-heading-hovered', '')\n headingHoveredRow = row\n },\n pointerleave: clearHeadingHover,\n}\n\n/*\n * The listeners come off without a pointerleave whenever the row stops being a\n * tree row under the pointer (a composition picker swaps the schema, so the\n * heading or the disclosure goes), and the marked row is this component's own\n * element, which outlives that change. Clear on both, or the puck stays lit.\n */\nwatch(isTreeRow, (treeRow) => {\n if (!treeRow) {\n clearHeadingHover()\n }\n})\n\nonBeforeUnmount(clearHeadingHover)\n\n/*\n * A close that did not come from the rail strip (the toggle, or the keyboard)\n * can leave the pointer resting on the strip, which then hides without a\n * pointerleave: drop the marks the strip wrote (see SchemaRailPanel.vue), or\n * the puck stays lit. Pre-flush, so the panel is still in the DOM here.\n */\nwatch(isTreeOpen, (open) => {\n if (open) {\n return\n }\n\n const panel = treePanelRef.value?.$el\n panel?.removeAttribute('data-rail-hovered')\n panel?.parentElement?.removeAttribute('data-child-rail-hovered')\n})\n\n/**\n * The schema the panel hands to its child `Schema`, so the count and the\n * preview describe the rows that render. Object-first, like `treeChildProps`.\n */\nconst treeChildSchema = computed(() =>\n rendersArrayBranch.value\n ? resolvedArrayItems.value\n : objectSchemaForChildren.value,\n)\n\n/**\n * The filtered, ordered child property names for the collapsed preview, and\n * for the count only when a hide flag filters the list. `sortPropertyNames`\n * (sort plus `$ref` resolution of every child) is the hottest per-row cost, so\n * nothing reads this while the row is open. Same call the panel makes — full\n * options, no discriminator — or the preview names the wrong first rows and\n * the count disagrees with the panel.\n */\nconst sortedChildPropertyNames = computed((): readonly string[] =>\n treeChildSchema.value\n ? sortPropertyNames(treeChildSchema.value, undefined, props.options)\n : [],\n)\n\n/**\n * The child count that rides the toggle's `aria-describedby`. A description\n * rather than part of the name, so screen-reader verbosity settings apply.\n */\nconst treeChildCountLabel = computed((): string | null => {\n if (!isExpandable.value) {\n return null\n }\n\n // Count the rows the panel will actually render: hideReadOnly / hideWriteOnly\n // filter the list, so raw keys would announce children that do not exist.\n const source = treeChildSchema.value\n if (!source) {\n return null\n }\n\n // Three groups, not one: properties, patternProperties and additionalProperties,\n // or a map-only schema announces no children at all.\n //\n // The count needs only a length. Without a hide flag the panel renders every\n // key, so counting them mirrors the sort's own early return and spares an\n // open row the sort entirely (the preview, its only other reader, exists\n // while collapsed). A hide flag drops rows, so only then is the filtered\n // length genuinely needed.\n const named =\n props.options.hideReadOnly || props.options.hideWriteOnly\n ? sortedChildPropertyNames.value.length\n : isTypeObject(source) && source.properties\n ? Object.keys(source.properties).length\n : 0\n const patterns =\n 'patternProperties' in source && source.patternProperties\n ? Object.keys(source.patternProperties).length\n : 0\n const additional =\n 'additionalProperties' in source && source.additionalProperties ? 1 : 0\n const count = named + patterns + additional\n\n if (count === 0) {\n return null\n }\n\n return translate('schema.propertyCount', { count: String(count) })\n})\n\n/**\n * Whether the type signature will render this row's enum values inline, which\n * is the only case where suppressing the separate value list is safe.\n */\nconst signatureInlinesEnum = computed((): boolean =>\n typeSignatureInlinesEnum(optimizedValue.value, {\n hideModelNames: hideModelNames.value,\n }),\n)\n\n/**\n * The toggle's accessible name when the row has no visible property name (an\n * array-of-objects root, say), so it is never announced as an unnamed button.\n */\nconst treeFallbackLabel = computed(\n (): string => props.modelName || translate('schema.schema'),\n)\n\nconst toggleTree = (): void => {\n const next = !isTreeOpen.value\n\n // Collapsing a subtree that holds focus moves focus up to this row's control\n // instead of dropping it to <body> as the panel hides.\n if (!next) {\n const active = document.activeElement\n const toggleElement =\n treeToggleRef.value instanceof HTMLElement\n ? treeToggleRef.value\n : treeToggleRef.value?.$el\n\n if (active && treePanelRef.value?.$el.contains(active)) {\n toggleElement?.focus()\n }\n }\n\n expansion.setExpanded(treeNodeKey.value, next)\n}\n\n/**\n * The whole heading is a pointer convenience for the disclosure; the gutter\n * toggle stays the accessible control. Interactive children keep their own\n * clicks, and a click that ends a text selection selects rather than toggles,\n * so property names stay copyable.\n */\nconst onHeadingClick = (event: MouseEvent): void => {\n if (!isTreeRow.value) {\n return\n }\n\n const target = event.target\n\n if (\n target instanceof Element &&\n target.closest('a, button, [role=\"button\"], input, select, label')\n ) {\n return\n }\n\n if (window.getSelection()?.toString()) {\n return\n }\n\n toggleTree()\n}\n\n/** Reopen a panel the browser revealed through find-in-page. */\nconst onBeforeMatch = (): void => {\n expansion.setExpanded(treeNodeKey.value, true)\n}\n</script>\n<template>\n <component\n :is=\"is ?? 'li'\"\n class=\"property\"\n :class=\"[\n `property--level-${level}`,\n {\n 'property--compact': compact,\n 'property--deprecated': optimizedValue?.deprecated,\n },\n /*\n * A single-column grid that never indents itself (see the indentation\n * model in the script). The tree spaces rows from --schema-row-pad and\n * separates them by rail, so the base padding and row border go.\n */\n 'property--tree grid! grid-cols-[minmax(0,1fr)] border-b-0! px-0! py-[var(--schema-row-pad,6px)]!',\n {\n 'property--tree-container':\n !isTreeRow &&\n !isCyclicProperty &&\n (isExpandable || !shouldDisplayHeadingComputed),\n },\n `property--depth-${depth}`,\n ]\">\n <!-- The disclosure control in this row's own gutter. See SchemaGutterToggle\n for the accessible-name wiring. -->\n <!-- Absolutely positioned so the hit box never sizes the heading row, and\n z-1 beats the rail strip so the puck wins the pointer.\n\n Vertically: the toggle is a grid item of row 1, so `top` is measured\n from the heading's own grid area. 10px is half the heading's 20px\n first-line slot, and the -50% translate centres a control of ANY size\n on it — a fixed offset silently rides 2px high the moment the narrow\n container shrinks the control. Anchored to the first line, not the\n area's middle, so a wrapped name keeps its toggle beside line one. -->\n <SchemaGutterToggle\n v-if=\"isTreeRow\"\n ref=\"treeToggle\"\n class=\"absolute start-[calc(0px_-_var(--schema-toggle-half,12px)_-_var(--schema-gutter,16px))] top-2.5 z-[1] col-start-1 row-start-1 -translate-y-1/2 print:hidden\"\n :countId=\"treeChildCountLabel ? treeCountId : undefined\"\n :fallbackLabel=\"treeFallbackLabel\"\n :nameId=\"name ? treeNameId : undefined\"\n :open=\"isTreeOpen\"\n :panelId=\"treePanelId\"\n :panelRendered=\"isTreePanelRendered\"\n @toggle=\"toggleTree\" />\n <!-- `row-start-1` shares the toggle's row. Whatever precedes the trailing\n hash drops its own right margin, so the hash sits the same distance\n after the text whether or not the row shows a preview (the preview\n carries no margin of its own — see below). -->\n <SchemaPropertyHeading\n v-if=\"shouldDisplayHeadingComputed\"\n class=\"group\"\n :class=\"[\n { 'cursor-pointer': isTreeRow },\n 'relative row-start-1 min-h-5 content-center [&>*:has(+.copy-link-trailing)]:me-0!',\n ]\"\n :enum=\"hasEnum\"\n :eventBus=\"eventBus\"\n :hideModelNames\n :isDiscriminator=\"isDiscriminatorProperty\"\n :keyKind=\"\n variant === 'additionalProperties'\n ? 'additional'\n : variant === 'patternProperties'\n ? 'pattern'\n : undefined\n \"\n :modelLinkOptions=\"{\n hideModels: options.hideModels,\n document: options.document,\n }\"\n :modelName=\"modelName\"\n :propertyNames=\"propertyNamesSchema\"\n :recursiveTo=\"isCyclicProperty ? cycleTargetName : undefined\"\n :required\n :value=\"optimizedValue\"\n v-on=\"isTreeRow ? treeHeadingHoverListeners : NO_LISTENERS\"\n @click=\"onHeadingClick\">\n <template\n v-if=\"name\"\n #name>\n <WithBreadcrumb\n v-if=\"hasBreadcrumbLink\"\n :breadcrumb=\"childBreadcrumb\">\n <!-- The ONLY node the gutter toggle's aria-labelledby points at.\n A plain inline span, never `display: contents`: the name is what\n a pointer aims at and what a test measures, and a box-less\n wrapper is unhoverable and reports no bounding box. -->\n <span :id=\"treeNameId\">\n <!-- The map-key keyword lives in the signature line (see\n SchemaPropertyHeading), so the chip chrome on the name —\n dashed box, accent colour, the `regex` badge — is switched\n off here and the name reads like any other. The class names\n stay as styling hooks. -->\n <span\n v-if=\"variant === 'patternProperties'\"\n class=\"property-name-pattern-properties text-c-1! border-0! p-0! before:hidden!\">\n <ScalarWrappingText\n preset=\"property\"\n :text=\"name\" />\n </span>\n <span\n v-else-if=\"variant === 'additionalProperties'\"\n class=\"property-name-additional-properties text-c-1! border-0! p-0! before:hidden!\">\n <ScalarWrappingText\n preset=\"property\"\n :text=\"name\" />\n </span>\n <ScalarWrappingText\n v-else\n preset=\"property\"\n :text=\"name\" />\n </span>\n </WithBreadcrumb>\n <template v-else>\n <!-- The ONLY node the gutter toggle's aria-labelledby points at.\n A plain inline span, never `display: contents`: the name is what\n a pointer aims at and what a test measures, and a box-less\n wrapper is unhoverable and reports no bounding box. -->\n <span :id=\"treeNameId\">\n <!-- The map-key keyword lives in the signature line (see\n SchemaPropertyHeading), so the chip chrome on the name —\n dashed box, accent colour, the `regex` badge — is switched\n off here and the name reads like any other. The class names\n stay as styling hooks. -->\n <span\n v-if=\"variant === 'patternProperties'\"\n class=\"property-name-pattern-properties text-c-1! border-0! p-0! before:hidden!\">\n <ScalarWrappingText\n preset=\"property\"\n :text=\"name\" />\n </span>\n <span\n v-else-if=\"variant === 'additionalProperties'\"\n class=\"property-name-additional-properties text-c-1! border-0! p-0! before:hidden!\">\n <ScalarWrappingText\n preset=\"property\"\n :text=\"name\" />\n </span>\n <ScalarWrappingText\n v-else\n preset=\"property\"\n :text=\"name\" />\n </span>\n </template>\n </template>\n <template\n v-if=\"optimizedValue?.example !== undefined\"\n #example>\n Example:\n {{ optimizedValue.example }}\n </template>\n <template\n v-if=\"isTreeRow && !isTreeOpen\"\n #preview>\n <!-- Purely visual: the child count already rides aria-describedby -->\n <!-- A zero-basis flex item must have a zero outer size, or the heading's\n 9px child margin wraps it onto its own line -->\n <SchemaCollapsedPreview\n aria-hidden=\"true\"\n class=\"mr-0!\"\n :propertyNames=\"sortedChildPropertyNames\"\n :schema=\"treeChildSchema as SchemaObject\" />\n </template>\n <template\n v-if=\"name && shouldHaveLink && childBreadcrumb\"\n #trailing>\n <CopyLinkButton\n :anchorId=\"childBreadcrumb.join('.')\"\n :eventBus=\"eventBus\" />\n </template>\n </SchemaPropertyHeading>\n\n <!-- Description -->\n <!-- The heading's 20px slot already leaves slack under the name, so 4px is\n enough under it; 6px above a composition keeps the row on the 12px\n rhythm. -->\n <div\n v-if=\"displayDescription || propertyDescription\"\n class=\"property-description mt-1! has-[+.property-rule]:mb-1.5!\">\n <ScalarMarkdown\n :value=\"displayDescription || propertyDescription || ''\" />\n </div>\n\n <!-- Enum for property names, on any additionalProperties/patternProperties\n schema whose propertyNames carry an enum. -->\n <SchemaEnums\n v-if=\"propertyNamesEnum && propertyNamesEnum.length > 0\"\n propertyNames\n :value=\"{ enum: propertyNamesEnum } as SchemaObject\" />\n\n <!-- Enum values -->\n <!-- The array items card rendered below already lists these same values. -->\n <!-- Skip the list when the signature already inlines the enum, but only\n when it genuinely does (never for a $ref or an untyped schema), or the\n values would be shown nowhere at all. -->\n <SchemaEnums\n v-if=\"\n enumValues.length > 0 &&\n !shouldRenderArrayOfObjects &&\n !signatureInlinesEnum\n \"\n :value=\"optimizedValue\" />\n\n <!-- The child count description and the rail panel -->\n <span\n v-if=\"isTreeRow && treeChildCountLabel\"\n :id=\"treeCountId\"\n class=\"screenreader-only\"\n >{{ treeChildCountLabel }}</span\n >\n\n <!-- closeOnRail: a pointer-only convenience like an editor's indent\n guide; the gutter toggle stays the accessible control. -->\n <!-- Nothing inside a panel may add trailing height below the last row,\n so the descendant resets reach into the child Schema cards. -->\n <SchemaRailPanel\n v-if=\"isTreePanelRendered\"\n :id=\"treePanelId\"\n ref=\"treePanel\"\n class=\"property-children mt-1.5 mb-0.5 [&_.schema-card]:mb-0! [&_.schema-card]:pb-0! [&_.schema-properties]:mb-0! [&_.schema-properties]:pb-0! [&_ul]:my-0! [&_ul]:py-0! [&[hidden=until-found]]:my-0 [&[hidden=until-found]]:border-s-0 [&[hidden]:not([hidden=until-found])]:hidden\"\n :closeOnRail=\"isTreeRow\"\n :depth=\"depth + 1\"\n :hidden=\"treePanelHidden\"\n @beforematch=\"onBeforeMatch\"\n @close=\"toggleTree\">\n <!-- The panel is one level deeper than the row it belongs to -->\n <Schema\n v-if=\"treeChildProps\"\n v-bind=\"treeChildProps\"\n :depth=\"depth + 1\"\n :expansion=\"expansion\"\n noncollapsible\n :scrollTargetId=\"scrollTargetId\"\n :specificationExtension=\"specificationExtension\" />\n </SchemaRailPanel>\n\n <!-- A container renders its children directly with no depth step. Not a\n v-else of the panel: a collapsed tree row must not fall through here.\n 6px under a description keeps the 12px rhythm. -->\n <div\n v-if=\"rendersFlatChildren\"\n class=\"children [.property-description+&]:mt-1.5!\">\n <!-- A container adds no rail, so its children keep this row's depth -->\n <Schema\n v-if=\"treeChildProps\"\n v-bind=\"treeChildProps\"\n :depth=\"depth\"\n :expansion=\"expansion\"\n noncollapsible\n :scrollTargetId=\"scrollTargetId\"\n :specificationExtension=\"specificationExtension\" />\n </div>\n\n <!-- Compositions -->\n <!-- This row's own breadcrumb, so sibling compositions do not collide on\n anchors and expansion keys. -->\n <!-- Fall back to the inherited discriminator to label the property inside an allOf variant (#9674) -->\n <SchemaComposition\n v-for=\"compositionData in compositionsToRender\"\n :key=\"compositionData.composition\"\n :breadcrumb=\"childBreadcrumb\"\n :compact=\"compact\"\n :composition=\"compositionData.composition\"\n :compositionPath=\"currentCompositionPath\"\n :depth=\"depth\"\n :discriminator=\"getCompositionDiscriminator(compositionData.composition)\"\n :eventBus=\"eventBus\"\n :expansion=\"expansion\"\n :hideHeading=\"hideHeading\"\n :hideModelNames\n :level=\"level\"\n :name=\"name\"\n :noncollapsible=\"noncollapsible\"\n :options=\"options\"\n :schema=\"compositionData.value\"\n :schemaContext=\"schemaContext\"\n :scrollTargetId=\"scrollTargetId\"\n :specificationExtension=\"specificationExtension\" />\n <component\n :is=\"specificationExtension\"\n v-if=\"hasSpecificationExtensions && specificationExtension\"\n :showExtensions=\"options.showExtensions\"\n :value=\"extensionValue\" />\n </component>\n</template>\n\n<style scoped>\n.property {\n color: var(--scalar-color-1);\n display: flex;\n flex-direction: column;\n padding: 10px;\n font-size: var(--scalar-small);\n position: relative;\n}\n\n/* if a property doesn't have a heading, remove the top padding */\n.property:has(> .property-rule:nth-of-type(1)):not(.property--compact) {\n padding-top: 8px;\n padding-bottom: 8px;\n}\n\n.property--deprecated {\n background: repeating-linear-gradient(\n -45deg,\n var(--scalar-background-2) 0,\n var(--scalar-background-2) 2px,\n transparent 2px,\n transparent 5px\n );\n background-size: 100%;\n}\n\n/*\n * A deprecated row keeps its text at full strength rather than fading it. Fading blended\n * the muted text into the card, leaving it at 3.0:1 where WCAG 1.4.3 asks 4.5:1 of body\n * text, and the row already says \"deprecated\" three other ways: the stripes above, the\n * strikethrough on the property name (see SchemaPropertyHeading) and the Deprecated badge\n * beside it. The fade was the one signal carrying no information and the only one costing\n * contrast, so do not reintroduce it.\n */\n\n.property-description {\n margin-top: 6px;\n line-height: 1.4;\n font-size: var(--scalar-small);\n}\n\n.property-description:has(+ .property-rule) {\n margin-bottom: 9px;\n}\n\n:deep(.property-description) * {\n color: var(--scalar-color-2) !important;\n}\n\n.property:not(:last-of-type) {\n border-bottom: var(--scalar-border-width) solid var(--scalar-border-color);\n}\n\n.property-description + .children,\n.children + .property-rule {\n margin-top: 9px;\n}\n\n.children {\n display: flex;\n flex-direction: column;\n}\n\n.children .property--compact.property--level-1 {\n padding: 12px;\n}\n\n.property-example-value {\n all: unset;\n font-family: var(--scalar-font-code);\n padding: 6px;\n border-top: var(--scalar-border-width) solid var(--scalar-border-color);\n}\n\n.property-rule {\n border-radius: var(--scalar-radius-lg);\n display: flex;\n flex-direction: column;\n}\n\n.property-example {\n background: transparent;\n border: none;\n display: flex;\n flex-direction: row;\n gap: 8px;\n}\n\n.property-example-label,\n.property-example-value {\n padding: 3px 0 0 0;\n}\n\n.property-example-value {\n background: var(--scalar-background-2);\n border-top: 0;\n border-radius: var(--scalar-radius);\n padding: 3px 4px;\n}\n\n.property-name {\n font-family: var(--scalar-font-code);\n font-weight: var(--scalar-semibold);\n}\n\n.property-name-additional-properties::before,\n.property-name-pattern-properties::before {\n text-transform: uppercase;\n font-size: var(--scalar-micro);\n display: inline-block;\n padding: 2px 4px;\n border-radius: var(--scalar-radius);\n color: var(--scalar-color-1);\n border: var(--scalar-border-width) solid var(--scalar-border-color);\n background-color: var(--scalar-background-2);\n margin-right: 4px;\n}\n\n.property-name-pattern-properties::before {\n content: 'regex';\n}\n\n.property-name-additional-properties,\n.property-name-pattern-properties {\n border: 1px dashed var(--scalar-border-color);\n color: var(--scalar-color-accent);\n display: inline-block;\n padding: 2px;\n border-radius: var(--scalar-radius);\n}\n</style>\n"],"mappings":"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"}
1
+ {"version":3,"file":"SchemaProperty.vue.script.js","names":[],"sources":["../../src/schema/SchemaProperty.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * The `v-on` binding a row without a disclosure gets. Module scope, and frozen\n * so it cannot be written through: an inline `{}` in the template is a fresh\n * object on every render of every row, and this component renders once per\n * property on the page.\n */\nconst NO_LISTENERS = Object.freeze({})\n</script>\n\n<script lang=\"ts\" setup>\nimport { ScalarMarkdown } from '@scalar/components/markdown'\nimport { ScalarWrappingText } from '@scalar/components/wrapping-text'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport {\n isDynamicRef,\n resolveDynamicRef,\n} from '@scalar/workspace-store/helpers/dynamic-ref'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type {\n DiscriminatorObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { isArraySchema } from '@scalar/workspace-store/schemas/v3.2/strict/type-guards'\nimport {\n computed,\n inject,\n onBeforeUnmount,\n onScopeDispose,\n ref,\n toRef,\n useId,\n useTemplateRef,\n watch,\n type Component,\n} from 'vue'\n\nimport ExternalDocs from '../shared/ExternalDocs.vue'\nimport CopyLinkButton from './components/CopyLinkButton.vue'\nimport WithBreadcrumb from './components/WithBreadcrumb.vue'\nimport {\n schemaDiscriminator,\n type DiscriminatorMetadata,\n} from './discriminator-metadata'\nimport { resolveDynamicSchema, useDynamicScope } from './helpers/dynamic-scope'\nimport {\n getCompositionsToRender,\n inferDiscriminatorMappingComposition,\n} from './helpers/get-compositions-to-render'\nimport { getEnumValues } from './helpers/get-enum-values'\nimport { getPropertyDescriptionKey } from './helpers/get-property-description'\nimport { getRefName } from './helpers/get-ref-name'\nimport { typeSignatureInlinesEnum } from './helpers/get-type-signature-tokens'\nimport { hasComplexArrayItems } from './helpers/has-complex-array-items'\nimport { isTypeObject } from './helpers/is-type-object'\nimport { normalizeObjectComposition } from './helpers/normalize-object-composition'\nimport { optimizeValueForDisplay } from './helpers/optimize-value-for-display'\nimport { partitionAllOfCompositions } from './helpers/partition-all-of-compositions'\nimport type { CompositionKeyword } from './helpers/schema-composition'\nimport { getCycleKey, SCHEMA_ANCESTORS_SYMBOL } from './helpers/schema-cycle'\nimport { toNodeKey, useSchemaExpansion } from './helpers/schema-expansion'\nimport { shouldDisplayDescription } from './helpers/should-display-description'\nimport { shouldDisplayHeading } from './helpers/should-display-heading'\nimport { sortPropertyNames } from './helpers/sort-property-names'\nimport { unwrapForRead } from './helpers/unwrap-for-read'\nimport { useLocalization } from './localization'\nimport Schema from './Schema.vue'\nimport SchemaCollapsedPreview from './SchemaCollapsedPreview.vue'\nimport SchemaComposition from './SchemaComposition.vue'\nimport SchemaEnums from './SchemaEnums.vue'\nimport SchemaGutterToggle from './SchemaGutterToggle.vue'\nimport SchemaPropertyHeading from './SchemaPropertyHeading.vue'\nimport SchemaRailPanel from './SchemaRailPanel.vue'\nimport type { SchemaOptions, SchemaRenderingProps } from './types'\n\nconst props = withDefaults(\n defineProps<\n {\n is?: string | Component\n schema: SchemaObject | undefined\n /** Extensions on the containing parameter or header; schema values take precedence. */\n extensionSource?: Record<string, unknown>\n noncollapsible?: boolean\n level?: number\n /**\n * Real nesting depth. Its own counter because `level` advances by a\n * different stride per edge (object +2, composition +1).\n */\n depth?: number\n name?: string\n required?: boolean\n compact?: boolean\n discriminator?: DiscriminatorObject\n description?: string\n hideModelNames?: boolean\n hideHeading?: boolean\n /** When the root schema was resolved from a $ref, pass the ref name for display (e.g. \"Data\"). */\n modelName?: string | null\n variant?: 'additionalProperties' | 'patternProperties'\n breadcrumb?: string[]\n eventBus: WorkspaceEventBus | null\n options: SchemaOptions\n /** Enum values for property names (from JSON Schema propertyNames keyword). */\n propertyNamesEnum?: string[]\n /** Resolved propertyNames schema, used to show key constraints like `format`. */\n propertyNamesSchema?: SchemaObject\n /** When \"requestBody\", composition selection is synced with the example snippet */\n schemaContext?: string\n /** Internal path used to sync nested request body compositions with the code sample */\n compositionPath?: string[]\n /** Internal path segment for this property when building nested composition keys */\n compositionPathSegment?: string\n /** Stable identity of this property's schema, used for cycle detection. */\n cycleKey?: unknown\n } & SchemaRenderingProps\n >(),\n {\n level: 0,\n depth: 0,\n required: false,\n compact: false,\n hideModelNames: false,\n },\n)\n\n/**\n * Note: We're taking in a prop called `value` which should be a JSON Schema.\n *\n * We're using `optimizeValueForDisplay` to merge null types in compositions (anyOf, allOf, oneOf, not).\n * So you should basically use the optimizedValue everywhere in the component.\n */\n\n/** Composition keywords that hold a list of schemas and can be flattened when they contain a single member. */\nconst SINGLE_ITEM_COMPOSITIONS = ['oneOf', 'anyOf', 'allOf'] as const\n\n/** The dynamic scope inherited from the enclosing schema resources, used to bind `$dynamicRef`s. */\nconst dynamicScope = useDynamicScope()\n\n/**\n * Simplified composition with `null` type.\n *\n * A top-level `$dynamicRef` (e.g. a linked-list `next` node) is bound to its concrete type via the\n * dynamic scope first; for ordinary schemas this is a no-op.\n *\n * The value is unwrapped here as well as at the `Schema` root, because callers such as\n * `ParameterListItem` and `Headers` hand a schema in below a root and would otherwise leave the\n * whole subtree on the reactive and detect-changes proxies. See {@link unwrapForRead}.\n */\nconst optimizedValue = computed(() =>\n normalizeObjectComposition(\n optimizeValueForDisplay(\n resolveDynamicSchema(unwrapForRead(props.schema), dynamicScope),\n ),\n props.name,\n ),\n)\n\n/** Mixed object/choice compositions still belong inside their named property's panel. */\nconst hasObjectComposition = computed((): boolean => {\n const { name } = props\n const value = optimizedValue.value\n return (\n !!name &&\n !!value?.allOf &&\n partitionAllOfCompositions(value).segments.some(\n (segment) => segment.kind === 'object' && isTypeObject(segment.schema),\n )\n )\n})\n\nconst childBreadcrumb = computed<string[] | undefined>(() =>\n props.breadcrumb\n ? // A named property extends the breadcrumb with its own name. A nameless\n // container (e.g. a response object, rendered without a name to avoid a\n // duplicate heading) passes its breadcrumb straight through so its\n // properties stay linkable.\n props.name\n ? [...props.breadcrumb, props.name]\n : props.breadcrumb\n : undefined,\n)\n\nconst currentCompositionPath = computed<string[]>(() =>\n props.compositionPathSegment\n ? [...(props.compositionPath ?? []), props.compositionPathSegment]\n : (props.compositionPath ?? []),\n)\n\nconst arrayItemsCompositionPath = computed<string[]>(() => [\n ...currentCompositionPath.value,\n 'items',\n])\n\nconst shouldHaveLink = computed((): boolean => {\n const target = props.options.linkablePropertyPath\n const path = childBreadcrumb.value\n return (\n props.level <= 2 ||\n Boolean(\n target &&\n path &&\n target.length === path.length &&\n target.every((segment, index) => segment === path[index]),\n )\n )\n})\n\n/**\n * Whether the name gets a deep link (an anchor id and a trailing copy button).\n *\n * Mirrors the condition `WithBreadcrumb` renders its anchor under. Without a link that\n * component only passes its slot through, yet every named row still paid to mount it\n * (a localization inject and an unread label computed), and most rows have no link: any\n * row deeper than level 2, and every row on surfaces that pass no breadcrumb at all\n * (models, the classic layout, AsyncAPI). So the template mounts `WithBreadcrumb` only\n * for linked rows and renders the same name span directly for the rest. Both branches\n * carry an identical copy of the span, comments included: the template comments are\n * DOM nodes in development builds, so the two copies must stay byte-for-byte in step.\n */\nconst hasBreadcrumbLink = computed(\n (): boolean =>\n shouldHaveLink.value && (childBreadcrumb.value?.length ?? 0) > 0,\n)\n\n/**\n * The array schema used for item inspection, with a `$dynamicRef` item bound to its concrete type.\n *\n * Returns the schema unchanged unless `items` is a `$dynamicRef` that resolves against the dynamic\n * scope, so ordinary arrays (including `$ref` items) keep their existing behavior exactly.\n */\nconst arrayValueWithBoundItems = computed(() => {\n const value = optimizedValue.value\n if (!value || !isArraySchema(value) || !isDynamicRef(value.items)) {\n return value\n }\n\n const bound = resolveDynamicRef(value.items.$dynamicRef, dynamicScope)\n return bound ? ({ ...value, items: bound } as SchemaObject) : value\n})\n\n/** Checks if array items have complex structure */\nconst hasComplexArrayItemsComputed = computed(() =>\n hasComplexArrayItems(arrayValueWithBoundItems.value),\n)\n\n/** Check if enum should be displayed (from value schema or from propertyNames) */\nconst hasEnum = computed(() => enumValues.value.length > 0)\n\n/**\n * The `oneOf` inferred from a bare `discriminator.mapping`, or `null` when there\n * is nothing to infer. Computed once and shared: `shouldRenderObjectProperties`\n * uses it to suppress the duplicate base object block, and `compositionsToRender`\n * passes it on so the inference does not run twice per render.\n */\nconst inferredDiscriminatorComposition = computed(() =>\n optimizedValue.value\n ? inferDiscriminatorMappingComposition(\n optimizedValue.value,\n props.options.document,\n )\n : null,\n)\n\n/** Determine if object properties should be displayed */\nconst shouldRenderObjectProperties = computed(() => {\n const value = optimizedValue.value\n if (!value) {\n return false\n }\n\n if (!('properties' in value || 'additionalProperties' in value)) {\n return false\n }\n\n // `allOf` already merges the factored-out sibling `properties` into its\n // rendered result (see `mergeAllOfSchemas`), so rendering a separate object\n // block here would show those properties twice. Let the composition handle it.\n if ('allOf' in value) {\n return false\n }\n\n // A *plain* bare `discriminator.mapping` base (no explicit `oneOf`/`anyOf` and\n // no `allOf` of its own) is rendered as an inferred `oneOf` composition below,\n // whose variants `allOf` back to this base type and therefore already include\n // its properties (including the discriminator property). Rendering the base\n // object block here as well would show those properties a second time, outside\n // the selector. `Schema.vue` renders the two mutually exclusively; mirror that\n // here so the property and the model render the base identically.\n // See https://github.com/scalar/scalar/issues/9861\n //\n // This intentionally shows the base only through its variants, matching the\n // discriminator contract that each mapped variant extends the base. A malformed\n // mapping whose variants do not include the base (or a base carrying only\n // `additionalProperties`/`patternProperties`) would surface those fields solely\n // via the variants — the same behavior `Schema.vue` already has for the model.\n //\n // A base that composes itself via `allOf` is excluded: `optimizeValueForDisplay`\n // flattens its members up into `properties`, and those contribute fields the\n // inferred variants do not carry, so the block must still render them. The check\n // reads the raw `props.schema` because the flattening has already erased `allOf`\n // from the optimized `value`.\n const composesWithAllOf =\n !!props.schema &&\n typeof props.schema === 'object' &&\n 'allOf' in props.schema\n if (!composesWithAllOf && inferredDiscriminatorComposition.value) {\n return false\n }\n\n // A schema may factor its common `properties` out to the top level alongside\n // a composition keyword (anyOf/oneOf/not), as described in the JSON Schema\n // \"factoring schemas\" guide. `isTypeObject` deliberately rejects such schemas\n // so the composition is rendered, but the factored-out properties must still\n // show. Unlike `allOf`, these compositions do not merge sibling properties.\n // Render them unless the schema is an explicit non-object (scalar or array)\n // type. See https://github.com/scalar/scalar/issues/8593\n const type = 'type' in value ? value.type : undefined\n const isExplicitNonObject = typeof type === 'string' && type !== 'object'\n\n return isTypeObject(value) || !isExplicitNonObject\n})\n\n/** Determine if array of objects should be rendered */\nconst shouldRenderArrayOfObjects = computed(() => {\n const value = optimizedValue.value\n if (!value || !isArraySchema(value) || value.items === undefined) {\n return false\n }\n\n return hasComplexArrayItemsComputed.value\n})\n\n/** Extract enum values from schema or array items */\nconst enumValues = computed(() => getEnumValues(optimizedValue.value))\n\n/** Generate property description from type/format */\nconst propertyDescription = computed(() => {\n const key = getPropertyDescriptionKey(optimizedValue.value)\n return key ? translate(key) : null\n})\n\n/** Determine if description should be displayed */\nconst displayDescription = computed(() =>\n shouldDisplayDescription(optimizedValue.value, props.description),\n)\n\n/**\n * The schema used to render the object's own properties.\n *\n * Composition keywords are stripped so the nested object renders only its\n * properties. The compositions are rendered separately below; leaving them here\n * would route the nested `Schema` back through `SchemaProperty` and recurse.\n *\n * The `discriminator` is stripped too: its variant selector is part of the\n * composition rendered below (including the one inferred from a bare\n * `discriminator.mapping`), so keeping it here would make the nested `Schema`\n * infer and render a second, identical selector.\n *\n * When the property already renders the description, we also drop it to avoid\n * repeating it in the nested object schema card.\n */\nconst objectSchemaForChildren = computed(() => {\n const value = optimizedValue.value\n if (!value) {\n return value\n }\n\n const {\n oneOf: _oneOf,\n anyOf: _anyOf,\n allOf: _allOf,\n not: _not,\n discriminator: _discriminator,\n externalDocs: _externalDocs,\n ...objectSchema\n } = value\n\n if (displayDescription.value && 'description' in objectSchema) {\n const { description: _description, ...schemaWithoutDescription } =\n objectSchema\n return schemaWithoutDescription\n }\n\n return objectSchema\n})\n\n/** Determine if property heading should be displayed */\nconst shouldDisplayHeadingComputed = computed(() =>\n shouldDisplayHeading(optimizedValue.value, props.name, props.required),\n)\n\n/** Computes which compositions should be rendered and with which values */\nconst compositionsToRender = computed(() =>\n isCyclicProperty.value || hasObjectComposition.value\n ? []\n : getCompositionsToRender(\n optimizedValue.value,\n props.options.document,\n inferredDiscriminatorComposition.value,\n ),\n)\n\n/**\n * Whether the schema carries any `x-` key at all.\n *\n * `SpecificationExtension` renders nothing for a schema without extensions, but mounting\n * it still costs a plugin-manager inject, two computeds and a key scan per row, and almost\n * no row has an extension. This cheap scan gates the mount instead: it is a superset of the\n * component's own condition, so a row with an `x-` key still mounts it and any extension a\n * plugin registers still renders. `optimizedValue` is a plain shallow copy, so the loop\n * reads no reactive proxy.\n */\nconst extensionValue = computed(() =>\n props.extensionSource\n ? { ...props.extensionSource, ...optimizedValue.value }\n : optimizedValue.value,\n)\n\nconst hasSpecificationExtensions = computed((): boolean => {\n const value = extensionValue.value\n\n if (!value || typeof value !== 'object') {\n return false\n }\n\n for (const key in value) {\n if (key.startsWith('x-')) {\n return true\n }\n }\n\n return false\n})\nconst getCompositionDiscriminator = (\n composition: CompositionKeyword,\n): DiscriminatorObject | undefined =>\n composition === 'allOf'\n ? (props.schema?.discriminator ?? props.discriminator)\n : props.schema?.discriminator\n\n/**\n * Get resolved array items for rendering (with any `$dynamicRef` bound to the concrete type).\n *\n * When the items are wrapped in a single-item composition (e.g. `items: { allOf: [{ type: 'object', ... }] }`), we\n * flatten that wrapper into its plain form. A composition with a single member is equivalent to that member, so\n * keeping the composition keyword only makes the items render through an extra schema layer, which adds an\n * unnecessary level of nesting and duplicates the item description. See https://github.com/scalar/scalar/issues/5900\n */\nconst resolvedArrayItems = computed(() => {\n const value = arrayValueWithBoundItems.value\n if (!value || !isArraySchema(value) || value.items === undefined) {\n return undefined\n }\n\n const items = resolve.schema(value.items)\n const hasSingleItemComposition = SINGLE_ITEM_COMPOSITIONS.some(\n (keyword) =>\n Array.isArray(items?.[keyword]) && items[keyword]?.length === 1,\n )\n\n return hasSingleItemComposition ? optimizeValueForDisplay(items) : items\n})\n\n/**\n * Cycle key for the array items schema, derived from the raw (unresolved) items\n * so a self-referential array element is detected as a cycle.\n */\nconst arrayItemsCycleKey = computed(() => {\n const value = optimizedValue.value\n if (!value || !isArraySchema(value)) {\n return undefined\n }\n return getCycleKey(value.items)\n})\n\n/**\n * Props for a child `<Schema>`, derived once instead of at every call site.\n *\n * A row's children render in two places — an open panel and a nameless\n * container — and each used to spell out both branches in full: four\n * invocations of thirteen near-identical props. All but one belong to the row\n * rather than the site, so they live here; the sites still pass `depth` (the\n * panel steps it, the container does not).\n */\nconst sharedChildProps = computed(() => ({\n compact: props.compact,\n eventBus: props.eventBus,\n hideModelNames: hideModelNames.value,\n level: props.level + 1,\n name: props.name,\n options: props.options,\n schemaContext: props.schemaContext,\n}))\n\n/** The object branch: this row's own properties, under this row's anchor path. */\nconst objectChildProps = computed(() =>\n shouldRenderObjectProperties.value\n ? {\n ...sharedChildProps.value,\n breadcrumb: childBreadcrumb.value,\n compositionPath: currentCompositionPath.value,\n cycleKey: props.cycleKey,\n schema: objectSchemaForChildren.value,\n discriminator:\n optimizedValue.value?.discriminator ?? props.discriminator,\n }\n : null,\n)\n\n/**\n * The array branch: the items schema. Deliberately no breadcrumb — items are\n * not a named property, so they extend no anchor path.\n */\nconst arrayChildProps = computed(() =>\n shouldRenderArrayOfObjects.value && resolvedArrayItems.value\n ? {\n ...sharedChildProps.value,\n compositionPath: arrayItemsCompositionPath.value,\n cycleKey: arrayItemsCycleKey.value,\n schema: resolve.schema(resolvedArrayItems.value),\n }\n : null,\n)\n\n/**\n * What a site renders: the branches tried object-first. They are derived\n * separately above because a schema can satisfy both, and the row has to know\n * which one it draws — see `rendersArrayBranch`.\n */\nconst treeChildProps = computed(() => {\n const { cycleKey } = props\n return hasObjectComposition.value\n ? {\n ...sharedChildProps.value,\n breadcrumb: childBreadcrumb.value,\n compositionPath: currentCompositionPath.value,\n cycleKey,\n schema: optimizedValue.value,\n }\n : (objectChildProps.value ?? arrayChildProps.value)\n})\n\n/**\n * Whether a row draws its ARRAY branch, which is the object branch's\n * first-match complement rather than `shouldRenderArrayOfObjects` on its own.\n * The two branches are not exclusive: `isArraySchema` accepts a type LIST, so\n * a schema typed `['array', 'object']` carrying both `items` and `properties`\n * satisfies both, and `treeChildProps` renders the object one. Everything a\n * row says about its children — the cycle key, the count, the preview — has to\n * describe the branch the panel actually draws.\n */\nconst rendersArrayBranch = computed(\n (): boolean => !objectChildProps.value && !!arrayChildProps.value,\n)\n\n/** A named property receives the selected variant's display value, never a fabricated const. */\nconst discriminatorValue = computed((): string | undefined =>\n props.name === props.discriminator?.propertyName\n ? (props.discriminator as DiscriminatorMetadata)?.[schemaDiscriminator]\n ?.value\n : undefined,\n)\n\n/** Check if discriminator matches current property */\nconst isDiscriminatorProperty = computed(() =>\n Boolean(props.name && props.discriminator?.propertyName === props.name),\n)\n\n// ---------------------------------------------------------------------------\n// The disclosure belongs to the property row itself — a gutter control on\n// this <li>, a rail down its children, and the child Schema rendered flat\n// (noncollapsible) inside the panel.\n// ---------------------------------------------------------------------------\n\n/*\n * THE INDENTATION MODEL. Read this before touching any offset.\n *\n * A row NEVER indents itself: it is a single-column grid, so its text starts\n * where its container puts it. Indentation is created in ONE place —\n * SchemaRailPanel (.property-children) pads its children by one gutter.\n * Floating controls hang in the margin at fixed offsets (the 24px toggle at\n * -28px, an 18px puck at -25px), both centred 16px left of the text: the\n * parent's rail line inside a panel, the open margin at the root. Never\n * reserve a gutter column per row and cancel it elsewhere; each cancellation\n * is one refactor away from re-indenting the first level.\n *\n * Every layout style is a utility in the template. The semantic classes\n * (`property--tree`, `property-children`, ...) stay as hooks for consumers.\n */\n\nconst { translate } = useLocalization()\n\nconst hideModelNames = computed(\n (): boolean => props.hideModelNames || !!props.options.hideModelNames,\n)\n\n/** Whether this property has children to put behind a toggle. */\nconst isExpandable = computed(\n (): boolean =>\n hasObjectComposition.value ||\n shouldRenderObjectProperties.value ||\n shouldRenderArrayOfObjects.value,\n)\n\n/**\n * Whether this property loops back onto an ancestor schema. A cycle renders\n * as a leaf row whose signature line says `recursive`.\n */\nconst ancestors = inject(SCHEMA_ANCESTORS_SYMBOL, undefined)\n\nconst treeCycleKey = computed(() =>\n rendersArrayBranch.value ? arrayItemsCycleKey.value : props.cycleKey,\n)\n\nconst isCyclicProperty = computed(\n (): boolean =>\n treeCycleKey.value != null && !!ancestors?.has(treeCycleKey.value),\n)\n\n/**\n * The schema the cycle returns to, which is what the row names. The cycle key\n * for a `$ref` node is the ref string, so the model name falls out of it;\n * naming this row instead would describe the wrong end of the loop.\n */\nconst cycleTargetName = computed((): string => {\n const key = treeCycleKey.value\n\n if (typeof key === 'string') {\n const refName = getRefName(key)\n\n if (refName) {\n return refName\n }\n }\n\n return props.modelName || props.name || translate('schema.schema')\n})\n\nconst expansion =\n props.expansion ?? useSchemaExpansion(toRef(() => props.scrollTargetId ?? ''))\n\n/** See Schema.vue — surfaces without breadcrumbs keep per-instance state. */\nconst anonymousTreeKey = useId()\n\n/**\n * This row's identity in the expansion store: deliberately the plain anchor\n * path, identical to the string the row's own anchor uses, so `commitPath`\n * can open it for a deep link. A structural marker would not be a prefix of\n * any anchor, and bridging that gap (an alias registry, an anchorPath hint)\n * expanded unrelated siblings and clobbered the reader's explicit collapse.\n */\nconst treeNodeKey = computed(\n (): string =>\n toNodeKey(childBreadcrumb.value) || `~anonymous-${anonymousTreeKey}`,\n)\n\n/**\n * Whether this property renders as a collapsible tree row. A nameless container\n * has no heading to hang a control on, so it renders its children directly.\n */\nconst isTreeRow = computed(\n (): boolean =>\n isExpandable.value &&\n !props.noncollapsible &&\n shouldDisplayHeadingComputed.value &&\n !isCyclicProperty.value,\n)\n\n/** Named, always-open rows still own an indented child panel, without a toggle. */\nconst isStaticTreeRow = computed(\n (): boolean =>\n isExpandable.value &&\n !!props.noncollapsible &&\n !!props.name &&\n shouldDisplayHeadingComputed.value &&\n !isCyclicProperty.value,\n)\n\nconst isTreeOpen = computed(\n (): boolean =>\n isTreeRow.value &&\n expansion.isExpanded(treeNodeKey.value, {\n cyclic: isCyclicProperty.value,\n defaultOpen: !!props.options.expandAllSchemaProperties,\n }),\n)\n\n/**\n * Mount policy, three states. Never opened: not rendered, which is the render\n * guard that stops a `$ref` cycle from recursing. Open: rendered. Opened then\n * closed: kept under `hidden=\"until-found\"` so find-in-page can reach it,\n * against a budget the whole reference shares, so hundreds of closed rows across\n * every tree on the page do not pile up as hidden DOM.\n * Past the cap, and in Safari where `until-found` is inert, closed panels unmount.\n */\nconst keepClosedPanelMounted = ref(false)\n\nwatch(isTreeOpen, (open, wasOpen) => {\n if (open) {\n if (keepClosedPanelMounted.value) {\n expansion.untilFound.release()\n keepClosedPanelMounted.value = false\n }\n return\n }\n\n if (wasOpen) {\n keepClosedPanelMounted.value =\n supportsUntilFound() && expansion.untilFound.acquire()\n }\n})\n\n/*\n * A row can leave the tree while still holding a slot (a composition picker\n * remounts its subtree on every variant change), and a leaked slot drains the\n * shared budget until find-in-page retention fails silently page-wide.\n */\nonScopeDispose(() => {\n if (keepClosedPanelMounted.value) {\n expansion.untilFound.release()\n keepClosedPanelMounted.value = false\n }\n})\n\n/** `hidden=\"until-found\"` support — Safari is the lone engine without it. */\nconst supportsUntilFound = (): boolean =>\n typeof document !== 'undefined' && 'onbeforematch' in document.body\n\nconst isTreePanelRendered = computed(\n (): boolean =>\n isStaticTreeRow.value ||\n (isTreeRow.value && (isTreeOpen.value || keepClosedPanelMounted.value)),\n)\n\nconst treePanelHidden = computed(() =>\n isStaticTreeRow.value || isTreeOpen.value ? undefined : 'until-found',\n)\n\n/** Nameless containers add no nesting level of their own. */\nconst rendersFlatChildren = computed(\n (): boolean =>\n isExpandable.value &&\n !isCyclicProperty.value &&\n !isTreeRow.value &&\n !isStaticTreeRow.value,\n)\n\nconst treePanelId = useId()\nconst treeNameId = useId()\nconst treeCountId = useId()\n\n/** The rail panel is a component, so the DOM node is reached through `$el`. */\nconst treePanelRef = useTemplateRef<{ $el: HTMLElement }>('treePanel')\nconst treeToggleRef = useTemplateRef<{ $el: HTMLElement } | HTMLElement>(\n 'treeToggle',\n)\n\n/**\n * Hovering the heading lights this row's puck, because the heading toggles the\n * row on click too. The state is a `data-heading-hovered` attribute on the row,\n * written by pointer events, rather than the former\n * `.property--tree:has(> .property-heading:hover)` selector: a `:has()` anchor\n * on every expandable row made each element inserted under it restyle the\n * whole open subtree. The attribute exists only while hovering and says exactly\n * what `:hover` said (see tailwind.config.css). Bound on tree rows only, so\n * leaf rows carry no listener and their DOM is untouched.\n */\nlet headingHoveredRow: HTMLElement | null = null\n\nconst clearHeadingHover = (): void => {\n headingHoveredRow?.removeAttribute('data-heading-hovered')\n headingHoveredRow = null\n}\n\nconst treeHeadingHoverListeners = {\n pointerenter: (event: Event): void => {\n clearHeadingHover()\n\n const row =\n event.currentTarget instanceof HTMLElement\n ? event.currentTarget.parentElement\n : null\n\n if (!row) {\n return\n }\n\n row.setAttribute('data-heading-hovered', '')\n headingHoveredRow = row\n },\n pointerleave: clearHeadingHover,\n}\n\n/*\n * The listeners come off without a pointerleave whenever the row stops being a\n * tree row under the pointer (a composition picker swaps the schema, so the\n * heading or the disclosure goes), and the marked row is this component's own\n * element, which outlives that change. Clear on both, or the puck stays lit.\n */\nwatch(isTreeRow, (treeRow) => {\n if (!treeRow) {\n clearHeadingHover()\n }\n})\n\nonBeforeUnmount(clearHeadingHover)\n\n/*\n * A close that did not come from the rail strip (the toggle, or the keyboard)\n * can leave the pointer resting on the strip, which then hides without a\n * pointerleave: drop the marks the strip wrote (see SchemaRailPanel.vue), or\n * the puck stays lit. Pre-flush, so the panel is still in the DOM here.\n */\nwatch(isTreeOpen, (open) => {\n if (open) {\n return\n }\n\n const panel = treePanelRef.value?.$el\n panel?.removeAttribute('data-rail-hovered')\n panel?.parentElement?.removeAttribute('data-child-rail-hovered')\n})\n\n/**\n * The schema the panel hands to its child `Schema`, so the count and the\n * preview describe the rows that render. Object-first, like `treeChildProps`.\n */\nconst treeChildSchema = computed(() =>\n rendersArrayBranch.value\n ? resolvedArrayItems.value\n : objectSchemaForChildren.value,\n)\n\n/**\n * The filtered, ordered child property names for the collapsed preview, and\n * for the count only when a hide flag filters the list. `sortPropertyNames`\n * (sort plus `$ref` resolution of every child) is the hottest per-row cost, so\n * nothing reads this while the row is open. Same call the panel makes — full\n * options, no discriminator — or the preview names the wrong first rows and\n * the count disagrees with the panel.\n */\nconst sortedChildPropertyNames = computed((): readonly string[] =>\n treeChildSchema.value\n ? sortPropertyNames(treeChildSchema.value, undefined, props.options)\n : [],\n)\n\n/**\n * The child count that rides the toggle's `aria-describedby`. A description\n * rather than part of the name, so screen-reader verbosity settings apply.\n */\nconst treeChildCountLabel = computed((): string | null => {\n if (!isExpandable.value) {\n return null\n }\n\n // Count the rows the panel will actually render: hideReadOnly / hideWriteOnly\n // filter the list, so raw keys would announce children that do not exist.\n const source = treeChildSchema.value\n if (!source) {\n return null\n }\n\n // Three groups, not one: properties, patternProperties and additionalProperties,\n // or a map-only schema announces no children at all.\n //\n // The count needs only a length. Without a hide flag the panel renders every\n // key, so counting them mirrors the sort's own early return and spares an\n // open row the sort entirely (the preview, its only other reader, exists\n // while collapsed). A hide flag drops rows, so only then is the filtered\n // length genuinely needed.\n const named =\n props.options.hideReadOnly || props.options.hideWriteOnly\n ? sortedChildPropertyNames.value.length\n : isTypeObject(source) && source.properties\n ? Object.keys(source.properties).length\n : 0\n const patterns =\n 'patternProperties' in source && source.patternProperties\n ? Object.keys(source.patternProperties).length\n : 0\n const additional =\n 'additionalProperties' in source && source.additionalProperties ? 1 : 0\n const count = named + patterns + additional\n\n if (count === 0) {\n return null\n }\n\n return translate('schema.propertyCount', { count: String(count) })\n})\n\n/**\n * Whether the type signature will render this row's enum values inline, which\n * is the only case where suppressing the separate value list is safe.\n */\nconst signatureInlinesEnum = computed((): boolean =>\n typeSignatureInlinesEnum(optimizedValue.value, {\n hideModelNames: hideModelNames.value,\n }),\n)\n\n/**\n * The toggle's accessible name when the row has no visible property name (an\n * array-of-objects root, say), so it is never announced as an unnamed button.\n */\nconst treeFallbackLabel = computed(\n (): string => props.modelName || translate('schema.schema'),\n)\n\nconst toggleTree = (): void => {\n const next = !isTreeOpen.value\n\n // Collapsing a subtree that holds focus moves focus up to this row's control\n // instead of dropping it to <body> as the panel hides.\n if (!next) {\n const active = document.activeElement\n const toggleElement =\n treeToggleRef.value instanceof HTMLElement\n ? treeToggleRef.value\n : treeToggleRef.value?.$el\n\n if (active && treePanelRef.value?.$el.contains(active)) {\n toggleElement?.focus()\n }\n }\n\n expansion.setExpanded(treeNodeKey.value, next)\n}\n\n/**\n * The whole heading is a pointer convenience for the disclosure; the gutter\n * toggle stays the accessible control. Interactive children keep their own\n * clicks, and a click that ends a text selection selects rather than toggles,\n * so property names stay copyable.\n */\nconst onHeadingClick = (event: MouseEvent): void => {\n if (!isTreeRow.value) {\n return\n }\n\n const target = event.target\n\n if (\n target instanceof Element &&\n target.closest('a, button, [role=\"button\"], input, select, label')\n ) {\n return\n }\n\n if (window.getSelection()?.toString()) {\n return\n }\n\n toggleTree()\n}\n\n/** Reopen a panel the browser revealed through find-in-page. */\nconst onBeforeMatch = (): void => {\n expansion.setExpanded(treeNodeKey.value, true)\n}\n</script>\n<template>\n <component\n :is=\"is ?? 'li'\"\n class=\"property\"\n :class=\"[\n `property--level-${level}`,\n {\n 'property--compact': compact,\n 'property--deprecated': optimizedValue?.deprecated,\n },\n /*\n * A single-column grid that never indents itself (see the indentation\n * model in the script). The tree spaces rows from --schema-row-pad and\n * separates them by rail, so the base padding and row border go.\n */\n 'property--tree grid! grid-cols-[minmax(0,1fr)] border-b-0! px-0! py-[var(--schema-row-pad,6px)]!',\n {\n 'property--tree-container':\n !isTreeRow &&\n !isCyclicProperty &&\n (isExpandable || !shouldDisplayHeadingComputed),\n },\n `property--depth-${depth}`,\n ]\">\n <!-- The disclosure control in this row's own gutter. See SchemaGutterToggle\n for the accessible-name wiring. -->\n <!-- Absolutely positioned so the hit box never sizes the heading row, and\n z-1 beats the rail strip so the puck wins the pointer.\n\n Vertically: the toggle is a grid item of row 1, so `top` is measured\n from the heading's own grid area. 10px is half the heading's 20px\n first-line slot, and the -50% translate centres a control of ANY size\n on it — a fixed offset silently rides 2px high the moment the narrow\n container shrinks the control. Anchored to the first line, not the\n area's middle, so a wrapped name keeps its toggle beside line one. -->\n <SchemaGutterToggle\n v-if=\"isTreeRow\"\n ref=\"treeToggle\"\n class=\"absolute start-[calc(0px_-_var(--schema-toggle-half,12px)_-_var(--schema-gutter,16px))] top-2.5 z-[1] col-start-1 row-start-1 -translate-y-1/2 print:hidden\"\n :countId=\"treeChildCountLabel ? treeCountId : undefined\"\n :fallbackLabel=\"treeFallbackLabel\"\n :nameId=\"name ? treeNameId : undefined\"\n :open=\"isTreeOpen\"\n :panelId=\"treePanelId\"\n :panelRendered=\"isTreePanelRendered\"\n @toggle=\"toggleTree\" />\n <!-- `row-start-1` shares the toggle's row. Whatever precedes the trailing\n hash drops its own right margin, so the hash sits the same distance\n after the text whether or not the row shows a preview (the preview\n carries no margin of its own — see below). -->\n <SchemaPropertyHeading\n v-if=\"shouldDisplayHeadingComputed\"\n class=\"group\"\n :class=\"[\n { 'cursor-pointer': isTreeRow },\n 'relative row-start-1 min-h-5 content-center [&>*:has(+.copy-link-trailing)]:me-0!',\n ]\"\n :discriminatorValue=\"discriminatorValue\"\n :enum=\"hasEnum\"\n :eventBus=\"eventBus\"\n :hideModelNames\n :isDiscriminator=\"isDiscriminatorProperty\"\n :keyKind=\"\n variant === 'additionalProperties'\n ? 'additional'\n : variant === 'patternProperties'\n ? 'pattern'\n : undefined\n \"\n :modelLinkOptions=\"{\n hideModels: options.hideModels,\n document: options.document,\n }\"\n :modelName=\"modelName\"\n :propertyNames=\"propertyNamesSchema\"\n :recursiveTo=\"isCyclicProperty ? cycleTargetName : undefined\"\n :required\n :value=\"optimizedValue\"\n v-on=\"isTreeRow ? treeHeadingHoverListeners : NO_LISTENERS\"\n @click=\"onHeadingClick\">\n <template\n v-if=\"name\"\n #name>\n <WithBreadcrumb\n v-if=\"hasBreadcrumbLink\"\n :breadcrumb=\"childBreadcrumb\">\n <!-- The ONLY node the gutter toggle's aria-labelledby points at.\n A plain inline span, never `display: contents`: the name is what\n a pointer aims at and what a test measures, and a box-less\n wrapper is unhoverable and reports no bounding box. -->\n <span :id=\"treeNameId\">\n <!-- The map-key keyword lives in the signature line (see\n SchemaPropertyHeading), so the chip chrome on the name —\n dashed box, accent colour, the `regex` badge — is switched\n off here and the name reads like any other. The class names\n stay as styling hooks. -->\n <span\n v-if=\"variant === 'patternProperties'\"\n class=\"property-name-pattern-properties text-c-1! border-0! p-0! before:hidden!\">\n <ScalarWrappingText\n preset=\"property\"\n :text=\"name\" />\n </span>\n <span\n v-else-if=\"variant === 'additionalProperties'\"\n class=\"property-name-additional-properties text-c-1! border-0! p-0! before:hidden!\">\n <ScalarWrappingText\n preset=\"property\"\n :text=\"name\" />\n </span>\n <ScalarWrappingText\n v-else\n preset=\"property\"\n :text=\"name\" />\n </span>\n </WithBreadcrumb>\n <template v-else>\n <!-- The ONLY node the gutter toggle's aria-labelledby points at.\n A plain inline span, never `display: contents`: the name is what\n a pointer aims at and what a test measures, and a box-less\n wrapper is unhoverable and reports no bounding box. -->\n <span :id=\"treeNameId\">\n <!-- The map-key keyword lives in the signature line (see\n SchemaPropertyHeading), so the chip chrome on the name —\n dashed box, accent colour, the `regex` badge — is switched\n off here and the name reads like any other. The class names\n stay as styling hooks. -->\n <span\n v-if=\"variant === 'patternProperties'\"\n class=\"property-name-pattern-properties text-c-1! border-0! p-0! before:hidden!\">\n <ScalarWrappingText\n preset=\"property\"\n :text=\"name\" />\n </span>\n <span\n v-else-if=\"variant === 'additionalProperties'\"\n class=\"property-name-additional-properties text-c-1! border-0! p-0! before:hidden!\">\n <ScalarWrappingText\n preset=\"property\"\n :text=\"name\" />\n </span>\n <ScalarWrappingText\n v-else\n preset=\"property\"\n :text=\"name\" />\n </span>\n </template>\n </template>\n <template\n v-if=\"optimizedValue?.example !== undefined\"\n #example>\n Example:\n {{ optimizedValue.example }}\n </template>\n <template\n v-if=\"isTreeRow && !isTreeOpen\"\n #preview>\n <!-- Purely visual: the child count already rides aria-describedby -->\n <!-- A zero-basis flex item must have a zero outer size, or the heading's\n 9px child margin wraps it onto its own line -->\n <SchemaCollapsedPreview\n aria-hidden=\"true\"\n class=\"mr-0!\"\n :propertyNames=\"sortedChildPropertyNames\"\n :schema=\"treeChildSchema as SchemaObject\" />\n </template>\n <template\n v-if=\"name && shouldHaveLink && childBreadcrumb\"\n #trailing>\n <CopyLinkButton\n :anchorId=\"childBreadcrumb.join('.')\"\n :eventBus=\"eventBus\" />\n </template>\n </SchemaPropertyHeading>\n\n <ExternalDocs\n class=\"my-2\"\n :value=\"optimizedValue?.externalDocs\" />\n\n <!-- Description -->\n <!-- The heading's 20px slot already leaves slack under the name, so 4px is\n enough under it; 6px above a composition keeps the row on the 12px\n rhythm. -->\n <div\n v-if=\"displayDescription || propertyDescription\"\n class=\"property-description mt-1! has-[+.property-rule]:mb-1.5!\">\n <ScalarMarkdown\n :value=\"displayDescription || propertyDescription || ''\" />\n </div>\n\n <!-- Enum for property names, on any additionalProperties/patternProperties\n schema whose propertyNames carry an enum. -->\n <SchemaEnums\n v-if=\"propertyNamesEnum && propertyNamesEnum.length > 0\"\n propertyNames\n :value=\"{ enum: propertyNamesEnum } as SchemaObject\" />\n\n <!-- Enum values -->\n <!-- The array items card rendered below already lists these same values. -->\n <!-- Skip the list when the signature already inlines the enum, but only\n when it genuinely does (never for a $ref or an untyped schema), or the\n values would be shown nowhere at all. -->\n <SchemaEnums\n v-if=\"\n enumValues.length > 0 &&\n !shouldRenderArrayOfObjects &&\n !signatureInlinesEnum\n \"\n :value=\"optimizedValue\" />\n\n <!-- The child count description and the rail panel -->\n <span\n v-if=\"isTreeRow && treeChildCountLabel\"\n :id=\"treeCountId\"\n class=\"screenreader-only\"\n >{{ treeChildCountLabel }}</span\n >\n\n <!-- closeOnRail: a pointer-only convenience like an editor's indent\n guide; the gutter toggle stays the accessible control. -->\n <!-- Nothing inside a panel may add trailing height below the last row,\n so the descendant resets reach into the child Schema cards. -->\n <SchemaRailPanel\n v-if=\"isTreePanelRendered\"\n :id=\"treePanelId\"\n ref=\"treePanel\"\n class=\"property-children mt-1.5 mb-0.5 [&_.schema-card]:mb-0! [&_.schema-card]:pb-0! [&_.schema-properties]:mb-0! [&_.schema-properties]:pb-0! [&_ul]:my-0! [&_ul]:py-0! [&[hidden=until-found]]:my-0 [&[hidden=until-found]]:border-s-0 [&[hidden]:not([hidden=until-found])]:hidden\"\n :closeOnRail=\"isTreeRow\"\n :depth=\"depth + 1\"\n :hidden=\"treePanelHidden\"\n @beforematch=\"onBeforeMatch\"\n @close=\"toggleTree\">\n <!-- The panel is one level deeper than the row it belongs to -->\n <Schema\n v-if=\"treeChildProps\"\n v-bind=\"treeChildProps\"\n :depth=\"depth + 1\"\n :expansion=\"expansion\"\n noncollapsible\n :scrollTargetId=\"scrollTargetId\"\n :specificationExtension=\"specificationExtension\" />\n </SchemaRailPanel>\n\n <!-- A container renders its children directly with no depth step. Not a\n v-else of the panel: a collapsed tree row must not fall through here.\n 6px under a description keeps the 12px rhythm. -->\n <div\n v-if=\"rendersFlatChildren\"\n class=\"children [.property-description+&]:mt-1.5!\">\n <!-- A container adds no rail, so its children keep this row's depth -->\n <Schema\n v-if=\"treeChildProps\"\n v-bind=\"treeChildProps\"\n :depth=\"depth\"\n :expansion=\"expansion\"\n noncollapsible\n :scrollTargetId=\"scrollTargetId\"\n :specificationExtension=\"specificationExtension\" />\n </div>\n\n <!-- Compositions -->\n <!-- This row's own breadcrumb, so sibling compositions do not collide on\n anchors and expansion keys. -->\n <!-- Fall back to the inherited discriminator to label the property inside an allOf variant (#9674) -->\n <SchemaComposition\n v-for=\"compositionData in compositionsToRender\"\n :key=\"compositionData.composition\"\n :breadcrumb=\"childBreadcrumb\"\n :compact=\"compact\"\n :composition=\"compositionData.composition\"\n :compositionPath=\"currentCompositionPath\"\n :depth=\"depth\"\n :discriminator=\"getCompositionDiscriminator(compositionData.composition)\"\n :eventBus=\"eventBus\"\n :expansion=\"expansion\"\n :hideHeading=\"hideHeading\"\n :hideModelNames\n :level=\"level\"\n :name=\"name\"\n :noncollapsible=\"noncollapsible\"\n :options=\"options\"\n :schema=\"compositionData.value\"\n :schemaContext=\"schemaContext\"\n :scrollTargetId=\"scrollTargetId\"\n :specificationExtension=\"specificationExtension\" />\n <component\n :is=\"specificationExtension\"\n v-if=\"hasSpecificationExtensions && specificationExtension\"\n :showExtensions=\"options.showExtensions\"\n :value=\"extensionValue\" />\n </component>\n</template>\n\n<style scoped>\n.property {\n color: var(--scalar-color-1);\n display: flex;\n flex-direction: column;\n padding: 10px;\n font-size: var(--scalar-small);\n position: relative;\n}\n\n/* if a property doesn't have a heading, remove the top padding */\n.property:has(> .property-rule:nth-of-type(1)):not(.property--compact) {\n padding-top: 8px;\n padding-bottom: 8px;\n}\n\n.property--deprecated {\n background: repeating-linear-gradient(\n -45deg,\n var(--scalar-background-2) 0,\n var(--scalar-background-2) 2px,\n transparent 2px,\n transparent 5px\n );\n background-size: 100%;\n}\n\n/*\n * A deprecated row keeps its text at full strength rather than fading it. Fading blended\n * the muted text into the card, leaving it at 3.0:1 where WCAG 1.4.3 asks 4.5:1 of body\n * text, and the row already says \"deprecated\" three other ways: the stripes above, the\n * strikethrough on the property name (see SchemaPropertyHeading) and the Deprecated badge\n * beside it. The fade was the one signal carrying no information and the only one costing\n * contrast, so do not reintroduce it.\n */\n\n.property-description {\n margin-top: 6px;\n line-height: 1.4;\n font-size: var(--scalar-small);\n}\n\n.property-description:has(+ .property-rule) {\n margin-bottom: 9px;\n}\n\n:deep(.property-description) * {\n color: var(--scalar-color-2) !important;\n}\n\n.property:not(:last-of-type) {\n border-bottom: var(--scalar-border-width) solid var(--scalar-border-color);\n}\n\n.property-description + .children,\n.children + .property-rule {\n margin-top: 9px;\n}\n\n.children {\n display: flex;\n flex-direction: column;\n}\n\n.children .property--compact.property--level-1 {\n padding: 12px;\n}\n\n.property-example-value {\n all: unset;\n font-family: var(--scalar-font-code);\n padding: 6px;\n border-top: var(--scalar-border-width) solid var(--scalar-border-color);\n}\n\n.property-rule {\n border-radius: var(--scalar-radius-lg);\n display: flex;\n flex-direction: column;\n}\n\n.property-example {\n background: transparent;\n border: none;\n display: flex;\n flex-direction: row;\n gap: 8px;\n}\n\n.property-example-label,\n.property-example-value {\n padding: 3px 0 0 0;\n}\n\n.property-example-value {\n background: var(--scalar-background-2);\n border-top: 0;\n border-radius: var(--scalar-radius);\n padding: 3px 4px;\n}\n\n.property-name {\n font-family: var(--scalar-font-code);\n font-weight: var(--scalar-semibold);\n}\n\n.property-name-additional-properties::before,\n.property-name-pattern-properties::before {\n text-transform: uppercase;\n font-size: var(--scalar-micro);\n display: inline-block;\n padding: 2px 4px;\n border-radius: var(--scalar-radius);\n color: var(--scalar-color-1);\n border: var(--scalar-border-width) solid var(--scalar-border-color);\n background-color: var(--scalar-background-2);\n margin-right: 4px;\n}\n\n.property-name-pattern-properties::before {\n content: 'regex';\n}\n\n.property-name-additional-properties,\n.property-name-pattern-properties {\n border: 1px dashed var(--scalar-border-color);\n color: var(--scalar-color-accent);\n display: inline-block;\n padding: 2px;\n border-radius: var(--scalar-radius);\n}\n</style>\n"],"mappings":"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"}
@@ -5,6 +5,8 @@ type __VLS_Props = {
5
5
  value: SchemaObject | undefined;
6
6
  enum?: boolean;
7
7
  isDiscriminator?: boolean;
8
+ /** Effective AsyncAPI variant value, separate from const/enum constraints. */
9
+ discriminatorValue?: string;
8
10
  required?: boolean;
9
11
  additional?: boolean;
10
12
  withExamples?: boolean;
@@ -33,13 +35,13 @@ type __VLS_Props = {
33
35
  */
34
36
  recursiveTo?: string;
35
37
  };
36
- declare var __VLS_1: {}, __VLS_80: {}, __VLS_82: {};
38
+ declare var __VLS_1: {}, __VLS_85: {}, __VLS_87: {};
37
39
  type __VLS_Slots = {} & {
38
40
  name?: (props: typeof __VLS_1) => any;
39
41
  } & {
40
- preview?: (props: typeof __VLS_80) => any;
42
+ preview?: (props: typeof __VLS_85) => any;
41
43
  } & {
42
- trailing?: (props: typeof __VLS_82) => any;
44
+ trailing?: (props: typeof __VLS_87) => any;
43
45
  };
44
46
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
45
47
  required: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"SchemaPropertyHeading.vue.d.ts","sourceRoot":"","sources":["../../src/schema/SchemaPropertyHeading.vue"],"names":[],"mappings":"AA4qBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAEvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8DAA8D,CAAA;AAWhG,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,6BAA6B,CAAA;AASpC,KAAK,WAAW,GAAG;IACf,KAAK,EAAE,YAAY,GAAG,SAAS,CAAA;IAC/B,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC,qHAAqH;IACrH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,8GAA8G;IAC9G,aAAa,CAAC,EAAE,YAAY,CAAA;IAC5B,QAAQ,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAA;IACnC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,YAAY,GAAG,SAAS,CAAA;IAClC;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAC;AAkvBJ,QAAA,IAAI,OAAO,IAAU,EAAE,QAAQ,IAAW,EAAE,QAAQ,IAAY,CAAE;AAClE,KAAK,WAAW,GAAG,EAAE,GACnB;IAAE,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,CAAA;CAAE,GACzC;IAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,QAAQ,KAAK,GAAG,CAAA;CAAE,GAC7C;IAAE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,QAAQ,KAAK,GAAG,CAAA;CAAE,CAAC;AAKjD,QAAA,MAAM,UAAU;cAtxBD,OAAO;cAaP,iBAAiB,GAAG,IAAI;oBAVlB,OAAO;qBAJN,OAAO;kBAGV,OAAO;6EAuxBxB,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":"SchemaPropertyHeading.vue.d.ts","sourceRoot":"","sources":["../../src/schema/SchemaPropertyHeading.vue"],"names":[],"mappings":"AAorBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAEvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8DAA8D,CAAA;AAWhG,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,6BAA6B,CAAA;AASpC,KAAK,WAAW,GAAG;IACf,KAAK,EAAE,YAAY,GAAG,SAAS,CAAA;IAC/B,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,8EAA8E;IAC9E,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC,qHAAqH;IACrH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,8GAA8G;IAC9G,aAAa,CAAC,EAAE,YAAY,CAAA;IAC5B,QAAQ,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAA;IACnC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,YAAY,GAAG,SAAS,CAAA;IAClC;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAC;AAiwBJ,QAAA,IAAI,OAAO,IAAU,EAAE,QAAQ,IAAW,EAAE,QAAQ,IAAY,CAAE;AAClE,KAAK,WAAW,GAAG,EAAE,GACnB;IAAE,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,CAAA;CAAE,GACzC;IAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,QAAQ,KAAK,GAAG,CAAA;CAAE,GAC7C;IAAE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,QAAQ,KAAK,GAAG,CAAA;CAAE,CAAC;AAKjD,QAAA,MAAM,UAAU;cAryBD,OAAO;cAaP,iBAAiB,GAAG,IAAI;oBAVlB,OAAO;qBANN,OAAO;kBAKV,OAAO;6EAsyBxB,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 e from "../_virtual/_plugin-vue_export-helper.js";
2
2
  import t from "./SchemaPropertyHeading.vue.script.js";
3
3
  /* empty css */
4
4
  //#region src/schema/SchemaPropertyHeading.vue
5
- var n = /*#__PURE__*/ e(t, [["__scopeId", "data-v-266fd7fb"]]);
5
+ var n = /*#__PURE__*/ e(t, [["__scopeId", "data-v-d9e2f10e"]]);
6
6
  //#endregion
7
7
  export { n as default };
8
8
 
@@ -1 +1 @@
1
- {"version":3,"file":"SchemaPropertyHeading.vue.js","names":[],"sources":["../../src/schema/SchemaPropertyHeading.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport { isDefined } from '@scalar/helpers/array/is-defined'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { SchemaObject } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport {\n isArraySchema,\n isNumberSchema,\n isStringSchema,\n} from '@scalar/workspace-store/schemas/v3.2/strict/type-guards'\nimport { computed, toRef } from 'vue'\n\nimport Badge from '../shared/Badge.vue'\nimport { getSchemaType } from './helpers/get-schema-type'\nimport { getDisplayTypeSignatureTokens } from './helpers/get-type-signature-tokens'\nimport {\n isModelLinkable,\n type ModelLinkOptions,\n} from './helpers/is-model-linkable'\nimport { getModelNameWithArray } from './helpers/schema-name'\nimport { useLocalization } from './localization'\nimport RenderString from './RenderString.vue'\nimport SchemaPropertyDefault from './SchemaPropertyDefault.vue'\nimport SchemaPropertyDetail from './SchemaPropertyDetail.vue'\nimport SchemaPropertyExamples from './SchemaPropertyExamples.vue'\nimport SchemaPropertyPattern from './SchemaPropertyPattern.vue'\n\nconst props = withDefaults(\n defineProps<{\n value: SchemaObject | undefined\n enum?: boolean\n isDiscriminator?: boolean\n required?: boolean\n additional?: boolean\n withExamples?: boolean\n hideModelNames?: boolean\n /**\n * Config for deciding whether a model name links to the models section. When the section or\n * the referenced model is hidden there is nothing to scroll to, so the name renders as plain text.\n */\n modelLinkOptions?: ModelLinkOptions\n /** When the schema was resolved from a $ref, pass the ref name so it displays as e.g. \"Data\" instead of \"object\". */\n modelName?: string | null\n /** Resolved propertyNames schema, used to surface key constraints like `format` for additional properties. */\n propertyNames?: SchemaObject\n eventBus?: WorkspaceEventBus | null\n /**\n * The row's name is a stand-in for keys the caller chooses\n * (`additionalProperties`) or keys matching a regex (`patternProperties`),\n * not a literal property. The heading says so in the signature line, where\n * the tree already describes shapes, instead of styling the name itself.\n */\n keyKind?: 'additional' | 'pattern'\n /**\n * The name of the schema this row loops back to. A cut cycle is a leaf, so\n * the signature line says why it does not expand; the model link beside it\n * already names the schema the loop returns to.\n */\n recursiveTo?: string\n }>(),\n {\n isDiscriminator: false,\n required: false,\n withExamples: true,\n hideModelNames: false,\n eventBus: null,\n },\n)\nconst { translate } = useLocalization()\n\n// Convert to reactive refs for composables\nconst valueRef = toRef(props, 'value')\n\nconst constValue = computed(() => {\n if (!valueRef.value) {\n return undefined\n }\n\n const schema = valueRef.value\n\n // Direct const value\n if (schema.const !== undefined) {\n return schema.const\n }\n\n // Single-item enum acts as const\n if (schema.enum?.length === 1) {\n return schema.enum[0]\n }\n\n // Check items for const values (for arrays)\n if (isArraySchema(schema) && schema.items) {\n const items = resolve.schema(schema.items)\n\n if (isDefined(items.const)) {\n return items.const\n }\n\n if (items.enum?.length === 1) {\n return items.enum[0]\n }\n }\n\n return undefined\n})\n\ntype ValidationProperty = {\n key: string\n value: string | number\n prefix?: string\n code?: boolean\n truncate?: boolean\n}\n\n/**\n * Constraints that live on a leaf (string or number) schema: length, pattern,\n * format and numeric ranges. Extracted so they can be surfaced for a primitive\n * schema as well as for a primitive array's items, which are not rendered on\n * their own. See https://github.com/scalar/scalar/issues/9690\n */\nconst getLeafConstraints = (schema: SchemaObject) => {\n const properties: ValidationProperty[] = []\n\n if (isStringSchema(schema)) {\n if (schema.minLength) {\n properties.push({\n key: 'min-length',\n prefix: `${translate('schema.minLength')}: `,\n value: schema.minLength,\n })\n }\n\n if (schema.maxLength) {\n properties.push({\n key: 'max-length',\n prefix: `${translate('schema.maxLength')}: `,\n value: schema.maxLength,\n })\n }\n\n // pattern is rendered via SchemaPropertyPattern (hover dropdown), skip here\n }\n\n if ((isStringSchema(schema) || isNumberSchema(schema)) && schema.format) {\n properties.push({\n key: 'format',\n value: schema.format,\n truncate: true,\n })\n }\n\n if (isNumberSchema(schema)) {\n if (isDefined(schema.exclusiveMinimum)) {\n properties.push({\n key: 'exclusive-minimum',\n prefix: `${translate('schema.greaterThan')}: `,\n value: schema.exclusiveMinimum,\n })\n }\n\n if (isDefined(schema.minimum)) {\n properties.push({\n key: 'minimum',\n prefix: `${translate('schema.min')}: `,\n value: schema.minimum,\n })\n }\n\n if (isDefined(schema.exclusiveMaximum)) {\n properties.push({\n key: 'exclusive-maximum',\n prefix: `${translate('schema.lessThan')}: `,\n value: schema.exclusiveMaximum,\n })\n }\n\n if (isDefined(schema.maximum)) {\n properties.push({\n key: 'maximum',\n prefix: `${translate('schema.max')}: `,\n value: schema.maximum,\n })\n }\n\n if (isDefined(schema.multipleOf)) {\n properties.push({\n key: 'multiple-of',\n prefix: `${translate('schema.multipleOf')}: `,\n value: schema.multipleOf,\n })\n }\n }\n\n return properties\n}\n\nconst validationProperties = computed(() => {\n if (!valueRef.value) {\n return []\n }\n\n const schema = valueRef.value\n const properties: ValidationProperty[] = []\n\n // Array validation properties\n if (isArraySchema(schema)) {\n if (schema.minItems || schema.maxItems) {\n properties.push({\n key: 'array-range',\n value: `${schema.minItems || ''}…${schema.maxItems || ''}`,\n })\n }\n\n // Unique items\n if (schema.uniqueItems) {\n properties.push({\n key: 'unique-items',\n value: `${translate('schema.unique')}!`,\n })\n }\n }\n\n properties.push(...getLeafConstraints(schema))\n\n // Primitive array items carry their own constraints (e.g. an array of `uuid`\n // strings) but are not rendered separately, so surface them here.\n if (isArraySchema(schema) && schema.items) {\n properties.push(...getLeafConstraints(resolve.schema(schema.items)))\n }\n\n return properties\n})\n\n/** Link data for navigating to the referenced model in the sidebar. */\nconst modelLink = computed(() => {\n if (!props.value) {\n return null\n }\n\n if (props.hideModelNames) {\n return null\n }\n\n if (props.modelName) {\n return { schemaKey: props.modelName, label: props.modelName }\n }\n\n return getModelNameWithArray(props.value)\n})\n\n/** Whether the model name links to the models section, or renders as plain text. */\nconst modelLinkable = computed(() =>\n isModelLinkable(modelLink.value?.schemaKey, props.modelLinkOptions ?? {}),\n)\n\n/**\n * The type as a run of tokens rather than a single string — identifiers in\n * the code face, English words like `array of` in the sans face, and a muted\n * `|` so `string | null` reads as one type with an alternative.\n *\n * The token run and the screen-reader label are written straight into the\n * template instead of being their own components: the tree mounts one per\n * typed row, and a component instance costs more to create than the span it\n * renders. On a flat object the type cells would be most of the instance\n * count. The linked and the plain copy of the token markup below must stay\n * identical.\n */\nconst signatureTokens = computed(() =>\n getDisplayTypeSignatureTokens(props.value, {\n hideModelNames: props.hideModelNames,\n modelName: modelLink.value?.label,\n }),\n)\n\n/** Check if we should show the type information */\nconst shouldShowType = computed(() => {\n if (!props.value || !('type' in props.value)) {\n return false\n }\n\n // Always show type for arrays, even when items have const values\n if (props.value.type === 'array') {\n return true\n }\n\n // For non-arrays, only show if no const value at the schema level\n return !constValue.value\n})\n\n/**\n * Type and format of the property keys, derived from the propertyNames schema.\n *\n * For a map keyed by UUIDs this renders e.g. \"string · uuid\" so the key\n * constraints are not lost. Returns undefined when there is nothing to show.\n */\nconst propertyNamesDetail = computed(() => {\n const schema = props.propertyNames\n if (!schema) {\n return undefined\n }\n\n const parts = [getSchemaType(schema)]\n if ('format' in schema && typeof schema.format === 'string') {\n parts.push(schema.format)\n }\n\n const detail = parts.filter(Boolean).join(' · ')\n return detail.length > 0 ? detail : undefined\n})\n\nconst exampleValue = computed(() => {\n // Treat only `undefined` as \"not set\" — `null` is a valid example value on a nullable schema.\n if (\n props.value &&\n 'example' in props.value &&\n props.value.example !== undefined\n ) {\n return props.value.example\n }\n\n if (props.value && isArraySchema(props.value)) {\n const itemsSchema = resolve.schema(props.value.items)\n if (\n itemsSchema &&\n 'example' in itemsSchema &&\n itemsSchema.example !== undefined\n ) {\n return itemsSchema.example\n }\n }\n\n return undefined\n})\n\n/**\n * Whether the examples chip has anything to render.\n *\n * `SchemaPropertyExamples` already renders nothing without an example, but it\n * still mounts, and mounting is what installs its popup's window-level click\n * and keydown listeners. `withExamples` defaults to true, so without this gate\n * every property row on the page — including a plain `{ type: 'string' }` —\n * pays for a popup it never opens. Mirrors the component's own two branches.\n */\nconst hasExampleContent = computed((): boolean => {\n if (exampleValue.value !== undefined) {\n return true\n }\n\n const examples = props.value?.examples\n\n return (\n !!examples &&\n typeof examples === 'object' &&\n Object.keys(examples).length > 0\n )\n})\n\n/**\n * The regex `pattern` to surface via the hover dropdown. It lives on a string\n * schema, or on the items of a primitive array (which is not rendered on its\n * own, so its constraints are surfaced on the array heading — see\n * https://github.com/scalar/scalar/issues/9690).\n */\nconst patternValue = computed(() => {\n const schema = valueRef.value\n if (!schema) {\n return undefined\n }\n\n if (isStringSchema(schema) && schema.pattern) {\n return schema.pattern\n }\n\n if (isArraySchema(schema) && schema.items) {\n const items = resolve.schema(schema.items)\n if (isStringSchema(items) && items.pattern) {\n return items.pattern\n }\n }\n\n return undefined\n})\n</script>\n<template>\n <div\n class=\"property-heading [&>.property-detail:has(+.property-detail)]:mr-0\">\n <!-- `:has(+.property-detail)`: only a detail FOLLOWED BY another detail\n drops its right margin, because the `·` separator supplies the gap\n there. Not `:not(:last-of-type)`, which matches by element type: the\n collapsed preview and the trailing copy-link are spans as well, so it\n would strip the margin from the final detail and glue \"Addressrequired\"\n together on a collapsed row. -->\n <div\n v-if=\"$slots.name\"\n class=\"property-name\"\n :class=\"{ deprecated: props.value?.deprecated }\">\n <slot name=\"name\" />\n </div>\n <div\n v-if=\"props.isDiscriminator\"\n class=\"property-discriminator\">\n {{ translate('schema.discriminator') }}\n </div>\n <template v-if=\"props.value\">\n <!-- A map key reads `additionalProperty · string`: the keyword leads the\n detail list in the accent colour, like a type word, so the name\n above it can look like every other name. -->\n <SchemaPropertyDetail\n v-if=\"props.keyKind\"\n class=\"property-key-kind\">\n <span class=\"font-code text-c-accent\">{{\n props.keyKind === 'pattern' ? 'patternProperty' : 'additionalProperty'\n }}</span>\n </SchemaPropertyDetail>\n <!-- Type information -->\n <SchemaPropertyDetail\n v-if=\"shouldShowType\"\n truncate>\n <!-- The type is a token run (`array of Planet`) and a $ref link IS the\n type, not an appended `· Account` -->\n <!-- Written across lines on purpose: Vue drops whitespace-only text\n between two elements, so a single-line label would read\n `Type:string`. -->\n <span class=\"screenreader-only\"> {{ translate('schema.type') }}: </span>\n <button\n v-if=\"props.eventBus && modelLink?.schemaKey && modelLinkable\"\n class=\"text-c-2 hover:text-c-1 underline\"\n type=\"button\"\n @click=\"\n props.eventBus.emit('scroll-to:model-by-name', {\n name: modelLink.schemaKey,\n })\n \">\n <span\n v-if=\"signatureTokens.length\"\n class=\"property-type-signature text-c-2 text-(length:--scalar-mini)\">\n <template\n v-for=\"(token, index) in signatureTokens\"\n :key=\"index\">\n {{ index > 0 ? ' ' : ''\n }}<span\n class=\"property-type-token\"\n :class=\"[\n `property-type-token--${token.kind}`,\n token.kind === 'word' ? 'font-sans' : '',\n token.kind === 'ident' || token.kind === 'literal'\n ? 'font-code'\n : '',\n token.kind === 'punctuation' ? 'text-c-2' : '',\n ]\"\n >{{ token.text }}</span\n >\n </template>\n </span>\n </button>\n <span\n v-else-if=\"signatureTokens.length\"\n class=\"property-type-signature text-c-2 text-(length:--scalar-mini)\">\n <template\n v-for=\"(token, index) in signatureTokens\"\n :key=\"index\">\n {{ index > 0 ? ' ' : ''\n }}<span\n class=\"property-type-token\"\n :class=\"[\n `property-type-token--${token.kind}`,\n token.kind === 'word' ? 'font-sans' : '',\n token.kind === 'ident' || token.kind === 'literal'\n ? 'font-code'\n : '',\n token.kind === 'punctuation' ? 'text-c-2' : '',\n ]\"\n >{{ token.text }}</span\n >\n </template>\n </span>\n </SchemaPropertyDetail>\n\n <!-- A cycle reads `array of Satellite · recursive`, a modifier like\n `nullable`; the full sentence rides the tooltip. -->\n <SchemaPropertyDetail\n v-if=\"props.recursiveTo\"\n class=\"property-recursive\"\n :title=\"\n translate('schema.recursiveReference', { name: props.recursiveTo })\n \">\n {{ translate('schema.recursive') }}\n </SchemaPropertyDetail>\n\n <!-- Key constraints from propertyNames (e.g. \"keys: string · uuid\") -->\n <SchemaPropertyDetail\n v-if=\"propertyNamesDetail\"\n truncate>\n <template #prefix>{{ translate('schema.keys') }}:</template>\n {{ propertyNamesDetail }}\n </SchemaPropertyDetail>\n\n <!-- Dynamic validation properties from composable -->\n <SchemaPropertyDetail\n v-for=\"property in validationProperties\"\n :key=\"property.key\"\n :code=\"property.code\"\n :truncate=\"property.truncate\">\n <span\n v-if=\"property.key === 'format'\"\n class=\"screenreader-only\">\n {{ translate('schema.format') }}:\n </span>\n <template\n v-if=\"property.prefix\"\n #prefix>\n {{ property.prefix }}\n </template>\n {{ property.value }}\n </SchemaPropertyDetail>\n\n <!-- Enum indicator -->\n <SchemaPropertyDetail v-if=\"props.enum\">\n {{ translate('schema.enum') }}\n </SchemaPropertyDetail>\n </template>\n <div\n v-if=\"props.additional\"\n class=\"property-additional\">\n <template v-if=\"props.value?.['x-additionalPropertiesName']\">\n {{ props.value['x-additionalPropertiesName'] }}\n </template>\n <template v-else>{{ translate('schema.additionalProperties') }}</template>\n </div>\n <div\n v-if=\"props.value?.deprecated\"\n class=\"property-deprecated\">\n <Badge>{{ translate('schema.deprecated') }}</Badge>\n </div>\n <!-- Don't use `isDefined` here, we want to show `const` when the value is `null` -->\n <div\n v-if=\"constValue !== undefined\"\n class=\"property-const\">\n <SchemaPropertyDetail truncate>\n <template #prefix>{{ translate('schema.const') }}: </template>\n <RenderString :value=\"constValue\" />\n </SchemaPropertyDetail>\n </div>\n <template v-else>\n <!-- Shows only when a composition is used (so props.value?.type is undefined) -->\n <SchemaPropertyDetail v-if=\"(props.value as any)?.nullable === true\">\n {{ translate('schema.nullable') }}\n </SchemaPropertyDetail>\n </template>\n <div\n v-if=\"props.value?.writeOnly\"\n class=\"property-write-only\">\n {{ translate('schema.writeOnly') }}\n </div>\n <div\n v-else-if=\"props.value?.readOnly\"\n class=\"property-read-only\">\n {{ translate('schema.readOnly') }}\n </div>\n <div\n v-if=\"props.required\"\n class=\"property-required\">\n {{ translate('schema.required') }}\n </div>\n <!-- Gated here, not only inside the component: each popup instance installs\n window-level click and keydown listeners for its dismissal, so mounting\n one per row costs the page a listener per row it never shows anything\n for. Same reason `SchemaPropertyPattern` below is gated. -->\n <SchemaPropertyDefault\n v-if=\"props.value?.default !== undefined\"\n :value=\"props.value?.default\" />\n <!--\n Pattern is a hover dropdown chip like Examples, not an inline constraint,\n so it sits beside the example. This keeps the real constraints (length,\n nullable, …) together in the dotted list. See #9966.\n -->\n <SchemaPropertyPattern\n v-if=\"patternValue\"\n :pattern=\"patternValue\" />\n <SchemaPropertyExamples\n v-if=\"props.withExamples && hasExampleContent\"\n :example=\"exampleValue\"\n :examples=\"props.value?.examples\" />\n <!-- The collapsed preview rides the end of the heading line -->\n <slot name=\"preview\" />\n <!-- Last so the tab order matches the visual order: the trailing copy-link\n is painted at the row's right edge, after every control to its left -->\n <slot name=\"trailing\" />\n </div>\n</template>\n<style scoped>\n.property-heading {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n row-gap: 9px;\n white-space: nowrap;\n}\n\n.property-heading:has(+ .children),\n.property-heading:has(+ .property-rule) {\n margin-bottom: 9px;\n}\n\n.property-heading > * {\n margin-right: 9px;\n}\n\n.property-heading:last-child {\n margin-right: 0;\n}\n\n.property-name {\n max-width: 100%;\n font-family: var(--scalar-font-code);\n font-weight: var(--scalar-bold);\n font-size: var(--scalar-font-size-4);\n white-space: normal;\n overflow-wrap: break-word;\n}\n\n.property-additional {\n font-family: var(--scalar-font-code);\n}\n\n.property-required,\n.property-optional {\n color: var(--scalar-color-2);\n}\n\n.property-required {\n font-size: var(--scalar-mini);\n color: var(--scalar-color-orange);\n}\n/*\n * Light-mode oranges are too bright on a light page for 13px text (the default\n * #ff5800 is 3.16:1), so blend the theme orange toward the text colour to reach\n * WCAG 1.4.3 (4.5:1) while keeping the hue and letting custom themes flow\n * through. Dark mode already passes (8.37:1) and keeps the plain token.\n */\n.light-mode .property-required {\n color: color-mix(\n in srgb,\n var(--scalar-color-orange),\n var(--scalar-color-1) 32%\n );\n}\n\n.property-read-only {\n font-size: var(--scalar-mini);\n color: var(--scalar-color-blue);\n}\n\n.property-write-only {\n font-size: var(--scalar-mini);\n color: var(--scalar-color-green);\n}\n\n.property-discriminator {\n font-size: var(--scalar-mini);\n color: var(--scalar-color-purple);\n}\n\n.property-detail {\n font-size: var(--scalar-mini);\n color: var(--scalar-color-2);\n display: flex;\n align-items: center;\n\n min-width: 0;\n}\n\n.property-const {\n color: var(--scalar-color-1);\n}\n\n.deprecated {\n text-decoration: line-through;\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"SchemaPropertyHeading.vue.js","names":[],"sources":["../../src/schema/SchemaPropertyHeading.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport { isDefined } from '@scalar/helpers/array/is-defined'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { SchemaObject } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport {\n isArraySchema,\n isNumberSchema,\n isStringSchema,\n} from '@scalar/workspace-store/schemas/v3.2/strict/type-guards'\nimport { computed, toRef } from 'vue'\n\nimport Badge from '../shared/Badge.vue'\nimport { getSchemaType } from './helpers/get-schema-type'\nimport { getDisplayTypeSignatureTokens } from './helpers/get-type-signature-tokens'\nimport {\n isModelLinkable,\n type ModelLinkOptions,\n} from './helpers/is-model-linkable'\nimport { getModelNameWithArray } from './helpers/schema-name'\nimport { useLocalization } from './localization'\nimport RenderString from './RenderString.vue'\nimport SchemaPropertyDefault from './SchemaPropertyDefault.vue'\nimport SchemaPropertyDetail from './SchemaPropertyDetail.vue'\nimport SchemaPropertyExamples from './SchemaPropertyExamples.vue'\nimport SchemaPropertyPattern from './SchemaPropertyPattern.vue'\n\nconst props = withDefaults(\n defineProps<{\n value: SchemaObject | undefined\n enum?: boolean\n isDiscriminator?: boolean\n /** Effective AsyncAPI variant value, separate from const/enum constraints. */\n discriminatorValue?: string\n required?: boolean\n additional?: boolean\n withExamples?: boolean\n hideModelNames?: boolean\n /**\n * Config for deciding whether a model name links to the models section. When the section or\n * the referenced model is hidden there is nothing to scroll to, so the name renders as plain text.\n */\n modelLinkOptions?: ModelLinkOptions\n /** When the schema was resolved from a $ref, pass the ref name so it displays as e.g. \"Data\" instead of \"object\". */\n modelName?: string | null\n /** Resolved propertyNames schema, used to surface key constraints like `format` for additional properties. */\n propertyNames?: SchemaObject\n eventBus?: WorkspaceEventBus | null\n /**\n * The row's name is a stand-in for keys the caller chooses\n * (`additionalProperties`) or keys matching a regex (`patternProperties`),\n * not a literal property. The heading says so in the signature line, where\n * the tree already describes shapes, instead of styling the name itself.\n */\n keyKind?: 'additional' | 'pattern'\n /**\n * The name of the schema this row loops back to. A cut cycle is a leaf, so\n * the signature line says why it does not expand; the model link beside it\n * already names the schema the loop returns to.\n */\n recursiveTo?: string\n }>(),\n {\n isDiscriminator: false,\n required: false,\n withExamples: true,\n hideModelNames: false,\n eventBus: null,\n },\n)\nconst { translate } = useLocalization()\n\n// Convert to reactive refs for composables\nconst valueRef = toRef(props, 'value')\n\nconst constValue = computed(() => {\n if (!valueRef.value) {\n return undefined\n }\n\n const schema = valueRef.value\n\n // Direct const value\n if (schema.const !== undefined) {\n return schema.const\n }\n\n // Single-item enum acts as const\n if (schema.enum?.length === 1) {\n return schema.enum[0]\n }\n\n // Check items for const values (for arrays)\n if (isArraySchema(schema) && schema.items) {\n const items = resolve.schema(schema.items)\n\n if (isDefined(items.const)) {\n return items.const\n }\n\n if (items.enum?.length === 1) {\n return items.enum[0]\n }\n }\n\n return undefined\n})\n\ntype ValidationProperty = {\n key: string\n value: string | number\n prefix?: string\n code?: boolean\n truncate?: boolean\n}\n\n/**\n * Constraints that live on a leaf (string or number) schema: length, pattern,\n * format and numeric ranges. Extracted so they can be surfaced for a primitive\n * schema as well as for a primitive array's items, which are not rendered on\n * their own. See https://github.com/scalar/scalar/issues/9690\n */\nconst getLeafConstraints = (schema: SchemaObject) => {\n const properties: ValidationProperty[] = []\n\n if (isStringSchema(schema)) {\n if (schema.minLength) {\n properties.push({\n key: 'min-length',\n prefix: `${translate('schema.minLength')}: `,\n value: schema.minLength,\n })\n }\n\n if (schema.maxLength) {\n properties.push({\n key: 'max-length',\n prefix: `${translate('schema.maxLength')}: `,\n value: schema.maxLength,\n })\n }\n\n // pattern is rendered via SchemaPropertyPattern (hover dropdown), skip here\n }\n\n if ((isStringSchema(schema) || isNumberSchema(schema)) && schema.format) {\n properties.push({\n key: 'format',\n value: schema.format,\n truncate: true,\n })\n }\n\n if (isNumberSchema(schema)) {\n if (isDefined(schema.exclusiveMinimum)) {\n properties.push({\n key: 'exclusive-minimum',\n prefix: `${translate('schema.greaterThan')}: `,\n value: schema.exclusiveMinimum,\n })\n }\n\n if (isDefined(schema.minimum)) {\n properties.push({\n key: 'minimum',\n prefix: `${translate('schema.min')}: `,\n value: schema.minimum,\n })\n }\n\n if (isDefined(schema.exclusiveMaximum)) {\n properties.push({\n key: 'exclusive-maximum',\n prefix: `${translate('schema.lessThan')}: `,\n value: schema.exclusiveMaximum,\n })\n }\n\n if (isDefined(schema.maximum)) {\n properties.push({\n key: 'maximum',\n prefix: `${translate('schema.max')}: `,\n value: schema.maximum,\n })\n }\n\n if (isDefined(schema.multipleOf)) {\n properties.push({\n key: 'multiple-of',\n prefix: `${translate('schema.multipleOf')}: `,\n value: schema.multipleOf,\n })\n }\n }\n\n return properties\n}\n\nconst validationProperties = computed(() => {\n if (!valueRef.value) {\n return []\n }\n\n const schema = valueRef.value\n const properties: ValidationProperty[] = []\n\n // Array validation properties\n if (isArraySchema(schema)) {\n if (schema.minItems || schema.maxItems) {\n properties.push({\n key: 'array-range',\n value: `${schema.minItems || ''}…${schema.maxItems || ''}`,\n })\n }\n\n // Unique items\n if (schema.uniqueItems) {\n properties.push({\n key: 'unique-items',\n value: `${translate('schema.unique')}!`,\n })\n }\n }\n\n properties.push(...getLeafConstraints(schema))\n\n // Primitive array items carry their own constraints (e.g. an array of `uuid`\n // strings) but are not rendered separately, so surface them here.\n if (isArraySchema(schema) && schema.items) {\n properties.push(...getLeafConstraints(resolve.schema(schema.items)))\n }\n\n return properties\n})\n\n/** Link data for navigating to the referenced model in the sidebar. */\nconst modelLink = computed(() => {\n if (!props.value) {\n return null\n }\n\n if (props.hideModelNames) {\n return null\n }\n\n if (props.modelName) {\n return { schemaKey: props.modelName, label: props.modelName }\n }\n\n return getModelNameWithArray(props.value)\n})\n\n/** Whether the model name links to the models section, or renders as plain text. */\nconst modelLinkable = computed(() =>\n isModelLinkable(modelLink.value?.schemaKey, props.modelLinkOptions ?? {}),\n)\n\n/**\n * The type as a run of tokens rather than a single string — identifiers in\n * the code face, English words like `array of` in the sans face, and a muted\n * `|` so `string | null` reads as one type with an alternative.\n *\n * The token run and the screen-reader label are written straight into the\n * template instead of being their own components: the tree mounts one per\n * typed row, and a component instance costs more to create than the span it\n * renders. On a flat object the type cells would be most of the instance\n * count. The linked and the plain copy of the token markup below must stay\n * identical.\n */\nconst signatureTokens = computed(() =>\n getDisplayTypeSignatureTokens(props.value, {\n hideModelNames: props.hideModelNames,\n modelName: modelLink.value?.label,\n }),\n)\n\n/** Check if we should show the type information */\nconst shouldShowType = computed(() => {\n if (!props.value || !('type' in props.value)) {\n return false\n }\n\n // Always show type for arrays, even when items have const values\n if (props.value.type === 'array') {\n return true\n }\n\n // For non-arrays, only show if no const value at the schema level\n return !constValue.value\n})\n\n/**\n * Type and format of the property keys, derived from the propertyNames schema.\n *\n * For a map keyed by UUIDs this renders e.g. \"string · uuid\" so the key\n * constraints are not lost. Returns undefined when there is nothing to show.\n */\nconst propertyNamesDetail = computed(() => {\n const schema = props.propertyNames\n if (!schema) {\n return undefined\n }\n\n const parts = [getSchemaType(schema)]\n if ('format' in schema && typeof schema.format === 'string') {\n parts.push(schema.format)\n }\n\n const detail = parts.filter(Boolean).join(' · ')\n return detail.length > 0 ? detail : undefined\n})\n\nconst exampleValue = computed(() => {\n // Treat only `undefined` as \"not set\" — `null` is a valid example value on a nullable schema.\n if (\n props.value &&\n 'example' in props.value &&\n props.value.example !== undefined\n ) {\n return props.value.example\n }\n\n if (props.value && isArraySchema(props.value)) {\n const itemsSchema = resolve.schema(props.value.items)\n if (\n itemsSchema &&\n 'example' in itemsSchema &&\n itemsSchema.example !== undefined\n ) {\n return itemsSchema.example\n }\n }\n\n return undefined\n})\n\n/**\n * Whether the examples chip has anything to render.\n *\n * `SchemaPropertyExamples` already renders nothing without an example, but it\n * still mounts, and mounting is what installs its popup's window-level click\n * and keydown listeners. `withExamples` defaults to true, so without this gate\n * every property row on the page — including a plain `{ type: 'string' }` —\n * pays for a popup it never opens. Mirrors the component's own two branches.\n */\nconst hasExampleContent = computed((): boolean => {\n if (exampleValue.value !== undefined) {\n return true\n }\n\n const examples = props.value?.examples\n\n return (\n !!examples &&\n typeof examples === 'object' &&\n Object.keys(examples).length > 0\n )\n})\n\n/**\n * The regex `pattern` to surface via the hover dropdown. It lives on a string\n * schema, or on the items of a primitive array (which is not rendered on its\n * own, so its constraints are surfaced on the array heading — see\n * https://github.com/scalar/scalar/issues/9690).\n */\nconst patternValue = computed(() => {\n const schema = valueRef.value\n if (!schema) {\n return undefined\n }\n\n if (isStringSchema(schema) && schema.pattern) {\n return schema.pattern\n }\n\n if (isArraySchema(schema) && schema.items) {\n const items = resolve.schema(schema.items)\n if (isStringSchema(items) && items.pattern) {\n return items.pattern\n }\n }\n\n return undefined\n})\n</script>\n<template>\n <div\n class=\"property-heading [&>.property-detail:has(+.property-detail)]:mr-0\">\n <!-- `:has(+.property-detail)`: only a detail FOLLOWED BY another detail\n drops its right margin, because the `·` separator supplies the gap\n there. Not `:not(:last-of-type)`, which matches by element type: the\n collapsed preview and the trailing copy-link are spans as well, so it\n would strip the margin from the final detail and glue \"Addressrequired\"\n together on a collapsed row. -->\n <div\n v-if=\"$slots.name\"\n class=\"property-name\"\n :class=\"{ deprecated: props.value?.deprecated }\">\n <slot name=\"name\" />\n </div>\n <div\n v-if=\"props.isDiscriminator\"\n class=\"property-discriminator\">\n {{ translate('schema.discriminator') }}\n </div>\n <template v-if=\"props.value\">\n <!-- A map key reads `additionalProperty · string`: the keyword leads the\n detail list in the accent colour, like a type word, so the name\n above it can look like every other name. -->\n <SchemaPropertyDetail\n v-if=\"props.keyKind\"\n class=\"property-key-kind\">\n <span class=\"font-code text-c-accent\">{{\n props.keyKind === 'pattern' ? 'patternProperty' : 'additionalProperty'\n }}</span>\n </SchemaPropertyDetail>\n <!-- Type information -->\n <SchemaPropertyDetail\n v-if=\"shouldShowType\"\n truncate>\n <!-- The type is a token run (`array of Planet`) and a $ref link IS the\n type, not an appended `· Account` -->\n <!-- Written across lines on purpose: Vue drops whitespace-only text\n between two elements, so a single-line label would read\n `Type:string`. -->\n <span class=\"screenreader-only\"> {{ translate('schema.type') }}: </span>\n <button\n v-if=\"props.eventBus && modelLink?.schemaKey && modelLinkable\"\n class=\"text-c-2 hover:text-c-1 underline\"\n type=\"button\"\n @click=\"\n props.eventBus.emit('scroll-to:model-by-name', {\n name: modelLink.schemaKey,\n })\n \">\n <span\n v-if=\"signatureTokens.length\"\n class=\"property-type-signature text-c-2 text-(length:--scalar-mini)\">\n <template\n v-for=\"(token, index) in signatureTokens\"\n :key=\"index\">\n {{ index > 0 ? ' ' : ''\n }}<span\n class=\"property-type-token\"\n :class=\"[\n `property-type-token--${token.kind}`,\n token.kind === 'word' ? 'font-sans' : '',\n token.kind === 'ident' || token.kind === 'literal'\n ? 'font-code'\n : '',\n token.kind === 'punctuation' ? 'text-c-2' : '',\n ]\"\n >{{ token.text }}</span\n >\n </template>\n </span>\n </button>\n <span\n v-else-if=\"signatureTokens.length\"\n class=\"property-type-signature text-c-2 text-(length:--scalar-mini)\">\n <template\n v-for=\"(token, index) in signatureTokens\"\n :key=\"index\">\n {{ index > 0 ? ' ' : ''\n }}<span\n class=\"property-type-token\"\n :class=\"[\n `property-type-token--${token.kind}`,\n token.kind === 'word' ? 'font-sans' : '',\n token.kind === 'ident' || token.kind === 'literal'\n ? 'font-code'\n : '',\n token.kind === 'punctuation' ? 'text-c-2' : '',\n ]\"\n >{{ token.text }}</span\n >\n </template>\n </span>\n </SchemaPropertyDetail>\n\n <!-- A cycle reads `array of Satellite · recursive`, a modifier like\n `nullable`; the full sentence rides the tooltip. -->\n <SchemaPropertyDetail\n v-if=\"props.recursiveTo\"\n class=\"property-recursive\"\n :title=\"\n translate('schema.recursiveReference', { name: props.recursiveTo })\n \">\n {{ translate('schema.recursive') }}\n </SchemaPropertyDetail>\n\n <!-- Key constraints from propertyNames (e.g. \"keys: string · uuid\") -->\n <SchemaPropertyDetail\n v-if=\"propertyNamesDetail\"\n truncate>\n <template #prefix>{{ translate('schema.keys') }}:</template>\n {{ propertyNamesDetail }}\n </SchemaPropertyDetail>\n\n <!-- Dynamic validation properties from composable -->\n <SchemaPropertyDetail\n v-for=\"property in validationProperties\"\n :key=\"property.key\"\n :code=\"property.code\"\n :truncate=\"property.truncate\">\n <span\n v-if=\"property.key === 'format'\"\n class=\"screenreader-only\">\n {{ translate('schema.format') }}:\n </span>\n <template\n v-if=\"property.prefix\"\n #prefix>\n {{ property.prefix }}\n </template>\n {{ property.value }}\n </SchemaPropertyDetail>\n\n <!-- Enum indicator -->\n <SchemaPropertyDetail v-if=\"props.enum\">\n {{ translate('schema.enum') }}\n </SchemaPropertyDetail>\n </template>\n <div\n v-if=\"props.additional\"\n class=\"property-additional\">\n <template v-if=\"props.value?.['x-additionalPropertiesName']\">\n {{ props.value['x-additionalPropertiesName'] }}\n </template>\n <template v-else>{{ translate('schema.additionalProperties') }}</template>\n </div>\n <div\n v-if=\"props.value?.deprecated\"\n class=\"property-deprecated\">\n <Badge>{{ translate('schema.deprecated') }}</Badge>\n </div>\n <span\n v-if=\"discriminatorValue !== undefined\"\n class=\"text-c-2\">\n {{ translate('schema.discriminatorValue') }}:\n <RenderString :value=\"discriminatorValue\" />\n </span>\n <!-- Don't use `isDefined` here, we want to show `const` when the value is `null` -->\n <div\n v-if=\"constValue !== undefined\"\n class=\"property-const\">\n <SchemaPropertyDetail truncate>\n <template #prefix>{{ translate('schema.const') }}: </template>\n <RenderString :value=\"constValue\" />\n </SchemaPropertyDetail>\n </div>\n <template v-else>\n <!-- Shows only when a composition is used (so props.value?.type is undefined) -->\n <SchemaPropertyDetail v-if=\"(props.value as any)?.nullable === true\">\n {{ translate('schema.nullable') }}\n </SchemaPropertyDetail>\n </template>\n <div\n v-if=\"props.value?.writeOnly\"\n class=\"property-write-only\">\n {{ translate('schema.writeOnly') }}\n </div>\n <div\n v-else-if=\"props.value?.readOnly\"\n class=\"property-read-only\">\n {{ translate('schema.readOnly') }}\n </div>\n <div\n v-if=\"props.required\"\n class=\"property-required\">\n {{ translate('schema.required') }}\n </div>\n <!-- Gated here, not only inside the component: each popup instance installs\n window-level click and keydown listeners for its dismissal, so mounting\n one per row costs the page a listener per row it never shows anything\n for. Same reason `SchemaPropertyPattern` below is gated. -->\n <SchemaPropertyDefault\n v-if=\"props.value?.default !== undefined\"\n :value=\"props.value?.default\" />\n <!--\n Pattern is a hover dropdown chip like Examples, not an inline constraint,\n so it sits beside the example. This keeps the real constraints (length,\n nullable, …) together in the dotted list. See #9966.\n -->\n <SchemaPropertyPattern\n v-if=\"patternValue\"\n :pattern=\"patternValue\" />\n <SchemaPropertyExamples\n v-if=\"props.withExamples && hasExampleContent\"\n :example=\"exampleValue\"\n :examples=\"props.value?.examples\" />\n <!-- The collapsed preview rides the end of the heading line -->\n <slot name=\"preview\" />\n <!-- Last so the tab order matches the visual order: the trailing copy-link\n is painted at the row's right edge, after every control to its left -->\n <slot name=\"trailing\" />\n </div>\n</template>\n<style scoped>\n.property-heading {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n row-gap: 9px;\n white-space: nowrap;\n}\n\n.property-heading:has(+ .children),\n.property-heading:has(+ .property-rule) {\n margin-bottom: 9px;\n}\n\n.property-heading > * {\n margin-right: 9px;\n}\n\n.property-heading:last-child {\n margin-right: 0;\n}\n\n.property-name {\n max-width: 100%;\n font-family: var(--scalar-font-code);\n font-weight: var(--scalar-bold);\n font-size: var(--scalar-font-size-4);\n white-space: normal;\n overflow-wrap: break-word;\n}\n\n.property-additional {\n font-family: var(--scalar-font-code);\n}\n\n.property-required,\n.property-optional {\n color: var(--scalar-color-2);\n}\n\n.property-required {\n font-size: var(--scalar-mini);\n color: var(--scalar-color-orange);\n}\n/*\n * Light-mode oranges are too bright on a light page for 13px text (the default\n * #ff5800 is 3.16:1), so blend the theme orange toward the text colour to reach\n * WCAG 1.4.3 (4.5:1) while keeping the hue and letting custom themes flow\n * through. Dark mode already passes (8.37:1) and keeps the plain token.\n */\n.light-mode .property-required {\n color: color-mix(\n in srgb,\n var(--scalar-color-orange),\n var(--scalar-color-1) 32%\n );\n}\n\n.property-read-only {\n font-size: var(--scalar-mini);\n color: var(--scalar-color-blue);\n}\n\n.property-write-only {\n font-size: var(--scalar-mini);\n color: var(--scalar-color-green);\n}\n\n.property-discriminator {\n font-size: var(--scalar-mini);\n color: var(--scalar-color-purple);\n}\n\n.property-detail {\n font-size: var(--scalar-mini);\n color: var(--scalar-color-2);\n display: flex;\n align-items: center;\n\n min-width: 0;\n}\n\n.property-const {\n color: var(--scalar-color-1);\n}\n\n.deprecated {\n text-decoration: line-through;\n}\n</style>\n"],"mappings":""}