| <script lang="ts"> | |
| import { createEventDispatcher } from "svelte"; | |
| import { copy, css_units } from "@gradio/utils"; | |
| import { Copy, Check } from "@gradio/icons"; | |
| import type { LoadingStatus } from "@gradio/statustracker"; | |
| import { IconButton, IconButtonWrapper } from "@gradio/atoms"; | |
| import MarkdownCode from "./MarkdownCode.svelte"; | |
| export let elem_classes: string[] = []; | |
| export let visible = true; | |
| export let value: string; | |
| export let min_height: number | string | undefined = undefined; | |
| export let rtl = false; | |
| export let sanitize_html = true; | |
| export let line_breaks = false; | |
| export let latex_delimiters: { | |
| left: string; | |
| right: string; | |
| display: boolean; | |
| }[]; | |
| export let header_links = false; | |
| export let height: number | string | undefined = undefined; | |
| export let show_copy_button = false; | |
| export let root: string; | |
| export let loading_status: LoadingStatus | undefined = undefined; | |
| let copied = false; | |
| let timer: NodeJS.Timeout; | |
| const dispatch = createEventDispatcher<{ change: undefined }>(); | |
| $: value, dispatch("change"); | |
| async function handle_copy(): Promise<void> { | |
| if ("clipboard" in navigator) { | |
| await navigator.clipboard.writeText(value); | |
| copy_feedback(); | |
| } | |
| } | |
| function copy_feedback(): void { | |
| copied = true; | |
| if (timer) clearTimeout(timer); | |
| timer = setTimeout(() => { | |
| copied = false; | |
| }, 1000); | |
| } | |
| </script> | |
| <div | |
| class="prose {elem_classes.join(' ')}" | |
| class:hide={!visible} | |
| data-testid="markdown" | |
| dir={rtl ? "rtl" : "ltr"} | |
| use:copy | |
| style={height ? `max-height: ${css_units(height)}; overflow-y: auto;` : ""} | |
| style:min-height={min_height && loading_status?.status !== "pending" | |
| ? css_units(min_height) | |
| : undefined} | |
| > | |
| {#if show_copy_button} | |
| <IconButtonWrapper> | |
| <IconButton | |
| Icon={copied ? Check : Copy} | |
| on:click={handle_copy} | |
| label={copied ? "Copied conversation" : "Copy conversation"} | |
| ></IconButton> | |
| </IconButtonWrapper> | |
| {/if} | |
| <MarkdownCode | |
| message={value} | |
| {latex_delimiters} | |
| {sanitize_html} | |
| {line_breaks} | |
| chatbot={false} | |
| {header_links} | |
| {root} | |
| /> | |
| </div> | |
| <style> | |
| div :global(.math.inline) { | |
| fill: var(--body-text-color); | |
| display: inline-block; | |
| vertical-align: middle; | |
| padding: var(--size-1-5) -var(--size-1); | |
| color: var(--body-text-color); | |
| } | |
| div :global(.math.inline svg) { | |
| display: inline; | |
| margin-bottom: 0.22em; | |
| } | |
| div { | |
| max-width: 100%; | |
| } | |
| .hide { | |
| display: none; | |
| } | |
| </style> | |