File size: 3,057 Bytes
c6b9c0b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
<script lang="ts">
    import { Block } from "@gradio/atoms";
    import { StatusTracker } from "@gradio/statustracker";
    import type { Gradio, SelectData } from "@gradio/utils";

    export let gradio: Gradio<{
        change: string;
        input: string;
        select: SelectData;
    }>;
    
    export let elem_id = "";
    export let elem_classes: string[] = [];
    export let visible = true;
    export let value = "";
    export let loading_status: any;
    export let label: string;
    export let show_label: boolean;
    export let interactive: boolean;
    export let root: string;

    let iframe_container: HTMLDivElement;
    
    // Handle iframe load events for dynamic sizing
    function handleIframeLoad(event: Event) {
        const iframe = event.target as HTMLIFrameElement;
        try {
            // Attempt to adjust height based on content (same-origin only)
            if (iframe.contentDocument) {
                const contentHeight = iframe.contentDocument.body.scrollHeight;
                iframe.style.height = contentHeight + "px";
            }
        } catch (e) {
            // Cross-origin iframes will throw security errors - this is expected
            console.log("Cannot access iframe content (cross-origin)");
        }
    }

    // Update value when content changes
    function updateValue(newValue: string) {
        value = newValue;
        gradio.dispatch("change", value);
        gradio.dispatch("input", value);
    }

    $: if (iframe_container && value) {
        iframe_container.innerHTML = value;
        
        // Add load event listeners to all iframes
        const iframes = iframe_container.querySelectorAll('iframe');
        iframes.forEach(iframe => {
            iframe.addEventListener('load', handleIframeLoad);
        });
    }
</script>

<Block {visible} {elem_id} {elem_classes} allow_overflow={false} padding={false}>
    {#if loading_status}
        <StatusTracker autoscroll={gradio.autoscroll} i18n={gradio.i18n} {...loading_status} />
    {/if}
    
    {#if show_label}
        <label for="iframe-{elem_id}" class="block text-sm font-medium text-gray-700 mb-2">
            {label}
        </label>
    {/if}
    
    <div 
        bind:this={iframe_container}
        class="iframe-container w-full"
        style="min-height: 300px; border-radius: 8px; overflow: hidden;"
    />
    
    {#if interactive}
        <div class="mt-2">
            <input
                type="url"
                placeholder="Enter URL or HTML content"
                class="w-full px-3 py-2 border border-gray-300 rounded-md"
                on:input={(e) => updateValue(e.target.value)}
                value={value}
            />
        </div>
    {/if}
</Block>

<style>
    .iframe-container :global(iframe) {
        width: 100%;
        border: none;
        border-radius: 8px;
        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
    }
    
    .iframe-container :global(iframe):focus {
        outline: 2px solid #3b82f6;
        outline-offset: 2px;
    }
</style>