File size: 2,718 Bytes
0bd62e5 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
<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>
|