<script lang="ts"> import { onDestroy } from "svelte"; import { JSON as JSONIcon } from "@gradio/icons"; import { Empty } from "@gradio/atoms"; import JSONNode from "./JSONNode.svelte"; import { Copy, Check } from "@gradio/icons"; export let value: any = {}; export let open = false; export let theme_mode: "system" | "light" | "dark" = "system"; export let show_indices = false; export let label_height: number; $: json_max_height = `calc(100% - ${label_height}px)`; let copied = false; let timer: NodeJS.Timeout; function copy_feedback(): void { copied = true; if (timer) clearTimeout(timer); timer = setTimeout(() => { copied = false; }, 1000); } async function handle_copy(): Promise<void> { if ("clipboard" in navigator) { await navigator.clipboard.writeText(JSON.stringify(value, null, 2)); copy_feedback(); } } function is_empty(obj: object): boolean { return ( obj && Object.keys(obj).length === 0 && Object.getPrototypeOf(obj) === Object.prototype && JSON.stringify(obj) === JSON.stringify({}) ); } onDestroy(() => { if (timer) clearTimeout(timer); }); </script> {#if value && value !== '""' && !is_empty(value)} <button on:click={handle_copy} title="copy" class={copied ? "copied" : "copy-text"} aria-roledescription={copied ? "Copied value" : "Copy value"} aria-label={copied ? "Copied" : "Copy"} > {#if copied} <Check /> {:else} <Copy /> {/if} </button> <div class="json-holder" style:max-height={json_max_height}> <JSONNode {value} depth={0} is_root={true} {open} {theme_mode} {show_indices} /> </div> {:else} <div class="empty-wrapper"> <Empty> <JSONIcon /> </Empty> </div> {/if} <style> :global(.copied svg) { animation: fade ease 300ms; animation-fill-mode: forwards; } @keyframes fade { 0% { opacity: 0; } 100% { opacity: 1; } } .json-holder { padding: var(--size-2); overflow-y: auto; } .empty-wrapper { min-height: calc(var(--size-32) - 20px); height: 100%; } button { display: flex; position: absolute; top: var(--block-label-margin); right: var(--block-label-margin); align-items: center; box-shadow: var(--shadow-drop); border: 1px solid var(--border-color-primary); border-top: none; border-right: none; border-radius: var(--block-label-right-radius); background: var(--block-label-background-fill); padding: 5px; width: 22px; height: 22px; overflow: hidden; color: var(--block-label-text-color); font: var(--font); font-size: var(--button-small-text-size); } </style>