Skip to content
edmi-ui

Schema Display

API endpoint with method badge, path, parameters and nested request and response schemas.

StackBlitz ↗StackBlitz ↗StackBlitz ↗
POST/v1/indexes/{id}/rebalance

Rebalance an index back to its target weights.

idstringpathrequiredIndex id
maxSlippagenumber0–0.05
dryRunbooleanQuote only
symbolstring
amountnumber
driftnumber
GET
POST
PUT
PATCH
DELETE
POST/v1/indexes/{id}/rebalance

Rebalance an index back to its target weights.

idstring
path
required
Index id
maxSlippagenumber0–0.05
dryRunbooleanQuote only
symbolstring
amountnumber
driftnumber
GET
POST
PUT
PATCH
DELETE
POST /v1/indexes/{id}/rebalance

Rebalance an index back to its target weights.

id string path required Index id
maxSlippage number 0–0.05
dryRun boolean Quote only
symbol string
amount number
drift number
GET
POST
PUT
PATCH
DELETE

Built on collapsible and badge.

Terminal window
npx shadcn@latest add @edmi-ui/ai-schema-display
Terminal window
pnpm dlx shadcn@latest add @edmi-ui/ai-schema-display
Terminal window
yarn dlx shadcn@latest add @edmi-ui/ai-schema-display
Terminal window
bunx shadcn@latest add @edmi-ui/ai-schema-display

Pick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.

Terminal window
npx shadcn-vue@latest add @edmi-ui/ai-schema-display
Terminal window
pnpm dlx shadcn-vue@latest add @edmi-ui/ai-schema-display
Terminal window
yarn dlx shadcn-vue@latest add @edmi-ui/ai-schema-display
Terminal window
bunx shadcn-vue@latest add @edmi-ui/ai-schema-display

Pick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.

Terminal window
npx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/ai-schema-display.json
Terminal window
pnpm dlx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/ai-schema-display.json
Terminal window
yarn dlx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/ai-schema-display.json
Terminal window
bunx --bun shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/ai-schema-display.json

Pick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.

