| <script lang="ts"> | |
| import { onDestroy } from "svelte"; | |
| import { fade } from "svelte/transition"; | |
| 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 = {}; | |
| 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 ? "" : "copy-text"} | |
| aria-roledescription={copied ? "Copied value" : "Copy value"} | |
| aria-label={copied ? "Copied" : "Copy"} | |
| > | |
| {#if copied} | |
| <span in:fade={{ duration: 300 }}> | |
| <Check /> | |
| </span> | |
| {:else} | |
| <Copy /> | |
| {/if} | |
| </button> | |
| <div class="json-holder"> | |
| <JSONNode {value} depth={0} /> | |
| </div> | |
| {:else} | |
| <div class="empty-wrapper"> | |
| <Empty> | |
| <JSONIcon /> | |
| </Empty> | |
| </div> | |
| {/if} | |
| <style> | |
| .json-holder { | |
| padding: var(--size-2); | |
| } | |
| .empty-wrapper { | |
| min-height: calc(var(--size-32) - 20px); | |
| } | |
| 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> | |