import { SchemaDisplay } from "@/components/ai/schema-display";
<div className="flex w-full max-w-xl flex-col gap-5">
<SchemaDisplay
description="Rebalance an index back to its target weights."
method="POST"
parameters={[
{
description: "Index id",
location: "path",
name: "id",
required: true,
type: "string",
},
]}
path="/v1/indexes/{id}/rebalance"
requestBody={[
{ description: "0–0.05", name: "maxSlippage", type: "number" },
{ description: "Quote only", name: "dryRun", type: "boolean" },
]}
responseBody={[
{
name: "trades",
properties: [
{ name: "symbol", type: "string" },
{ name: "amount", type: "number" },
],
type: "object[]",
},
{ name: "drift", type: "number" },
]}
/>
{/* … */}
</div>
<script setup lang="ts">
import {
SchemaDisplay,
SchemaDisplayMethod,
} from "@/components/ai/schema-display";
</script>
<template>
<div class="flex w-full max-w-xl flex-col gap-5">
<SchemaDisplay
description="Rebalance an index back to its target weights."
method="POST"
path="/v1/indexes/{id}/rebalance"
/>
<div class="flex flex-wrap items-center gap-1.5">
<SchemaDisplay
:key="method"
class="inline-flex border-0 bg-transparent"
:method="method"
path=""
>
<SchemaDisplayMethod />
</SchemaDisplay>
</div>
</div>
</template>
<script lang="ts">
import {
SchemaDisplay,
SchemaDisplayMethod,
} from "$lib/components/ai/schema-display";
</script>
<div class="flex w-full max-w-xl flex-col gap-5">
<SchemaDisplay
description="Rebalance an index back to its target weights."
method="POST"
path="/v1/indexes/{'{id}'}/rebalance"
/>
<div class="flex flex-wrap items-center gap-1.5">
{#each methods as method (method)}
<SchemaDisplay class="inline-flex border-0 bg-transparent" {method} path="">
<SchemaDisplayMethod />
</SchemaDisplay>
{/each}
</div>
</div>
registry/components/ai/schema-display.tsx
"use client";
import { cn } from "cn";
import type { ComponentProps, HTMLAttributes } from "react";
import { createContext, useContext, useMemo } from "react";
import { CaretDownIcon } from "@phosphor-icons/react";
import { Badge } from "@/registry/edmi/ui/badge";
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "@/registry/edmi/ui/collapsible";
type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
interface SchemaParameter {
name: string;
type: string;
required?: boolean;
description?: string;
location?: "path" | "query" | "header";
}
interface SchemaProperty {
name: string;
type: string;
required?: boolean;
description?: string;
properties?: SchemaProperty[];
items?: SchemaProperty;
}
interface SchemaDisplayContextType {
method: HttpMethod;
path: string;
description?: string;
parameters?: SchemaParameter[];
requestBody?: SchemaProperty[];
responseBody?: SchemaProperty[];
}
const SchemaDisplayContext = createContext<SchemaDisplayContextType>({
method: "GET",
path: "",
});
// Solid soft fills, never /NN opacity (DESIGN §4.16). GET success, POST info, PUT/PATCH warning, DELETE destructive.
const methodStyles: Record<HttpMethod, string> = {
DELETE: "bg-destructive-soft text-destructive-text",
GET: "bg-success-soft text-success-text",
PATCH: "bg-warning-soft text-warning-text",
POST: "bg-info-soft text-info-text",
PUT: "bg-warning-soft text-warning-text",
};
const sectionTrigger =
"group/ai-schema-trigger flex w-full items-center gap-2 px-4 py-2 text-left text-[13.5px] text-muted-foreground outline-none transition-colors hover:text-foreground focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-ring";
const sectionChevron =
"size-3.5 shrink-0 transition-transform group-data-[panel-open]/ai-schema-trigger:rotate-180";
const panel =
"h-(--collapsible-panel-height) overflow-hidden transition-[height] duration-200 ease-out data-[ending-style]:h-0 data-[starting-style]:h-0";
const RequiredBadge = () => (
<Badge className="h-[18px] text-[10.5px]" variant="warning">
required
</Badge>
);
const SectionChevron = ({ className }: { className?: string }) => (
<CaretDownIcon
className={cn(sectionChevron, className)}
/>
);
export type SchemaDisplayHeaderProps = HTMLAttributes<HTMLDivElement>;
export const SchemaDisplayHeader = ({
className,
children,
...props
}: SchemaDisplayHeaderProps) => (
<div
data-slot="ai-schema-display-header"
className={cn("flex items-center gap-2.5 px-4 py-3.5", className)}
{...props}
>
{children}
</div>
);
export type SchemaDisplayMethodProps = HTMLAttributes<HTMLSpanElement>;
export const SchemaDisplayMethod = ({
className,
children,
...props
}: SchemaDisplayMethodProps) => {
const { method } = useContext(SchemaDisplayContext);
return (
<span
data-slot="ai-schema-display-method"
data-method={method}
className={cn(
"inline-flex rounded-[5px] px-[7px] py-0.5 font-mono text-[11px] font-semibold",
methodStyles[method],
className,
)}
{...props}
>
{children ?? method}
</span>
);
};
const PATH_PARAM = /(\{[^}]+\})/g;
export type SchemaDisplayPathProps = HTMLAttributes<HTMLSpanElement>;
export const SchemaDisplayPath = ({
className,
children,
...props
}: SchemaDisplayPathProps) => {
const { path } = useContext(SchemaDisplayContext);
return (
<span
data-slot="ai-schema-display-path"
className={cn("font-mono text-[13.5px]", className)}
{...props}
>
{children ??
path.split(PATH_PARAM).map((part, index) =>
part.startsWith("{") ? (
// biome-ignore lint/suspicious/noArrayIndexKey: static split of the path string
<span className="text-chart-2" key={`${part}-${index}`}>
{part}
</span>
) : (
part
),
)}
</span>
);
};
export type SchemaDisplayDescriptionProps =
HTMLAttributes<HTMLParagraphElement>;
export const SchemaDisplayDescription = ({
className,
children,
...props
}: SchemaDisplayDescriptionProps) => {
const { description } = useContext(SchemaDisplayContext);
return (
<p
data-slot="ai-schema-display-description"
className={cn(
"-mt-2 px-4 pb-3.5 text-xs text-muted-foreground",
className,
)}
{...props}
>
{children ?? description}
</p>
);
};
export type SchemaDisplayContentProps = HTMLAttributes<HTMLDivElement>;
export const SchemaDisplayContent = ({
className,
children,
...props
}: SchemaDisplayContentProps) => (
<div
data-slot="ai-schema-display-content"
className={cn(
"divide-y divide-border-2 border-t border-border-2",
className,
)}
{...props}
>
{children}
</div>
);
export type SchemaDisplayParameterProps = HTMLAttributes<HTMLDivElement> &
SchemaParameter;
export const SchemaDisplayParameter = ({
name,
type,
required,
description,
location,
className,
...props
}: SchemaDisplayParameterProps) => (
<div
data-slot="ai-schema-display-parameter"
className={cn("flex items-center gap-2 py-1.5 text-[12.5px]", className)}
{...props}
>
<span className="font-mono font-medium">{name}</span>
<span className="font-mono text-muted-foreground">{type}</span>
{location && (
<Badge className="h-[18px] text-[10.5px]" variant="secondary">
{location}
</Badge>
)}
{required && <RequiredBadge />}
{description && (
<span className="ml-auto text-right text-xs text-muted-foreground">
{description}
</span>
)}
</div>
);
export type SchemaDisplayParametersProps = ComponentProps<typeof Collapsible>;
export const SchemaDisplayParameters = ({
className,
children,
...props
}: SchemaDisplayParametersProps) => {
const { parameters } = useContext(SchemaDisplayContext);
return (
<Collapsible
data-slot="ai-schema-display-parameters"
className={className}
defaultOpen
{...props}
>
<CollapsibleTrigger className={sectionTrigger}>
<SectionChevron />
<span>Parameters</span>
</CollapsibleTrigger>
<CollapsibleContent className={panel}>
<div className="px-4 pb-2.5">
{children ??
parameters?.map((param) => (
<SchemaDisplayParameter key={param.name} {...param} />
))}
</div>
</CollapsibleContent>
</Collapsible>
);
};
export type SchemaDisplayPropertyProps = HTMLAttributes<HTMLDivElement> &
SchemaProperty & {
depth?: number;
};
export const SchemaDisplayProperty = ({
name,
type,
required,
description,
properties,
items,
depth = 0,
className,
...props
}: SchemaDisplayPropertyProps) => {
const hasChildren = properties || items;
const paddingLeft = depth * 16;
if (hasChildren) {
return (
<Collapsible defaultOpen={depth < 2}>
<CollapsibleTrigger
className={cn(
"group/ai-schema-property flex w-full items-center gap-2 py-1.5 text-left text-[12.5px] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring",
className,
)}
style={{ paddingLeft }}
>
<CaretDownIcon
className="size-3.5 shrink-0 -rotate-90 text-muted-foreground transition-transform group-data-[panel-open]/ai-schema-property:rotate-0"
/>
<span className="font-mono font-medium">{name}</span>
<span className="font-mono text-muted-foreground">{type}</span>
{required && <RequiredBadge />}
{description && (
<span className="ml-auto text-right text-xs text-muted-foreground">
{description}
</span>
)}
</CollapsibleTrigger>
<CollapsibleContent className={panel}>
<div>
{properties?.map((prop) => (
<SchemaDisplayProperty
key={prop.name}
{...prop}
depth={depth + 1}
/>
))}
{items && (
<SchemaDisplayProperty
{...items}
depth={depth + 1}
name={`${name}[]`}
/>
)}
</div>
</CollapsibleContent>
</Collapsible>
);
}
return (
<div
data-slot="ai-schema-display-property"
className={cn("flex items-center gap-2 py-1.5 text-[12.5px]", className)}
style={{ paddingLeft: paddingLeft + (depth > 0 ? 22 : 0) }}
{...props}
>
<span className="font-mono font-medium">{name}</span>
<span className="font-mono text-muted-foreground">{type}</span>
{required && <RequiredBadge />}
{description && (
<span className="ml-auto text-right text-xs text-muted-foreground">
{description}
</span>
)}
</div>
);
};
export type SchemaDisplayRequestProps = ComponentProps<typeof Collapsible>;
export const SchemaDisplayRequest = ({
className,
children,
...props
}: SchemaDisplayRequestProps) => {
const { requestBody } = useContext(SchemaDisplayContext);
return (
<Collapsible
data-slot="ai-schema-display-request"
className={className}
defaultOpen
{...props}
>
<CollapsibleTrigger className={sectionTrigger}>
<SectionChevron />
<span>Request body</span>
</CollapsibleTrigger>
<CollapsibleContent className={panel}>
<div className="px-4 pb-2.5">
{children ??
requestBody?.map((prop) => (
<SchemaDisplayProperty key={prop.name} {...prop} depth={0} />
))}
</div>
</CollapsibleContent>
</Collapsible>
);
};
export type SchemaDisplayResponseProps = ComponentProps<typeof Collapsible>;
export const SchemaDisplayResponse = ({
className,
children,
...props
}: SchemaDisplayResponseProps) => {
const { responseBody } = useContext(SchemaDisplayContext);
return (
<Collapsible
data-slot="ai-schema-display-response"
className={className}
defaultOpen
{...props}
>
<CollapsibleTrigger className={sectionTrigger}>
<SectionChevron />
<span>Response</span>
</CollapsibleTrigger>
<CollapsibleContent className={panel}>
<div className="px-4 pb-2.5">
{children ??
responseBody?.map((prop) => (
<SchemaDisplayProperty key={prop.name} {...prop} depth={0} />
))}
</div>
</CollapsibleContent>
</Collapsible>
);
};
export type SchemaDisplayProps = HTMLAttributes<HTMLDivElement> & {
method: HttpMethod;
path: string;
description?: string;
parameters?: SchemaParameter[];
requestBody?: SchemaProperty[];
responseBody?: SchemaProperty[];
};
export const SchemaDisplay = ({
method,
path,
description,
parameters,
requestBody,
responseBody,
className,
children,
...props
}: SchemaDisplayProps) => {
const contextValue = useMemo(
() => ({
description,
method,
parameters,
path,
requestBody,
responseBody,
}),
[description, method, parameters, path, requestBody, responseBody],
);
return (
<SchemaDisplayContext.Provider value={contextValue}>
<div
data-slot="ai-schema-display"
className={cn(
"overflow-hidden rounded-xl border border-border bg-card",
className,
)}
{...props}
>
{children ?? (
<>
<SchemaDisplayHeader>
<SchemaDisplayMethod />
<SchemaDisplayPath />
</SchemaDisplayHeader>
{description && <SchemaDisplayDescription />}
<SchemaDisplayContent>
{parameters && parameters.length > 0 && (
<SchemaDisplayParameters />
)}
{requestBody && requestBody.length > 0 && (
<SchemaDisplayRequest />
)}
{responseBody && responseBody.length > 0 && (
<SchemaDisplayResponse />
)}
</SchemaDisplayContent>
</>
)}
</div>
</SchemaDisplayContext.Provider>
);
};
export type SchemaDisplayBodyProps = HTMLAttributes<HTMLDivElement>;
export const SchemaDisplayBody = ({
className,
children,
...props
}: SchemaDisplayBodyProps) => (
<div className={cn("divide-y divide-border-2", className)} {...props}>
{children}
</div>
);
export type SchemaDisplayExampleProps = HTMLAttributes<HTMLPreElement>;
export const SchemaDisplayExample = ({
className,
children,
...props
}: SchemaDisplayExampleProps) => (
<pre
data-slot="ai-schema-display-example"
className={cn(
"mx-4 mb-3.5 overflow-auto rounded-md bg-muted px-3 py-2.5 font-mono text-xs leading-[1.6]",
className,
)}
{...props}
>
{children}
</pre>
);
registry/components/ai/schema-display/SchemaDisplay.vue
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import type { HttpMethod, SchemaParameter, SchemaProperty } from "./context"
import { computed, provide } from "vue"
import { cn } from "@/registry/edmi/lib/utils"
import { SchemaDisplayKey } from "./context"
import SchemaDisplayContent from "./SchemaDisplayContent.vue"
import SchemaDisplayDescription from "./SchemaDisplayDescription.vue"
import SchemaDisplayHeader from "./SchemaDisplayHeader.vue"
import SchemaDisplayMethod from "./SchemaDisplayMethod.vue"
import SchemaDisplayParameters from "./SchemaDisplayParameters.vue"
import SchemaDisplayPath from "./SchemaDisplayPath.vue"
import SchemaDisplayRequest from "./SchemaDisplayRequest.vue"
import SchemaDisplayResponse from "./SchemaDisplayResponse.vue"
const props = defineProps<{
method: HttpMethod
path: string
description?: string
parameters?: SchemaParameter[]
requestBody?: SchemaProperty[]
responseBody?: SchemaProperty[]
class?: HTMLAttributes["class"]
}>()
provide(SchemaDisplayKey, {
method: computed(() => props.method),
path: computed(() => props.path),
description: computed(() => props.description),
parameters: computed(() => props.parameters),
requestBody: computed(() => props.requestBody),
responseBody: computed(() => props.responseBody),
})
</script>
<template>
<div
data-slot="ai-schema-display"
:class="cn('overflow-hidden rounded-xl border border-border bg-card', props.class)"
>
<slot>
<SchemaDisplayHeader>
<SchemaDisplayMethod />
<SchemaDisplayPath />
</SchemaDisplayHeader>
<SchemaDisplayDescription v-if="props.description" />
<SchemaDisplayContent>
<SchemaDisplayParameters v-if="props.parameters?.length" />
<SchemaDisplayRequest v-if="props.requestBody?.length" />
<SchemaDisplayResponse v-if="props.responseBody?.length" />
</SchemaDisplayContent>
</slot>
</div>
</template>
registry/components/ai/schema-display/SchemaDisplayBody.vue
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/registry/edmi/lib/utils"
const props = defineProps<{
class?: HTMLAttributes["class"]
}>()
</script>
<template>
<div :class="cn('divide-y divide-border-2', props.class)">
<slot />
</div>
</template>
registry/components/ai/schema-display/SchemaDisplayContent.vue
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/registry/edmi/lib/utils"
const props = defineProps<{
class?: HTMLAttributes["class"]
}>()
</script>
<template>
<div
data-slot="ai-schema-display-content"
:class="cn('divide-y divide-border-2 border-t border-border-2', props.class)"
>
<slot />
</div>
</template>
registry/components/ai/schema-display/SchemaDisplayDescription.vue
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/registry/edmi/lib/utils"
import { useSchemaDisplayContext } from "./context"
const props = defineProps<{
class?: HTMLAttributes["class"]
}>()
const { description } = useSchemaDisplayContext("SchemaDisplayDescription")
</script>
<template>
<p
data-slot="ai-schema-display-description"
:class="cn('-mt-2 px-4 pb-3.5 text-xs text-muted-foreground', props.class)"
>
<slot>{{ description }}</slot>
</p>
</template>
registry/components/ai/schema-display/SchemaDisplayExample.vue
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/registry/edmi/lib/utils"
const props = defineProps<{
class?: HTMLAttributes["class"]
}>()
</script>
<template>
<pre
data-slot="ai-schema-display-example"
:class="cn('mx-4 mb-3.5 overflow-auto rounded-md bg-muted px-3 py-2.5 font-mono text-xs leading-[1.6]', props.class)"
><slot /></pre>
</template>
registry/components/ai/schema-display/SchemaDisplayHeader.vue
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/registry/edmi/lib/utils"
const props = defineProps<{
class?: HTMLAttributes["class"]
}>()
</script>
<template>
<div
data-slot="ai-schema-display-header"
:class="cn('flex items-center gap-2.5 px-4 py-3.5', props.class)"
>
<slot />
</div>
</template>
registry/components/ai/schema-display/SchemaDisplayMethod.vue
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import type { HttpMethod } from "./context"
import { cn } from "@/registry/edmi/lib/utils"
import { useSchemaDisplayContext } from "./context"
const props = defineProps<{
class?: HTMLAttributes["class"]
}>()
const { method } = useSchemaDisplayContext("SchemaDisplayMethod")
// Solid soft fills, never /NN opacity (DESIGN §4.16). GET success, POST info, PUT/PATCH warning, DELETE destructive.
const methodStyles: Record<HttpMethod, string> = {
DELETE: "bg-destructive-soft text-destructive-text",
GET: "bg-success-soft text-success-text",
PATCH: "bg-warning-soft text-warning-text",
POST: "bg-info-soft text-info-text",
PUT: "bg-warning-soft text-warning-text",
}
</script>
<template>
<span
data-slot="ai-schema-display-method"
:data-method="method"
:class="cn(
'inline-flex rounded-[5px] px-[7px] py-0.5 font-mono text-[11px] font-semibold',
methodStyles[method],
props.class,
)"
>
<slot>{{ method }}</slot>
</span>
</template>
registry/components/ai/schema-display/SchemaDisplayParameter.vue
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/registry/edmi/lib/utils"
import { Badge } from "@/registry/edmi/ui/badge"
const props = defineProps<{
name: string
type: string
required?: boolean
description?: string
location?: "path" | "query" | "header"
class?: HTMLAttributes["class"]
}>()
</script>
<template>
<div
data-slot="ai-schema-display-parameter"
:class="cn('flex items-center gap-2 py-1.5 text-[12.5px]', props.class)"
>
<span class="font-mono font-medium">{{ props.name }}</span>
<span class="font-mono text-muted-foreground">{{ props.type }}</span>
<Badge v-if="props.location" class="h-[18px] text-[10.5px]" variant="secondary">
{{ props.location }}
</Badge>
<Badge v-if="props.required" class="h-[18px] text-[10.5px]" variant="warning">
required
</Badge>
<span v-if="props.description" class="ml-auto text-right text-xs text-muted-foreground">{{ props.description }}</span>
</div>
</template>
registry/components/ai/schema-display/SchemaDisplayParameters.vue
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { useSchemaDisplayContext } from "./context"
import SchemaDisplayParameter from "./SchemaDisplayParameter.vue"
import SchemaDisplaySection from "./SchemaDisplaySection.vue"
const props = withDefaults(defineProps<{
defaultOpen?: boolean
class?: HTMLAttributes["class"]
}>(), {
defaultOpen: true,
})
const { parameters } = useSchemaDisplayContext("SchemaDisplayParameters")
</script>
<template>
<SchemaDisplaySection
data-slot="ai-schema-display-parameters"
title="Parameters"
:default-open="props.defaultOpen"
:class="props.class"
>
<slot>
<SchemaDisplayParameter v-for="param in parameters" :key="param.name" v-bind="param" />
</slot>
</SchemaDisplaySection>
</template>
registry/components/ai/schema-display/SchemaDisplayPath.vue
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { computed } from "vue"
import { cn } from "@/registry/edmi/lib/utils"
import { useSchemaDisplayContext } from "./context"
const props = defineProps<{
class?: HTMLAttributes["class"]
}>()
const { path } = useSchemaDisplayContext("SchemaDisplayPath")
// `{param}` segments are highlighted; everything else is plain text.
const parts = computed(() =>
path.value.split(/(\{[^}]+\})/g).filter(Boolean).map(text => ({ text, param: text.startsWith("{") })))
</script>
<template>
<span
data-slot="ai-schema-display-path"
:class="cn('font-mono text-[13.5px]', props.class)"
>
<slot>
<template v-for="(part, index) in parts" :key="`${part.text}-${index}`">
<span v-if="part.param" class="text-chart-2">{{ part.text }}</span>
<template v-else>{{ part.text }}</template>
</template>
</slot>
</span>
</template>
registry/components/ai/schema-display/SchemaDisplayProperty.vue
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import type { SchemaProperty } from "./context"
import { ChevronDownIcon } from "@lucide/vue"
import { computed } from "vue"
import { cn } from "@/registry/edmi/lib/utils"
import { Badge } from "@/registry/edmi/ui/badge"
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/registry/edmi/ui/collapsible"
const props = withDefaults(defineProps<{
name: string
type: string
required?: boolean
description?: string
properties?: SchemaProperty[]
items?: SchemaProperty
depth?: number
class?: HTMLAttributes["class"]
}>(), {
depth: 0,
})
const hasChildren = computed(() => !!props.properties || !!props.items)
const paddingLeft = computed(() => props.depth * 16)
</script>
<template>
<Collapsible v-if="hasChildren" :default-open="props.depth < 2">
<CollapsibleTrigger
:class="cn(
'group/ai-schema-property flex w-full items-center gap-2 py-1.5 text-left text-[12.5px] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring',
props.class,
)"
:style="{ paddingLeft: `${paddingLeft}px` }"
>
<ChevronDownIcon class="size-3.5 shrink-0 -rotate-90 text-muted-foreground transition-transform group-data-[state=open]/ai-schema-property:rotate-0" />
<span class="font-mono font-medium">{{ props.name }}</span>
<span class="font-mono text-muted-foreground">{{ props.type }}</span>
<Badge v-if="props.required" class="h-[18px] text-[10.5px]" variant="warning">
required
</Badge>
<span v-if="props.description" class="ml-auto text-right text-xs text-muted-foreground">{{ props.description }}</span>
</CollapsibleTrigger>
<CollapsibleContent class="overflow-hidden">
<div>
<SchemaDisplayProperty
v-for="prop in props.properties"
:key="prop.name"
v-bind="prop"
:depth="props.depth + 1"
/>
<SchemaDisplayProperty
v-if="props.items"
v-bind="props.items"
:depth="props.depth + 1"
:name="`${props.name}[]`"
/>
</div>
</CollapsibleContent>
</Collapsible>
<div
v-else
data-slot="ai-schema-display-property"
:class="cn('flex items-center gap-2 py-1.5 text-[12.5px]', props.class)"
:style="{ paddingLeft: `${paddingLeft + (props.depth > 0 ? 22 : 0)}px` }"
>
<span class="font-mono font-medium">{{ props.name }}</span>
<span class="font-mono text-muted-foreground">{{ props.type }}</span>
<Badge v-if="props.required" class="h-[18px] text-[10.5px]" variant="warning">
required
</Badge>
<span v-if="props.description" class="ml-auto text-right text-xs text-muted-foreground">{{ props.description }}</span>
</div>
</template>
registry/components/ai/schema-display/SchemaDisplayRequest.vue
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { useSchemaDisplayContext } from "./context"
import SchemaDisplayProperty from "./SchemaDisplayProperty.vue"
import SchemaDisplaySection from "./SchemaDisplaySection.vue"
const props = withDefaults(defineProps<{
defaultOpen?: boolean
class?: HTMLAttributes["class"]
}>(), {
defaultOpen: true,
})
const { requestBody } = useSchemaDisplayContext("SchemaDisplayRequest")
</script>
<template>
<SchemaDisplaySection
data-slot="ai-schema-display-request"
title="Request body"
:default-open="props.defaultOpen"
:class="props.class"
>
<slot>
<SchemaDisplayProperty v-for="prop in requestBody" :key="prop.name" v-bind="prop" :depth="0" />
</slot>
</SchemaDisplaySection>
</template>
registry/components/ai/schema-display/SchemaDisplayResponse.vue
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { useSchemaDisplayContext } from "./context"
import SchemaDisplayProperty from "./SchemaDisplayProperty.vue"
import SchemaDisplaySection from "./SchemaDisplaySection.vue"
const props = withDefaults(defineProps<{
defaultOpen?: boolean
class?: HTMLAttributes["class"]
}>(), {
defaultOpen: true,
})
const { responseBody } = useSchemaDisplayContext("SchemaDisplayResponse")
</script>
<template>
<SchemaDisplaySection
data-slot="ai-schema-display-response"
title="Response"
:default-open="props.defaultOpen"
:class="props.class"
>
<slot>
<SchemaDisplayProperty v-for="prop in responseBody" :key="prop.name" v-bind="prop" :depth="0" />
</slot>
</SchemaDisplaySection>
</template>
registry/components/ai/schema-display/SchemaDisplaySection.vue
<script setup lang="ts">
// Shared collapsible section (title + body) behind Parameters, Request and Response.
import type { HTMLAttributes } from "vue"
import { ChevronDownIcon } from "@lucide/vue"
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/registry/edmi/ui/collapsible"
const props = withDefaults(defineProps<{
title: string
defaultOpen?: boolean
class?: HTMLAttributes["class"]
}>(), {
defaultOpen: true,
})
</script>
<template>
<Collapsible :class="props.class" :default-open="props.defaultOpen">
<CollapsibleTrigger class="group/ai-schema-trigger flex w-full items-center gap-2 px-4 py-2 text-left text-[13.5px] text-muted-foreground outline-none transition-colors hover:text-foreground focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-ring">
<ChevronDownIcon class="size-3.5 shrink-0 transition-transform group-data-[state=open]/ai-schema-trigger:rotate-180" />
<span>{{ props.title }}</span>
</CollapsibleTrigger>
<CollapsibleContent class="overflow-hidden">
<div class="px-4 pb-2.5">
<slot />
</div>
</CollapsibleContent>
</Collapsible>
</template>
registry/components/ai/schema-display/context.ts
import type { ComputedRef, InjectionKey } from "vue";
import { inject } from "vue";
export type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
export interface SchemaParameter {
name: string;
type: string;
required?: boolean;
description?: string;
location?: "path" | "query" | "header";
}
export interface SchemaProperty {
name: string;
type: string;
required?: boolean;
description?: string;
properties?: SchemaProperty[];
items?: SchemaProperty;
}
export interface SchemaDisplayContextValue {
method: ComputedRef<HttpMethod>;
path: ComputedRef<string>;
description: ComputedRef<string | undefined>;
parameters: ComputedRef<SchemaParameter[] | undefined>;
requestBody: ComputedRef<SchemaProperty[] | undefined>;
responseBody: ComputedRef<SchemaProperty[] | undefined>;
}
export const SchemaDisplayKey: InjectionKey<SchemaDisplayContextValue> = Symbol(
"SchemaDisplayContext",
);
export function useSchemaDisplayContext(
componentName: string,
): SchemaDisplayContextValue {
const context = inject(SchemaDisplayKey);
if (!context) {
throw new Error(`${componentName} must be used within SchemaDisplay`);
}
return context;
}
registry/components/ai/schema-display/index.ts
export type {
HttpMethod,
SchemaParameter,
SchemaProperty,
} from "./context";
export { default as SchemaDisplay } from "./SchemaDisplay.vue";
export { default as SchemaDisplayBody } from "./SchemaDisplayBody.vue";
export { default as SchemaDisplayContent } from "./SchemaDisplayContent.vue";
export { default as SchemaDisplayDescription } from "./SchemaDisplayDescription.vue";
export { default as SchemaDisplayExample } from "./SchemaDisplayExample.vue";
export { default as SchemaDisplayHeader } from "./SchemaDisplayHeader.vue";
export { default as SchemaDisplayMethod } from "./SchemaDisplayMethod.vue";
export { default as SchemaDisplayParameter } from "./SchemaDisplayParameter.vue";
export { default as SchemaDisplayParameters } from "./SchemaDisplayParameters.vue";
export { default as SchemaDisplayPath } from "./SchemaDisplayPath.vue";
export { default as SchemaDisplayProperty } from "./SchemaDisplayProperty.vue";
export { default as SchemaDisplayRequest } from "./SchemaDisplayRequest.vue";
export { default as SchemaDisplayResponse } from "./SchemaDisplayResponse.vue";
src/lib/registry/ai/schema-display/index.ts
import SchemaDisplay from "./schema-display.svelte";
import SchemaDisplayBody from "./schema-display-body.svelte";
import SchemaDisplayContent from "./schema-display-content.svelte";
import SchemaDisplayDescription from "./schema-display-description.svelte";
import SchemaDisplayExample from "./schema-display-example.svelte";
import SchemaDisplayHeader from "./schema-display-header.svelte";
import SchemaDisplayMethod from "./schema-display-method.svelte";
import SchemaDisplayParameter from "./schema-display-parameter.svelte";
import SchemaDisplayParameters from "./schema-display-parameters.svelte";
import SchemaDisplayPath from "./schema-display-path.svelte";
import SchemaDisplayProperty from "./schema-display-property.svelte";
import SchemaDisplayRequest from "./schema-display-request.svelte";
import SchemaDisplayResponse from "./schema-display-response.svelte";
export type {
HttpMethod,
SchemaParameter,
SchemaProperty,
} from "./use-schema-display.svelte.js";
export {
SchemaDisplay,
SchemaDisplayBody,
SchemaDisplayContent,
SchemaDisplayDescription,
SchemaDisplayExample,
SchemaDisplayHeader,
SchemaDisplayMethod,
SchemaDisplayParameter,
SchemaDisplayParameters,
SchemaDisplayPath,
SchemaDisplayProperty,
SchemaDisplayRequest,
SchemaDisplayResponse,
};
src/lib/registry/ai/schema-display/schema-display-body.svelte
<script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements";
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script>
<div bind:this={ref} class={cn("divide-y divide-border-2", className)} {...restProps}>
{@render children?.()}
</div>
src/lib/registry/ai/schema-display/schema-display-content.svelte
<script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements";
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script>
<div bind:this={ref} data-slot="ai-schema-display-content" class={cn("divide-y divide-border-2 border-t border-border-2", className)} {...restProps}>
{@render children?.()}
</div>
src/lib/registry/ai/schema-display/schema-display-description.svelte
<script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements";
import { useSchemaDisplayContext } from "./use-schema-display.svelte.js";
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement> = $props();
const schema = useSchemaDisplayContext();
</script>
<p
bind:this={ref}
data-slot="ai-schema-display-description"
class={cn("-mt-2 px-4 pb-3.5 text-xs text-muted-foreground", className)}
{...restProps}
>
{#if children}
{@render children()}
{:else}
{schema.description}
{/if}
</p>
src/lib/registry/ai/schema-display/schema-display-example.svelte
<script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements";
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLPreElement>, HTMLPreElement> = $props();
</script>
<pre
bind:this={ref}
data-slot="ai-schema-display-example"
class={cn(
"mx-4 mb-3.5 overflow-auto rounded-md bg-muted px-3 py-2.5 font-mono text-xs leading-[1.6]",
className
)}
{...restProps}>{@render children?.()}</pre>
src/lib/registry/ai/schema-display/schema-display-header.svelte
<script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements";
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script>
<div bind:this={ref} data-slot="ai-schema-display-header" class={cn("flex items-center gap-2.5 px-4 py-3.5", className)} {...restProps}>
{@render children?.()}
</div>
src/lib/registry/ai/schema-display/schema-display-method.svelte
<script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements";
import { type HttpMethod, useSchemaDisplayContext } from "./use-schema-display.svelte.js";
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> = $props();
const schema = useSchemaDisplayContext();
// Solid soft fills, never /NN opacity (DESIGN §4.16). GET success, POST info, PUT/PATCH warning, DELETE destructive.
const methodStyles: Record<HttpMethod, string> = {
DELETE: "bg-destructive-soft text-destructive-text",
GET: "bg-success-soft text-success-text",
PATCH: "bg-warning-soft text-warning-text",
POST: "bg-info-soft text-info-text",
PUT: "bg-warning-soft text-warning-text",
};
</script>
<span
bind:this={ref}
data-slot="ai-schema-display-method"
data-method={schema.method}
class={cn(
"inline-flex rounded-[5px] px-[7px] py-0.5 font-mono text-[11px] font-semibold",
methodStyles[schema.method],
className
)}
{...restProps}
>
{#if children}
{@render children()}
{:else}
{schema.method}
{/if}
</span>
src/lib/registry/ai/schema-display/schema-display-parameter.svelte
<script lang="ts">
import { Badge } from "$lib/registry/ui/badge/index.js";
import { cn } from "$lib/utils.js";
let {
name,
type,
required,
description,
location,
class: className,
}: {
name: string;
type: string;
required?: boolean;
description?: string;
location?: "path" | "query" | "header";
class?: string;
} = $props();
</script>
<div
data-slot="ai-schema-display-parameter"
class={cn("flex items-center gap-2 py-1.5 text-[12.5px]", className)}
>
<span class="font-mono font-medium">{name}</span>
<span class="font-mono text-muted-foreground">{type}</span>
{#if location}
<Badge class="h-[18px] text-[10.5px]" variant="secondary">{location}</Badge>
{/if}
{#if required}
<Badge class="h-[18px] text-[10.5px]" variant="warning">required</Badge>
{/if}
{#if description}
<span class="ml-auto text-right text-xs text-muted-foreground">{description}</span>
{/if}
</div>
src/lib/registry/ai/schema-display/schema-display-parameters.svelte
<script lang="ts">
import type { Snippet } from "svelte";
import SchemaDisplayParameter from "./schema-display-parameter.svelte";
import SchemaDisplaySection from "./schema-display-section.svelte";
import { useSchemaDisplayContext } from "./use-schema-display.svelte.js";
let {
open = $bindable(true),
class: className,
children,
}: { open?: boolean; class?: string; children?: Snippet } = $props();
const schema = useSchemaDisplayContext();
</script>
<SchemaDisplaySection data-slot="ai-schema-display-parameters" title="Parameters" bind:open class={className}>
{#if children}
{@render children()}
{:else}
{#each schema.parameters ?? [] as param (param.name)}
<SchemaDisplayParameter {...param} />
{/each}
{/if}
</SchemaDisplaySection>
src/lib/registry/ai/schema-display/schema-display-path.svelte
<script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements";
import { useSchemaDisplayContext } from "./use-schema-display.svelte.js";
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> = $props();
const schema = useSchemaDisplayContext();
// `{param}` segments are highlighted; everything else is plain text.
const parts = $derived(
schema.path
.split(/(\{[^}]+\})/g)
.filter(Boolean)
.map((text) => ({ text, param: text.startsWith("{") }))
);
</script>
<span
bind:this={ref}
data-slot="ai-schema-display-path"
class={cn("font-mono text-[13.5px]", className)}
{...restProps}
>
{#if children}
{@render children()}
{:else}
{#each parts as part, index (`${part.text}-${index}`)}
{#if part.param}<span class="text-chart-2">{part.text}</span>{:else}{part.text}{/if}
{/each}
{/if}
</span>
src/lib/registry/ai/schema-display/schema-display-property.svelte
<script lang="ts">
import CaretDownIcon from "phosphor-svelte/lib/CaretDown";
import { Badge } from "$lib/registry/ui/badge/index.js";
import * as Collapsible from "$lib/registry/ui/collapsible/index.js";
import { cn } from "$lib/utils.js";
import SchemaDisplayProperty from "./schema-display-property.svelte";
import type { SchemaProperty } from "./use-schema-display.svelte.js";
let {
name,
type,
required,
description,
properties,
items,
depth = 0,
class: className,
}: SchemaProperty & { depth?: number; class?: string } = $props();
const hasChildren = $derived(!!properties || !!items);
const paddingLeft = $derived(depth * 16);
</script>
{#if hasChildren}
<Collapsible.Root open={depth < 2}>
<Collapsible.Trigger
class={cn(
"group/ai-schema-property flex w-full items-center gap-2 py-1.5 text-left text-[12.5px] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring",
className
)}
style={`padding-left: ${paddingLeft}px`}
>
<CaretDownIcon
class="size-3.5 shrink-0 -rotate-90 text-muted-foreground transition-transform group-data-[state=open]/ai-schema-property:rotate-0"
/>
<span class="font-mono font-medium">{name}</span>
<span class="font-mono text-muted-foreground">{type}</span>
{#if required}
<Badge class="h-[18px] text-[10.5px]" variant="warning">required</Badge>
{/if}
{#if description}
<span class="ml-auto text-right text-xs text-muted-foreground">{description}</span>
{/if}
</Collapsible.Trigger>
<Collapsible.Content class="overflow-hidden">
<div>
{#each properties ?? [] as prop (prop.name)}
<SchemaDisplayProperty {...prop} depth={depth + 1} />
{/each}
{#if items}
<SchemaDisplayProperty {...items} depth={depth + 1} name={`${name}[]`} />
{/if}
</div>
</Collapsible.Content>
</Collapsible.Root>
{:else}
<div
data-slot="ai-schema-display-property"
class={cn("flex items-center gap-2 py-1.5 text-[12.5px]", className)}
style={`padding-left: ${paddingLeft + (depth > 0 ? 22 : 0)}px`}
>
<span class="font-mono font-medium">{name}</span>
<span class="font-mono text-muted-foreground">{type}</span>
{#if required}
<Badge class="h-[18px] text-[10.5px]" variant="warning">required</Badge>
{/if}
{#if description}
<span class="ml-auto text-right text-xs text-muted-foreground">{description}</span>
{/if}
</div>
{/if}
src/lib/registry/ai/schema-display/schema-display-request.svelte
<script lang="ts">
import type { Snippet } from "svelte";
import SchemaDisplayProperty from "./schema-display-property.svelte";
import SchemaDisplaySection from "./schema-display-section.svelte";
import { useSchemaDisplayContext } from "./use-schema-display.svelte.js";
let {
open = $bindable(true),
class: className,
children,
}: { open?: boolean; class?: string; children?: Snippet } = $props();
const schema = useSchemaDisplayContext();
</script>
<SchemaDisplaySection data-slot="ai-schema-display-request" title="Request body" bind:open class={className}>
{#if children}
{@render children()}
{:else}
{#each schema.requestBody ?? [] as prop (prop.name)}
<SchemaDisplayProperty {...prop} depth={0} />
{/each}
{/if}
</SchemaDisplaySection>
src/lib/registry/ai/schema-display/schema-display-response.svelte
<script lang="ts">
import type { Snippet } from "svelte";
import SchemaDisplayProperty from "./schema-display-property.svelte";
import SchemaDisplaySection from "./schema-display-section.svelte";
import { useSchemaDisplayContext } from "./use-schema-display.svelte.js";
let {
open = $bindable(true),
class: className,
children,
}: { open?: boolean; class?: string; children?: Snippet } = $props();
const schema = useSchemaDisplayContext();
</script>
<SchemaDisplaySection data-slot="ai-schema-display-response" title="Response" bind:open class={className}>
{#if children}
{@render children()}
{:else}
{#each schema.responseBody ?? [] as prop (prop.name)}
<SchemaDisplayProperty {...prop} depth={0} />
{/each}
{/if}
</SchemaDisplaySection>
src/lib/registry/ai/schema-display/schema-display-section.svelte
<script lang="ts">
// Shared collapsible section (title + body) behind Parameters, Request and Response.
import CaretDownIcon from "phosphor-svelte/lib/CaretDown";
import * as Collapsible from "$lib/registry/ui/collapsible/index.js";
import type { Snippet } from "svelte";
let {
title,
open = $bindable(true),
class: className,
children,
...restProps
}: {
title: string;
open?: boolean;
class?: string;
children?: Snippet;
[key: string]: unknown;
} = $props();
</script>
<Collapsible.Root bind:open class={className} {...restProps}>
<Collapsible.Trigger
class="group/ai-schema-trigger flex w-full items-center gap-2 px-4 py-2 text-left text-[13.5px] text-muted-foreground outline-none transition-colors hover:text-foreground focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-ring"
>
<CaretDownIcon
class="size-3.5 shrink-0 transition-transform group-data-[state=open]/ai-schema-trigger:rotate-180"
/>
<span>{title}</span>
</Collapsible.Trigger>
<Collapsible.Content class="overflow-hidden">
<div class="px-4 pb-2.5">
{@render children?.()}
</div>
</Collapsible.Content>
</Collapsible.Root>
src/lib/registry/ai/schema-display/schema-display.svelte
<script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements";
import SchemaDisplayContent from "./schema-display-content.svelte";
import SchemaDisplayDescription from "./schema-display-description.svelte";
import SchemaDisplayHeader from "./schema-display-header.svelte";
import SchemaDisplayMethod from "./schema-display-method.svelte";
import SchemaDisplayParameters from "./schema-display-parameters.svelte";
import SchemaDisplayPath from "./schema-display-path.svelte";
import SchemaDisplayRequest from "./schema-display-request.svelte";
import SchemaDisplayResponse from "./schema-display-response.svelte";
import {
type HttpMethod,
type SchemaParameter,
type SchemaProperty,
setSchemaDisplayContext,
} from "./use-schema-display.svelte.js";
let {
ref = $bindable(null),
method,
path,
description,
parameters,
requestBody,
responseBody,
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> & {
method: HttpMethod;
path: string;
description?: string;
parameters?: SchemaParameter[];
requestBody?: SchemaProperty[];
responseBody?: SchemaProperty[];
} = $props();
setSchemaDisplayContext({
get method() {
return method;
},
get path() {
return path;
},
get description() {
return description;
},
get parameters() {
return parameters;
},
get requestBody() {
return requestBody;
},
get responseBody() {
return responseBody;
},
});
</script>
<div
bind:this={ref}
data-slot="ai-schema-display"
class={cn("overflow-hidden rounded-xl border border-border bg-card", className)}
{...restProps}
>
{#if children}
{@render children()}
{:else}
<SchemaDisplayHeader>
<SchemaDisplayMethod />
<SchemaDisplayPath />
</SchemaDisplayHeader>
{#if description}
<SchemaDisplayDescription />
{/if}
<SchemaDisplayContent>
{#if parameters?.length}
<SchemaDisplayParameters />
{/if}
{#if requestBody?.length}
<SchemaDisplayRequest />
{/if}
{#if responseBody?.length}
<SchemaDisplayResponse />
{/if}
</SchemaDisplayContent>
{/if}
</div>
src/lib/registry/ai/schema-display/use-schema-display.svelte.ts
import { getContext, setContext } from "svelte";
export type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
export interface SchemaParameter {
name: string;
type: string;
required?: boolean;
description?: string;
location?: "path" | "query" | "header";
}
export interface SchemaProperty {
name: string;
type: string;
required?: boolean;
description?: string;
properties?: SchemaProperty[];
items?: SchemaProperty;
}
export interface SchemaDisplayContext {
readonly method: HttpMethod;
readonly path: string;
readonly description: string | undefined;
readonly parameters: SchemaParameter[] | undefined;
readonly requestBody: SchemaProperty[] | undefined;
readonly responseBody: SchemaProperty[] | undefined;
}
const KEY = Symbol("ai-schema-display");
export function setSchemaDisplayContext(ctx: SchemaDisplayContext) {
setContext(KEY, ctx);
}
export function useSchemaDisplayContext(): SchemaDisplayContext {
const ctx = getContext<SchemaDisplayContext | undefined>(KEY);
if (!ctx)
throw new Error(
"SchemaDisplay components must be used within SchemaDisplay",
);
return ctx;
}
Part Prop Type Default
SchemaDisplay method, path, description GET | POST | PUT | PATCH | DELETE, string, string
SchemaDisplay parameters, requestBody, responseBody SchemaParameter[], SchemaProperty[], SchemaProperty[]
SchemaDisplayProperty name, type, required, properties, items, depth recursive 0
SchemaDisplayHeader, Method, Path, Description, Content, Parameters, Parameter, Request, Response, Example
  • Method colors use solid soft tokens: GET --success, POST --info, PUT and PATCH --warning, DELETE --destructive.
  • {param} segments of the path are highlighted in --chart-2 (rendered as elements, not HTML).