jayavibhav commited on
Commit
c6b9c0b
·
verified ·
1 Parent(s): 8ab658f

Upload folder using huggingface_hub

Browse files
.gitignore ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .eggs/
2
+ dist/
3
+ *.pyc
4
+ __pycache__/
5
+ *.py[cod]
6
+ *$py.class
7
+ __tmp/*
8
+ *.pyi
9
+ .mypycache
10
+ .ruff_cache
11
+ node_modules
12
+ backend/**/templates/
README.md CHANGED
@@ -1,12 +1,259 @@
1
  ---
2
- title: Gradio Iframecomponent
3
- emoji: 🔥
4
- colorFrom: pink
5
- colorTo: red
 
6
  sdk: gradio
7
- sdk_version: 5.33.1
8
- app_file: app.py
9
  pinned: false
 
10
  ---
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ tags: [gradio-custom-component, SimpleTextbox]
3
+ title: gradio_iframecomponent
4
+ short_description: iframe
5
+ colorFrom: blue
6
+ colorTo: yellow
7
  sdk: gradio
 
 
8
  pinned: false
9
+ app_file: space.py
10
  ---
11
 
12
+ # `gradio_iframecomponent`
13
+ <img alt="Static Badge" src="https://img.shields.io/badge/version%20-%200.0.1%20-%20orange">
14
+
15
+ iframe
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ pip install gradio_iframecomponent
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ```python
26
+ import gradio as gr
27
+ from gradio_iframecomponent import IFrame
28
+
29
+ def create_demo():
30
+ with gr.Blocks() as demo:
31
+ gr.Markdown("# IFrame Component Demo")
32
+
33
+ iframe = IFrame(
34
+ label="Web Page Viewer",
35
+ value="https://www.gradio.app",
36
+ interactive=True,
37
+ height=500
38
+ )
39
+
40
+ url_input = gr.Textbox(
41
+ label="Enter URL",
42
+ placeholder="https://example.com"
43
+ )
44
+
45
+ load_btn = gr.Button("Load URL")
46
+
47
+ load_btn.click(
48
+ fn=lambda url: url,
49
+ inputs=url_input,
50
+ outputs=iframe
51
+ )
52
+
53
+ return demo
54
+
55
+ if __name__ == "__main__":
56
+ demo = create_demo()
57
+ demo.launch()
58
+
59
+ ```
60
+
61
+ ## `IFrame`
62
+
63
+ ### Initialization
64
+
65
+ <table>
66
+ <thead>
67
+ <tr>
68
+ <th align="left">name</th>
69
+ <th align="left" style="width: 25%;">type</th>
70
+ <th align="left">default</th>
71
+ <th align="left">description</th>
72
+ </tr>
73
+ </thead>
74
+ <tbody>
75
+ <tr>
76
+ <td align="left"><code>value</code></td>
77
+ <td align="left" style="width: 25%;">
78
+
79
+ ```python
80
+ str
81
+ ```
82
+
83
+ </td>
84
+ <td align="left"><code>""</code></td>
85
+ <td align="left">None</td>
86
+ </tr>
87
+
88
+ <tr>
89
+ <td align="left"><code>src</code></td>
90
+ <td align="left" style="width: 25%;">
91
+
92
+ ```python
93
+ str | None
94
+ ```
95
+
96
+ </td>
97
+ <td align="left"><code>None</code></td>
98
+ <td align="left">None</td>
99
+ </tr>
100
+
101
+ <tr>
102
+ <td align="left"><code>width</code></td>
103
+ <td align="left" style="width: 25%;">
104
+
105
+ ```python
106
+ str | int
107
+ ```
108
+
109
+ </td>
110
+ <td align="left"><code>"100%"</code></td>
111
+ <td align="left">None</td>
112
+ </tr>
113
+
114
+ <tr>
115
+ <td align="left"><code>height</code></td>
116
+ <td align="left" style="width: 25%;">
117
+
118
+ ```python
119
+ str | int
120
+ ```
121
+
122
+ </td>
123
+ <td align="left"><code>400</code></td>
124
+ <td align="left">None</td>
125
+ </tr>
126
+
127
+ <tr>
128
+ <td align="left"><code>sandbox</code></td>
129
+ <td align="left" style="width: 25%;">
130
+
131
+ ```python
132
+ str | None
133
+ ```
134
+
135
+ </td>
136
+ <td align="left"><code>None</code></td>
137
+ <td align="left">None</td>
138
+ </tr>
139
+
140
+ <tr>
141
+ <td align="left"><code>interactive</code></td>
142
+ <td align="left" style="width: 25%;">
143
+
144
+ ```python
145
+ bool
146
+ ```
147
+
148
+ </td>
149
+ <td align="left"><code>True</code></td>
150
+ <td align="left">None</td>
151
+ </tr>
152
+
153
+ <tr>
154
+ <td align="left"><code>visible</code></td>
155
+ <td align="left" style="width: 25%;">
156
+
157
+ ```python
158
+ bool
159
+ ```
160
+
161
+ </td>
162
+ <td align="left"><code>True</code></td>
163
+ <td align="left">None</td>
164
+ </tr>
165
+
166
+ <tr>
167
+ <td align="left"><code>elem_id</code></td>
168
+ <td align="left" style="width: 25%;">
169
+
170
+ ```python
171
+ str | None
172
+ ```
173
+
174
+ </td>
175
+ <td align="left"><code>None</code></td>
176
+ <td align="left">None</td>
177
+ </tr>
178
+
179
+ <tr>
180
+ <td align="left"><code>elem_classes</code></td>
181
+ <td align="left" style="width: 25%;">
182
+
183
+ ```python
184
+ list[str] | str | None
185
+ ```
186
+
187
+ </td>
188
+ <td align="left"><code>None</code></td>
189
+ <td align="left">None</td>
190
+ </tr>
191
+
192
+ <tr>
193
+ <td align="left"><code>render</code></td>
194
+ <td align="left" style="width: 25%;">
195
+
196
+ ```python
197
+ bool
198
+ ```
199
+
200
+ </td>
201
+ <td align="left"><code>True</code></td>
202
+ <td align="left">None</td>
203
+ </tr>
204
+
205
+ <tr>
206
+ <td align="left"><code>label</code></td>
207
+ <td align="left" style="width: 25%;">
208
+
209
+ ```python
210
+ str | None
211
+ ```
212
+
213
+ </td>
214
+ <td align="left"><code>None</code></td>
215
+ <td align="left">None</td>
216
+ </tr>
217
+
218
+ <tr>
219
+ <td align="left"><code>show_label</code></td>
220
+ <td align="left" style="width: 25%;">
221
+
222
+ ```python
223
+ bool
224
+ ```
225
+
226
+ </td>
227
+ <td align="left"><code>True</code></td>
228
+ <td align="left">None</td>
229
+ </tr>
230
+ </tbody></table>
231
+
232
+
233
+ ### Events
234
+
235
+ | name | description |
236
+ |:-----|:------------|
237
+ | `change` | Triggered when the value of the IFrame changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input. |
238
+ | `input` | This listener is triggered when the user changes the value of the IFrame. |
239
+
240
+
241
+
242
+ ### User function
243
+
244
+ The impact on the users predict function varies depending on whether the component is used as an input or output for an event (or both).
245
+
246
+ - When used as an Input, the component only impacts the input signature of the user function.
247
+ - When used as an output, the component only impacts the return signature of the user function.
248
+
249
+ The code snippet below is accurate in cases where the component is used as both an input and an output.
250
+
251
+
252
+
253
+ ```python
254
+ def predict(
255
+ value: str | None
256
+ ) -> str | None:
257
+ return value
258
+ ```
259
+
__init__.py ADDED
File without changes
app.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from gradio_iframecomponent import IFrame
3
+
4
+ def create_demo():
5
+ with gr.Blocks() as demo:
6
+ gr.Markdown("# IFrame Component Demo")
7
+
8
+ iframe = IFrame(
9
+ label="Web Page Viewer",
10
+ value="https://www.gradio.app",
11
+ interactive=True,
12
+ height=500
13
+ )
14
+
15
+ url_input = gr.Textbox(
16
+ label="Enter URL",
17
+ placeholder="https://example.com"
18
+ )
19
+
20
+ load_btn = gr.Button("Load URL")
21
+
22
+ load_btn.click(
23
+ fn=lambda url: url,
24
+ inputs=url_input,
25
+ outputs=iframe
26
+ )
27
+
28
+ return demo
29
+
30
+ if __name__ == "__main__":
31
+ demo = create_demo()
32
+ demo.launch()
css.css ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ html {
2
+ font-family: Inter;
3
+ font-size: 16px;
4
+ font-weight: 400;
5
+ line-height: 1.5;
6
+ -webkit-text-size-adjust: 100%;
7
+ background: #fff;
8
+ color: #323232;
9
+ -webkit-font-smoothing: antialiased;
10
+ -moz-osx-font-smoothing: grayscale;
11
+ text-rendering: optimizeLegibility;
12
+ }
13
+
14
+ :root {
15
+ --space: 1;
16
+ --vspace: calc(var(--space) * 1rem);
17
+ --vspace-0: calc(3 * var(--space) * 1rem);
18
+ --vspace-1: calc(2 * var(--space) * 1rem);
19
+ --vspace-2: calc(1.5 * var(--space) * 1rem);
20
+ --vspace-3: calc(0.5 * var(--space) * 1rem);
21
+ }
22
+
23
+ .app {
24
+ max-width: 748px !important;
25
+ }
26
+
27
+ .prose p {
28
+ margin: var(--vspace) 0;
29
+ line-height: var(--vspace * 2);
30
+ font-size: 1rem;
31
+ }
32
+
33
+ code {
34
+ font-family: "Inconsolata", sans-serif;
35
+ font-size: 16px;
36
+ }
37
+
38
+ h1,
39
+ h1 code {
40
+ font-weight: 400;
41
+ line-height: calc(2.5 / var(--space) * var(--vspace));
42
+ }
43
+
44
+ h1 code {
45
+ background: none;
46
+ border: none;
47
+ letter-spacing: 0.05em;
48
+ padding-bottom: 5px;
49
+ position: relative;
50
+ padding: 0;
51
+ }
52
+
53
+ h2 {
54
+ margin: var(--vspace-1) 0 var(--vspace-2) 0;
55
+ line-height: 1em;
56
+ }
57
+
58
+ h3,
59
+ h3 code {
60
+ margin: var(--vspace-1) 0 var(--vspace-2) 0;
61
+ line-height: 1em;
62
+ }
63
+
64
+ h4,
65
+ h5,
66
+ h6 {
67
+ margin: var(--vspace-3) 0 var(--vspace-3) 0;
68
+ line-height: var(--vspace);
69
+ }
70
+
71
+ .bigtitle,
72
+ h1,
73
+ h1 code {
74
+ font-size: calc(8px * 4.5);
75
+ word-break: break-word;
76
+ }
77
+
78
+ .title,
79
+ h2,
80
+ h2 code {
81
+ font-size: calc(8px * 3.375);
82
+ font-weight: lighter;
83
+ word-break: break-word;
84
+ border: none;
85
+ background: none;
86
+ }
87
+
88
+ .subheading1,
89
+ h3,
90
+ h3 code {
91
+ font-size: calc(8px * 1.8);
92
+ font-weight: 600;
93
+ border: none;
94
+ background: none;
95
+ letter-spacing: 0.1em;
96
+ text-transform: uppercase;
97
+ }
98
+
99
+ h2 code {
100
+ padding: 0;
101
+ position: relative;
102
+ letter-spacing: 0.05em;
103
+ }
104
+
105
+ blockquote {
106
+ font-size: calc(8px * 1.1667);
107
+ font-style: italic;
108
+ line-height: calc(1.1667 * var(--vspace));
109
+ margin: var(--vspace-2) var(--vspace-2);
110
+ }
111
+
112
+ .subheading2,
113
+ h4 {
114
+ font-size: calc(8px * 1.4292);
115
+ text-transform: uppercase;
116
+ font-weight: 600;
117
+ }
118
+
119
+ .subheading3,
120
+ h5 {
121
+ font-size: calc(8px * 1.2917);
122
+ line-height: calc(1.2917 * var(--vspace));
123
+
124
+ font-weight: lighter;
125
+ text-transform: uppercase;
126
+ letter-spacing: 0.15em;
127
+ }
128
+
129
+ h6 {
130
+ font-size: calc(8px * 1.1667);
131
+ font-size: 1.1667em;
132
+ font-weight: normal;
133
+ font-style: italic;
134
+ font-family: "le-monde-livre-classic-byol", serif !important;
135
+ letter-spacing: 0px !important;
136
+ }
137
+
138
+ #start .md > *:first-child {
139
+ margin-top: 0;
140
+ }
141
+
142
+ h2 + h3 {
143
+ margin-top: 0;
144
+ }
145
+
146
+ .md hr {
147
+ border: none;
148
+ border-top: 1px solid var(--block-border-color);
149
+ margin: var(--vspace-2) 0 var(--vspace-2) 0;
150
+ }
151
+ .prose ul {
152
+ margin: var(--vspace-2) 0 var(--vspace-1) 0;
153
+ }
154
+
155
+ .gap {
156
+ gap: 0;
157
+ }
requirements.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ gradio_iframecomponent
space.py ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import gradio as gr
3
+ from app import demo as app
4
+ import os
5
+
6
+ _docs = {'IFrame': {'description': 'A custom Gradio component for embedding iframes.', 'members': {'__init__': {'value': {'type': 'str', 'default': '""', 'description': None}, 'src': {'type': 'str | None', 'default': 'None', 'description': None}, 'width': {'type': 'str | int', 'default': '"100%"', 'description': None}, 'height': {'type': 'str | int', 'default': '400', 'description': None}, 'sandbox': {'type': 'str | None', 'default': 'None', 'description': None}, 'interactive': {'type': 'bool', 'default': 'True', 'description': None}, 'visible': {'type': 'bool', 'default': 'True', 'description': None}, 'elem_id': {'type': 'str | None', 'default': 'None', 'description': None}, 'elem_classes': {'type': 'list[str] | str | None', 'default': 'None', 'description': None}, 'render': {'type': 'bool', 'default': 'True', 'description': None}, 'label': {'type': 'str | None', 'default': 'None', 'description': None}, 'show_label': {'type': 'bool', 'default': 'True', 'description': None}}, 'postprocess': {'value': {'type': 'str | None', 'description': None}}, 'preprocess': {'return': {'type': 'str | None', 'description': None}, 'value': None}}, 'events': {'change': {'type': None, 'default': None, 'description': 'Triggered when the value of the IFrame changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input.'}, 'input': {'type': None, 'default': None, 'description': 'This listener is triggered when the user changes the value of the IFrame.'}}}, '__meta__': {'additional_interfaces': {}, 'user_fn_refs': {'IFrame': []}}}
7
+
8
+ abs_path = os.path.join(os.path.dirname(__file__), "css.css")
9
+
10
+ with gr.Blocks(
11
+ css=abs_path,
12
+ theme=gr.themes.Default(
13
+ font_mono=[
14
+ gr.themes.GoogleFont("Inconsolata"),
15
+ "monospace",
16
+ ],
17
+ ),
18
+ ) as demo:
19
+ gr.Markdown(
20
+ """
21
+ # `gradio_iframecomponent`
22
+
23
+ <div style="display: flex; gap: 7px;">
24
+ <img alt="Static Badge" src="https://img.shields.io/badge/version%20-%200.0.1%20-%20orange">
25
+ </div>
26
+
27
+ iframe
28
+ """, elem_classes=["md-custom"], header_links=True)
29
+ app.render()
30
+ gr.Markdown(
31
+ """
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install gradio_iframecomponent
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ ```python
41
+ import gradio as gr
42
+ from gradio_iframecomponent import IFrame
43
+
44
+ def create_demo():
45
+ with gr.Blocks() as demo:
46
+ gr.Markdown("# IFrame Component Demo")
47
+
48
+ iframe = IFrame(
49
+ label="Web Page Viewer",
50
+ value="https://www.gradio.app",
51
+ interactive=True,
52
+ height=500
53
+ )
54
+
55
+ url_input = gr.Textbox(
56
+ label="Enter URL",
57
+ placeholder="https://example.com"
58
+ )
59
+
60
+ load_btn = gr.Button("Load URL")
61
+
62
+ load_btn.click(
63
+ fn=lambda url: url,
64
+ inputs=url_input,
65
+ outputs=iframe
66
+ )
67
+
68
+ return demo
69
+
70
+ if __name__ == "__main__":
71
+ demo = create_demo()
72
+ demo.launch()
73
+
74
+ ```
75
+ """, elem_classes=["md-custom"], header_links=True)
76
+
77
+
78
+ gr.Markdown("""
79
+ ## `IFrame`
80
+
81
+ ### Initialization
82
+ """, elem_classes=["md-custom"], header_links=True)
83
+
84
+ gr.ParamViewer(value=_docs["IFrame"]["members"]["__init__"], linkify=[])
85
+
86
+
87
+ gr.Markdown("### Events")
88
+ gr.ParamViewer(value=_docs["IFrame"]["events"], linkify=['Event'])
89
+
90
+
91
+
92
+
93
+ gr.Markdown("""
94
+
95
+ ### User function
96
+
97
+ The impact on the users predict function varies depending on whether the component is used as an input or output for an event (or both).
98
+
99
+ - When used as an Input, the component only impacts the input signature of the user function.
100
+ - When used as an output, the component only impacts the return signature of the user function.
101
+
102
+ The code snippet below is accurate in cases where the component is used as both an input and an output.
103
+
104
+
105
+
106
+ ```python
107
+ def predict(
108
+ value: str | None
109
+ ) -> str | None:
110
+ return value
111
+ ```
112
+ """, elem_classes=["md-custom", "IFrame-user-fn"], header_links=True)
113
+
114
+
115
+
116
+
117
+ demo.load(None, js=r"""function() {
118
+ const refs = {};
119
+ const user_fn_refs = {
120
+ IFrame: [], };
121
+ requestAnimationFrame(() => {
122
+
123
+ Object.entries(user_fn_refs).forEach(([key, refs]) => {
124
+ if (refs.length > 0) {
125
+ const el = document.querySelector(`.${key}-user-fn`);
126
+ if (!el) return;
127
+ refs.forEach(ref => {
128
+ el.innerHTML = el.innerHTML.replace(
129
+ new RegExp("\\b"+ref+"\\b", "g"),
130
+ `<a href="#h-${ref.toLowerCase()}">${ref}</a>`
131
+ );
132
+ })
133
+ }
134
+ })
135
+
136
+ Object.entries(refs).forEach(([key, refs]) => {
137
+ if (refs.length > 0) {
138
+ const el = document.querySelector(`.${key}`);
139
+ if (!el) return;
140
+ refs.forEach(ref => {
141
+ el.innerHTML = el.innerHTML.replace(
142
+ new RegExp("\\b"+ref+"\\b", "g"),
143
+ `<a href="#h-${ref.toLowerCase()}">${ref}</a>`
144
+ );
145
+ })
146
+ }
147
+ })
148
+ })
149
+ }
150
+
151
+ """)
152
+
153
+ demo.launch()
src/.gitignore ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .eggs/
2
+ dist/
3
+ *.pyc
4
+ __pycache__/
5
+ *.py[cod]
6
+ *$py.class
7
+ __tmp/*
8
+ *.pyi
9
+ .mypycache
10
+ .ruff_cache
11
+ node_modules
12
+ backend/**/templates/
src/.pypirc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ [pypi]
2
+ username = __token__
3
+ password = pypi-AgEIcHlwaS5vcmcCJDZmMjUxMWYwLTlhMTAtNDZlZi1hNDhiLWE0NTdiYzgxZTFkMQACKlszLCJmMjMyNDM4NC04Y2FjLTQ3ODgtYjk4OC00NTgyMzRlNjA0NzAiXQAABiBHk0w9VX_ToWSOZP7Ulx_dkbMMWAUrU_uIPmlxdBMp4A
src/README.md ADDED
@@ -0,0 +1,259 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ tags: [gradio-custom-component, SimpleTextbox]
3
+ title: gradio_iframecomponent
4
+ short_description: iframe
5
+ colorFrom: blue
6
+ colorTo: yellow
7
+ sdk: gradio
8
+ pinned: false
9
+ app_file: space.py
10
+ ---
11
+
12
+ # `gradio_iframecomponent`
13
+ <img alt="Static Badge" src="https://img.shields.io/badge/version%20-%200.0.1%20-%20orange">
14
+
15
+ iframe
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ pip install gradio_iframecomponent
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ```python
26
+ import gradio as gr
27
+ from gradio_iframecomponent import IFrame
28
+
29
+ def create_demo():
30
+ with gr.Blocks() as demo:
31
+ gr.Markdown("# IFrame Component Demo")
32
+
33
+ iframe = IFrame(
34
+ label="Web Page Viewer",
35
+ value="https://www.gradio.app",
36
+ interactive=True,
37
+ height=500
38
+ )
39
+
40
+ url_input = gr.Textbox(
41
+ label="Enter URL",
42
+ placeholder="https://example.com"
43
+ )
44
+
45
+ load_btn = gr.Button("Load URL")
46
+
47
+ load_btn.click(
48
+ fn=lambda url: url,
49
+ inputs=url_input,
50
+ outputs=iframe
51
+ )
52
+
53
+ return demo
54
+
55
+ if __name__ == "__main__":
56
+ demo = create_demo()
57
+ demo.launch()
58
+
59
+ ```
60
+
61
+ ## `IFrame`
62
+
63
+ ### Initialization
64
+
65
+ <table>
66
+ <thead>
67
+ <tr>
68
+ <th align="left">name</th>
69
+ <th align="left" style="width: 25%;">type</th>
70
+ <th align="left">default</th>
71
+ <th align="left">description</th>
72
+ </tr>
73
+ </thead>
74
+ <tbody>
75
+ <tr>
76
+ <td align="left"><code>value</code></td>
77
+ <td align="left" style="width: 25%;">
78
+
79
+ ```python
80
+ str
81
+ ```
82
+
83
+ </td>
84
+ <td align="left"><code>""</code></td>
85
+ <td align="left">None</td>
86
+ </tr>
87
+
88
+ <tr>
89
+ <td align="left"><code>src</code></td>
90
+ <td align="left" style="width: 25%;">
91
+
92
+ ```python
93
+ str | None
94
+ ```
95
+
96
+ </td>
97
+ <td align="left"><code>None</code></td>
98
+ <td align="left">None</td>
99
+ </tr>
100
+
101
+ <tr>
102
+ <td align="left"><code>width</code></td>
103
+ <td align="left" style="width: 25%;">
104
+
105
+ ```python
106
+ str | int
107
+ ```
108
+
109
+ </td>
110
+ <td align="left"><code>"100%"</code></td>
111
+ <td align="left">None</td>
112
+ </tr>
113
+
114
+ <tr>
115
+ <td align="left"><code>height</code></td>
116
+ <td align="left" style="width: 25%;">
117
+
118
+ ```python
119
+ str | int
120
+ ```
121
+
122
+ </td>
123
+ <td align="left"><code>400</code></td>
124
+ <td align="left">None</td>
125
+ </tr>
126
+
127
+ <tr>
128
+ <td align="left"><code>sandbox</code></td>
129
+ <td align="left" style="width: 25%;">
130
+
131
+ ```python
132
+ str | None
133
+ ```
134
+
135
+ </td>
136
+ <td align="left"><code>None</code></td>
137
+ <td align="left">None</td>
138
+ </tr>
139
+
140
+ <tr>
141
+ <td align="left"><code>interactive</code></td>
142
+ <td align="left" style="width: 25%;">
143
+
144
+ ```python
145
+ bool
146
+ ```
147
+
148
+ </td>
149
+ <td align="left"><code>True</code></td>
150
+ <td align="left">None</td>
151
+ </tr>
152
+
153
+ <tr>
154
+ <td align="left"><code>visible</code></td>
155
+ <td align="left" style="width: 25%;">
156
+
157
+ ```python
158
+ bool
159
+ ```
160
+
161
+ </td>
162
+ <td align="left"><code>True</code></td>
163
+ <td align="left">None</td>
164
+ </tr>
165
+
166
+ <tr>
167
+ <td align="left"><code>elem_id</code></td>
168
+ <td align="left" style="width: 25%;">
169
+
170
+ ```python
171
+ str | None
172
+ ```
173
+
174
+ </td>
175
+ <td align="left"><code>None</code></td>
176
+ <td align="left">None</td>
177
+ </tr>
178
+
179
+ <tr>
180
+ <td align="left"><code>elem_classes</code></td>
181
+ <td align="left" style="width: 25%;">
182
+
183
+ ```python
184
+ list[str] | str | None
185
+ ```
186
+
187
+ </td>
188
+ <td align="left"><code>None</code></td>
189
+ <td align="left">None</td>
190
+ </tr>
191
+
192
+ <tr>
193
+ <td align="left"><code>render</code></td>
194
+ <td align="left" style="width: 25%;">
195
+
196
+ ```python
197
+ bool
198
+ ```
199
+
200
+ </td>
201
+ <td align="left"><code>True</code></td>
202
+ <td align="left">None</td>
203
+ </tr>
204
+
205
+ <tr>
206
+ <td align="left"><code>label</code></td>
207
+ <td align="left" style="width: 25%;">
208
+
209
+ ```python
210
+ str | None
211
+ ```
212
+
213
+ </td>
214
+ <td align="left"><code>None</code></td>
215
+ <td align="left">None</td>
216
+ </tr>
217
+
218
+ <tr>
219
+ <td align="left"><code>show_label</code></td>
220
+ <td align="left" style="width: 25%;">
221
+
222
+ ```python
223
+ bool
224
+ ```
225
+
226
+ </td>
227
+ <td align="left"><code>True</code></td>
228
+ <td align="left">None</td>
229
+ </tr>
230
+ </tbody></table>
231
+
232
+
233
+ ### Events
234
+
235
+ | name | description |
236
+ |:-----|:------------|
237
+ | `change` | Triggered when the value of the IFrame changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input. |
238
+ | `input` | This listener is triggered when the user changes the value of the IFrame. |
239
+
240
+
241
+
242
+ ### User function
243
+
244
+ The impact on the users predict function varies depending on whether the component is used as an input or output for an event (or both).
245
+
246
+ - When used as an Input, the component only impacts the input signature of the user function.
247
+ - When used as an output, the component only impacts the return signature of the user function.
248
+
249
+ The code snippet below is accurate in cases where the component is used as both an input and an output.
250
+
251
+
252
+
253
+ ```python
254
+ def predict(
255
+ value: str | None
256
+ ) -> str | None:
257
+ return value
258
+ ```
259
+
src/backend/gradio_iframecomponent/__init__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+
2
+ from .iframecomponent import IFrame
3
+
4
+ __all__ = ['IFrame']
src/backend/gradio_iframecomponent/iframecomponent.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+ from typing import Any, Callable, Literal
3
+ import gradio as gr
4
+ from gradio.components.base import Component
5
+ from gradio.events import Events
6
+
7
+ class IFrame(Component):
8
+ """
9
+ A custom Gradio component for embedding iframes.
10
+ """
11
+
12
+ EVENTS = [Events.change, Events.input]
13
+
14
+ def __init__(
15
+ self,
16
+ value: str = "",
17
+ *,
18
+ src: str | None = None,
19
+ width: str | int = "100%",
20
+ height: str | int = 400,
21
+ sandbox: str | None = None,
22
+ interactive: bool = True,
23
+ visible: bool = True,
24
+ elem_id: str | None = None,
25
+ elem_classes: list[str] | str | None = None,
26
+ render: bool = True,
27
+ label: str | None = None,
28
+ show_label: bool = True,
29
+ **kwargs,
30
+ ):
31
+ self.src = src
32
+ self.width = width
33
+ self.height = height
34
+ self.sandbox = sandbox or "allow-scripts allow-same-origin"
35
+
36
+ super().__init__(
37
+ value=value,
38
+ interactive=interactive,
39
+ visible=visible,
40
+ elem_id=elem_id,
41
+ elem_classes=elem_classes,
42
+ render=render,
43
+ label=label,
44
+ show_label=show_label,
45
+ **kwargs,
46
+ )
47
+
48
+ def preprocess(self, payload: str | None) -> str | None:
49
+ """Process input from frontend to backend."""
50
+ return payload
51
+
52
+ def postprocess(self, value: str | None) -> str | None:
53
+ """Process output from backend to frontend."""
54
+ if value is None:
55
+ return None
56
+
57
+ if self.src or (value.startswith('http') and '<iframe' not in value):
58
+ url = self.src or value
59
+ return f"""
60
+ <iframe
61
+ src="{url}"
62
+ width="{self.width}"
63
+ height="{self.height}"
64
+ sandbox="{self.sandbox}"
65
+ frameborder="0"
66
+ ></iframe>
67
+ """
68
+ return value
69
+
70
+ def example_payload(self) -> Any:
71
+ """Example input for API usage - must be JSON-serializable."""
72
+ return "https://www.gradio.app"
73
+
74
+ def example_value(self) -> Any:
75
+ """Example value for component development."""
76
+ return "https://www.gradio.app"
77
+
78
+ def api_info(self) -> dict[str, Any]:
79
+ """JSON-schema representation for API."""
80
+ return {"type": "string"}
src/backend/gradio_iframecomponent/templates/component/index.js ADDED
The diff for this file is too large to render. See raw diff
 
src/backend/gradio_iframecomponent/templates/component/style.css ADDED
The diff for this file is too large to render. See raw diff
 
src/backend/gradio_iframecomponent/templates/example/index.js ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const {
2
+ SvelteComponent: h,
3
+ add_iframe_resize_listener: g,
4
+ add_render_callback: v,
5
+ append_hydration: y,
6
+ attr: b,
7
+ binding_callbacks: m,
8
+ children: w,
9
+ claim_element: z,
10
+ claim_text: k,
11
+ detach: c,
12
+ element: p,
13
+ init: E,
14
+ insert_hydration: S,
15
+ noop: o,
16
+ safe_not_equal: q,
17
+ set_data: C,
18
+ text: D,
19
+ toggle_class: _
20
+ } = window.__gradio__svelte__internal, { onMount: I } = window.__gradio__svelte__internal;
21
+ function M(t) {
22
+ let e, i = (
23
+ /*value*/
24
+ (t[0] ? (
25
+ /*value*/
26
+ t[0]
27
+ ) : "") + ""
28
+ ), s, d;
29
+ return {
30
+ c() {
31
+ e = p("div"), s = D(i), this.h();
32
+ },
33
+ l(l) {
34
+ e = z(l, "DIV", { class: !0 });
35
+ var n = w(e);
36
+ s = k(n, i), n.forEach(c), this.h();
37
+ },
38
+ h() {
39
+ b(e, "class", "svelte-84cxb8"), v(() => (
40
+ /*div_elementresize_handler*/
41
+ t[5].call(e)
42
+ )), _(
43
+ e,
44
+ "table",
45
+ /*type*/
46
+ t[1] === "table"
47
+ ), _(
48
+ e,
49
+ "gallery",
50
+ /*type*/
51
+ t[1] === "gallery"
52
+ ), _(
53
+ e,
54
+ "selected",
55
+ /*selected*/
56
+ t[2]
57
+ );
58
+ },
59
+ m(l, n) {
60
+ S(l, e, n), y(e, s), d = g(
61
+ e,
62
+ /*div_elementresize_handler*/
63
+ t[5].bind(e)
64
+ ), t[6](e);
65
+ },
66
+ p(l, [n]) {
67
+ n & /*value*/
68
+ 1 && i !== (i = /*value*/
69
+ (l[0] ? (
70
+ /*value*/
71
+ l[0]
72
+ ) : "") + "") && C(s, i), n & /*type*/
73
+ 2 && _(
74
+ e,
75
+ "table",
76
+ /*type*/
77
+ l[1] === "table"
78
+ ), n & /*type*/
79
+ 2 && _(
80
+ e,
81
+ "gallery",
82
+ /*type*/
83
+ l[1] === "gallery"
84
+ ), n & /*selected*/
85
+ 4 && _(
86
+ e,
87
+ "selected",
88
+ /*selected*/
89
+ l[2]
90
+ );
91
+ },
92
+ i: o,
93
+ o,
94
+ d(l) {
95
+ l && c(e), d(), t[6](null);
96
+ }
97
+ };
98
+ }
99
+ function P(t, e) {
100
+ t.style.setProperty("--local-text-width", `${e && e < 150 ? e : 200}px`), t.style.whiteSpace = "unset";
101
+ }
102
+ function V(t, e, i) {
103
+ let { value: s } = e, { type: d } = e, { selected: l = !1 } = e, n, r;
104
+ I(() => {
105
+ P(r, n);
106
+ });
107
+ function u() {
108
+ n = this.clientWidth, i(3, n);
109
+ }
110
+ function f(a) {
111
+ m[a ? "unshift" : "push"](() => {
112
+ r = a, i(4, r);
113
+ });
114
+ }
115
+ return t.$$set = (a) => {
116
+ "value" in a && i(0, s = a.value), "type" in a && i(1, d = a.type), "selected" in a && i(2, l = a.selected);
117
+ }, [s, d, l, n, r, u, f];
118
+ }
119
+ class W extends h {
120
+ constructor(e) {
121
+ super(), E(this, e, V, M, q, { value: 0, type: 1, selected: 2 });
122
+ }
123
+ }
124
+ export {
125
+ W as default
126
+ };
src/backend/gradio_iframecomponent/templates/example/style.css ADDED
@@ -0,0 +1 @@
 
 
1
+ .gallery.svelte-84cxb8{padding:var(--size-1) var(--size-2)}div.svelte-84cxb8{overflow:hidden;min-width:var(--local-text-width);white-space:nowrap}
src/demo/__init__.py ADDED
File without changes
src/demo/app.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from gradio_iframecomponent import IFrame
3
+
4
+ def create_demo():
5
+ with gr.Blocks() as demo:
6
+ gr.Markdown("# IFrame Component Demo")
7
+
8
+ iframe = IFrame(
9
+ label="Web Page Viewer",
10
+ value="https://www.gradio.app",
11
+ interactive=True,
12
+ height=500
13
+ )
14
+
15
+ url_input = gr.Textbox(
16
+ label="Enter URL",
17
+ placeholder="https://example.com"
18
+ )
19
+
20
+ load_btn = gr.Button("Load URL")
21
+
22
+ load_btn.click(
23
+ fn=lambda url: url,
24
+ inputs=url_input,
25
+ outputs=iframe
26
+ )
27
+
28
+ return demo
29
+
30
+ if __name__ == "__main__":
31
+ demo = create_demo()
32
+ demo.launch()
src/demo/css.css ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ html {
2
+ font-family: Inter;
3
+ font-size: 16px;
4
+ font-weight: 400;
5
+ line-height: 1.5;
6
+ -webkit-text-size-adjust: 100%;
7
+ background: #fff;
8
+ color: #323232;
9
+ -webkit-font-smoothing: antialiased;
10
+ -moz-osx-font-smoothing: grayscale;
11
+ text-rendering: optimizeLegibility;
12
+ }
13
+
14
+ :root {
15
+ --space: 1;
16
+ --vspace: calc(var(--space) * 1rem);
17
+ --vspace-0: calc(3 * var(--space) * 1rem);
18
+ --vspace-1: calc(2 * var(--space) * 1rem);
19
+ --vspace-2: calc(1.5 * var(--space) * 1rem);
20
+ --vspace-3: calc(0.5 * var(--space) * 1rem);
21
+ }
22
+
23
+ .app {
24
+ max-width: 748px !important;
25
+ }
26
+
27
+ .prose p {
28
+ margin: var(--vspace) 0;
29
+ line-height: var(--vspace * 2);
30
+ font-size: 1rem;
31
+ }
32
+
33
+ code {
34
+ font-family: "Inconsolata", sans-serif;
35
+ font-size: 16px;
36
+ }
37
+
38
+ h1,
39
+ h1 code {
40
+ font-weight: 400;
41
+ line-height: calc(2.5 / var(--space) * var(--vspace));
42
+ }
43
+
44
+ h1 code {
45
+ background: none;
46
+ border: none;
47
+ letter-spacing: 0.05em;
48
+ padding-bottom: 5px;
49
+ position: relative;
50
+ padding: 0;
51
+ }
52
+
53
+ h2 {
54
+ margin: var(--vspace-1) 0 var(--vspace-2) 0;
55
+ line-height: 1em;
56
+ }
57
+
58
+ h3,
59
+ h3 code {
60
+ margin: var(--vspace-1) 0 var(--vspace-2) 0;
61
+ line-height: 1em;
62
+ }
63
+
64
+ h4,
65
+ h5,
66
+ h6 {
67
+ margin: var(--vspace-3) 0 var(--vspace-3) 0;
68
+ line-height: var(--vspace);
69
+ }
70
+
71
+ .bigtitle,
72
+ h1,
73
+ h1 code {
74
+ font-size: calc(8px * 4.5);
75
+ word-break: break-word;
76
+ }
77
+
78
+ .title,
79
+ h2,
80
+ h2 code {
81
+ font-size: calc(8px * 3.375);
82
+ font-weight: lighter;
83
+ word-break: break-word;
84
+ border: none;
85
+ background: none;
86
+ }
87
+
88
+ .subheading1,
89
+ h3,
90
+ h3 code {
91
+ font-size: calc(8px * 1.8);
92
+ font-weight: 600;
93
+ border: none;
94
+ background: none;
95
+ letter-spacing: 0.1em;
96
+ text-transform: uppercase;
97
+ }
98
+
99
+ h2 code {
100
+ padding: 0;
101
+ position: relative;
102
+ letter-spacing: 0.05em;
103
+ }
104
+
105
+ blockquote {
106
+ font-size: calc(8px * 1.1667);
107
+ font-style: italic;
108
+ line-height: calc(1.1667 * var(--vspace));
109
+ margin: var(--vspace-2) var(--vspace-2);
110
+ }
111
+
112
+ .subheading2,
113
+ h4 {
114
+ font-size: calc(8px * 1.4292);
115
+ text-transform: uppercase;
116
+ font-weight: 600;
117
+ }
118
+
119
+ .subheading3,
120
+ h5 {
121
+ font-size: calc(8px * 1.2917);
122
+ line-height: calc(1.2917 * var(--vspace));
123
+
124
+ font-weight: lighter;
125
+ text-transform: uppercase;
126
+ letter-spacing: 0.15em;
127
+ }
128
+
129
+ h6 {
130
+ font-size: calc(8px * 1.1667);
131
+ font-size: 1.1667em;
132
+ font-weight: normal;
133
+ font-style: italic;
134
+ font-family: "le-monde-livre-classic-byol", serif !important;
135
+ letter-spacing: 0px !important;
136
+ }
137
+
138
+ #start .md > *:first-child {
139
+ margin-top: 0;
140
+ }
141
+
142
+ h2 + h3 {
143
+ margin-top: 0;
144
+ }
145
+
146
+ .md hr {
147
+ border: none;
148
+ border-top: 1px solid var(--block-border-color);
149
+ margin: var(--vspace-2) 0 var(--vspace-2) 0;
150
+ }
151
+ .prose ul {
152
+ margin: var(--vspace-2) 0 var(--vspace-1) 0;
153
+ }
154
+
155
+ .gap {
156
+ gap: 0;
157
+ }
src/demo/requirements.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ gradio_iframecomponent
src/demo/space.py ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import gradio as gr
3
+ from app import demo as app
4
+ import os
5
+
6
+ _docs = {'IFrame': {'description': 'A custom Gradio component for embedding iframes.', 'members': {'__init__': {'value': {'type': 'str', 'default': '""', 'description': None}, 'src': {'type': 'str | None', 'default': 'None', 'description': None}, 'width': {'type': 'str | int', 'default': '"100%"', 'description': None}, 'height': {'type': 'str | int', 'default': '400', 'description': None}, 'sandbox': {'type': 'str | None', 'default': 'None', 'description': None}, 'interactive': {'type': 'bool', 'default': 'True', 'description': None}, 'visible': {'type': 'bool', 'default': 'True', 'description': None}, 'elem_id': {'type': 'str | None', 'default': 'None', 'description': None}, 'elem_classes': {'type': 'list[str] | str | None', 'default': 'None', 'description': None}, 'render': {'type': 'bool', 'default': 'True', 'description': None}, 'label': {'type': 'str | None', 'default': 'None', 'description': None}, 'show_label': {'type': 'bool', 'default': 'True', 'description': None}}, 'postprocess': {'value': {'type': 'str | None', 'description': None}}, 'preprocess': {'return': {'type': 'str | None', 'description': None}, 'value': None}}, 'events': {'change': {'type': None, 'default': None, 'description': 'Triggered when the value of the IFrame changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input.'}, 'input': {'type': None, 'default': None, 'description': 'This listener is triggered when the user changes the value of the IFrame.'}}}, '__meta__': {'additional_interfaces': {}, 'user_fn_refs': {'IFrame': []}}}
7
+
8
+ abs_path = os.path.join(os.path.dirname(__file__), "css.css")
9
+
10
+ with gr.Blocks(
11
+ css=abs_path,
12
+ theme=gr.themes.Default(
13
+ font_mono=[
14
+ gr.themes.GoogleFont("Inconsolata"),
15
+ "monospace",
16
+ ],
17
+ ),
18
+ ) as demo:
19
+ gr.Markdown(
20
+ """
21
+ # `gradio_iframecomponent`
22
+
23
+ <div style="display: flex; gap: 7px;">
24
+ <img alt="Static Badge" src="https://img.shields.io/badge/version%20-%200.0.1%20-%20orange">
25
+ </div>
26
+
27
+ iframe
28
+ """, elem_classes=["md-custom"], header_links=True)
29
+ app.render()
30
+ gr.Markdown(
31
+ """
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install gradio_iframecomponent
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ ```python
41
+ import gradio as gr
42
+ from gradio_iframecomponent import IFrame
43
+
44
+ def create_demo():
45
+ with gr.Blocks() as demo:
46
+ gr.Markdown("# IFrame Component Demo")
47
+
48
+ iframe = IFrame(
49
+ label="Web Page Viewer",
50
+ value="https://www.gradio.app",
51
+ interactive=True,
52
+ height=500
53
+ )
54
+
55
+ url_input = gr.Textbox(
56
+ label="Enter URL",
57
+ placeholder="https://example.com"
58
+ )
59
+
60
+ load_btn = gr.Button("Load URL")
61
+
62
+ load_btn.click(
63
+ fn=lambda url: url,
64
+ inputs=url_input,
65
+ outputs=iframe
66
+ )
67
+
68
+ return demo
69
+
70
+ if __name__ == "__main__":
71
+ demo = create_demo()
72
+ demo.launch()
73
+
74
+ ```
75
+ """, elem_classes=["md-custom"], header_links=True)
76
+
77
+
78
+ gr.Markdown("""
79
+ ## `IFrame`
80
+
81
+ ### Initialization
82
+ """, elem_classes=["md-custom"], header_links=True)
83
+
84
+ gr.ParamViewer(value=_docs["IFrame"]["members"]["__init__"], linkify=[])
85
+
86
+
87
+ gr.Markdown("### Events")
88
+ gr.ParamViewer(value=_docs["IFrame"]["events"], linkify=['Event'])
89
+
90
+
91
+
92
+
93
+ gr.Markdown("""
94
+
95
+ ### User function
96
+
97
+ The impact on the users predict function varies depending on whether the component is used as an input or output for an event (or both).
98
+
99
+ - When used as an Input, the component only impacts the input signature of the user function.
100
+ - When used as an output, the component only impacts the return signature of the user function.
101
+
102
+ The code snippet below is accurate in cases where the component is used as both an input and an output.
103
+
104
+
105
+
106
+ ```python
107
+ def predict(
108
+ value: str | None
109
+ ) -> str | None:
110
+ return value
111
+ ```
112
+ """, elem_classes=["md-custom", "IFrame-user-fn"], header_links=True)
113
+
114
+
115
+
116
+
117
+ demo.load(None, js=r"""function() {
118
+ const refs = {};
119
+ const user_fn_refs = {
120
+ IFrame: [], };
121
+ requestAnimationFrame(() => {
122
+
123
+ Object.entries(user_fn_refs).forEach(([key, refs]) => {
124
+ if (refs.length > 0) {
125
+ const el = document.querySelector(`.${key}-user-fn`);
126
+ if (!el) return;
127
+ refs.forEach(ref => {
128
+ el.innerHTML = el.innerHTML.replace(
129
+ new RegExp("\\b"+ref+"\\b", "g"),
130
+ `<a href="#h-${ref.toLowerCase()}">${ref}</a>`
131
+ );
132
+ })
133
+ }
134
+ })
135
+
136
+ Object.entries(refs).forEach(([key, refs]) => {
137
+ if (refs.length > 0) {
138
+ const el = document.querySelector(`.${key}`);
139
+ if (!el) return;
140
+ refs.forEach(ref => {
141
+ el.innerHTML = el.innerHTML.replace(
142
+ new RegExp("\\b"+ref+"\\b", "g"),
143
+ `<a href="#h-${ref.toLowerCase()}">${ref}</a>`
144
+ );
145
+ })
146
+ }
147
+ })
148
+ })
149
+ }
150
+
151
+ """)
152
+
153
+ demo.launch()
src/frontend/Example.svelte ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { onMount } from "svelte";
3
+
4
+ export let value: string | null;
5
+ export let type: "gallery" | "table";
6
+ export let selected = false;
7
+
8
+ let size: number;
9
+ let el: HTMLDivElement;
10
+
11
+ function set_styles(element: HTMLElement, el_width: number): void {
12
+ element.style.setProperty(
13
+ "--local-text-width",
14
+ `${el_width && el_width < 150 ? el_width : 200}px`
15
+ );
16
+ element.style.whiteSpace = "unset";
17
+ }
18
+
19
+ onMount(() => {
20
+ set_styles(el, size);
21
+ });
22
+ </script>
23
+
24
+ <div
25
+ bind:clientWidth={size}
26
+ bind:this={el}
27
+ class:table={type === "table"}
28
+ class:gallery={type === "gallery"}
29
+ class:selected
30
+ >
31
+ {value ? value : ""}
32
+ </div>
33
+
34
+ <style>
35
+ .gallery {
36
+ padding: var(--size-1) var(--size-2);
37
+ }
38
+
39
+ div {
40
+ overflow: hidden;
41
+ min-width: var(--local-text-width);
42
+
43
+ white-space: nowrap;
44
+ }
45
+ </style>
src/frontend/Index.svelte ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { Block } from "@gradio/atoms";
3
+ import { StatusTracker } from "@gradio/statustracker";
4
+ import type { Gradio, SelectData } from "@gradio/utils";
5
+
6
+ export let gradio: Gradio<{
7
+ change: string;
8
+ input: string;
9
+ select: SelectData;
10
+ }>;
11
+
12
+ export let elem_id = "";
13
+ export let elem_classes: string[] = [];
14
+ export let visible = true;
15
+ export let value = "";
16
+ export let loading_status: any;
17
+ export let label: string;
18
+ export let show_label: boolean;
19
+ export let interactive: boolean;
20
+ export let root: string;
21
+
22
+ let iframe_container: HTMLDivElement;
23
+
24
+ // Handle iframe load events for dynamic sizing
25
+ function handleIframeLoad(event: Event) {
26
+ const iframe = event.target as HTMLIFrameElement;
27
+ try {
28
+ // Attempt to adjust height based on content (same-origin only)
29
+ if (iframe.contentDocument) {
30
+ const contentHeight = iframe.contentDocument.body.scrollHeight;
31
+ iframe.style.height = contentHeight + "px";
32
+ }
33
+ } catch (e) {
34
+ // Cross-origin iframes will throw security errors - this is expected
35
+ console.log("Cannot access iframe content (cross-origin)");
36
+ }
37
+ }
38
+
39
+ // Update value when content changes
40
+ function updateValue(newValue: string) {
41
+ value = newValue;
42
+ gradio.dispatch("change", value);
43
+ gradio.dispatch("input", value);
44
+ }
45
+
46
+ $: if (iframe_container && value) {
47
+ iframe_container.innerHTML = value;
48
+
49
+ // Add load event listeners to all iframes
50
+ const iframes = iframe_container.querySelectorAll('iframe');
51
+ iframes.forEach(iframe => {
52
+ iframe.addEventListener('load', handleIframeLoad);
53
+ });
54
+ }
55
+ </script>
56
+
57
+ <Block {visible} {elem_id} {elem_classes} allow_overflow={false} padding={false}>
58
+ {#if loading_status}
59
+ <StatusTracker autoscroll={gradio.autoscroll} i18n={gradio.i18n} {...loading_status} />
60
+ {/if}
61
+
62
+ {#if show_label}
63
+ <label for="iframe-{elem_id}" class="block text-sm font-medium text-gray-700 mb-2">
64
+ {label}
65
+ </label>
66
+ {/if}
67
+
68
+ <div
69
+ bind:this={iframe_container}
70
+ class="iframe-container w-full"
71
+ style="min-height: 300px; border-radius: 8px; overflow: hidden;"
72
+ />
73
+
74
+ {#if interactive}
75
+ <div class="mt-2">
76
+ <input
77
+ type="url"
78
+ placeholder="Enter URL or HTML content"
79
+ class="w-full px-3 py-2 border border-gray-300 rounded-md"
80
+ on:input={(e) => updateValue(e.target.value)}
81
+ value={value}
82
+ />
83
+ </div>
84
+ {/if}
85
+ </Block>
86
+
87
+ <style>
88
+ .iframe-container :global(iframe) {
89
+ width: 100%;
90
+ border: none;
91
+ border-radius: 8px;
92
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
93
+ }
94
+
95
+ .iframe-container :global(iframe):focus {
96
+ outline: 2px solid #3b82f6;
97
+ outline-offset: 2px;
98
+ }
99
+ </style>
src/frontend/gradio.config.js ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ export default {
2
+ plugins: [],
3
+ svelte: {
4
+ preprocess: [],
5
+ },
6
+ build: {
7
+ target: "modules",
8
+ },
9
+ };
src/frontend/package-lock.json ADDED
The diff for this file is too large to render. See raw diff
 
src/frontend/package.json ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "gradio_iframecomponent",
3
+ "version": "0.3.22",
4
+ "description": "Gradio UI packages",
5
+ "type": "module",
6
+ "author": "",
7
+ "license": "ISC",
8
+ "private": false,
9
+ "main_changeset": true,
10
+ "exports": {
11
+ ".": {
12
+ "gradio": "./Index.svelte",
13
+ "svelte": "./dist/Index.svelte",
14
+ "types": "./dist/Index.svelte.d.ts"
15
+ },
16
+ "./example": {
17
+ "gradio": "./Example.svelte",
18
+ "svelte": "./dist/Example.svelte",
19
+ "types": "./dist/Example.svelte.d.ts"
20
+ },
21
+ "./package.json": "./package.json"
22
+ },
23
+ "dependencies": {
24
+ "@gradio/atoms": "0.16.1",
25
+ "@gradio/icons": "0.12.0",
26
+ "@gradio/statustracker": "0.10.12",
27
+ "@gradio/utils": "0.10.2"
28
+ },
29
+ "devDependencies": {
30
+ "@gradio/preview": "0.13.1"
31
+ },
32
+ "peerDependencies": {
33
+ "svelte": "^4.0.0"
34
+ },
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/gradio-app/gradio.git",
38
+ "directory": "js/simpletextbox"
39
+ }
40
+ }
src/frontend/tsconfig.json ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "compilerOptions": {
3
+ "allowJs": true,
4
+ "checkJs": true,
5
+ "esModuleInterop": true,
6
+ "forceConsistentCasingInFileNames": true,
7
+ "resolveJsonModule": true,
8
+ "skipLibCheck": true,
9
+ "sourceMap": true,
10
+ "strict": true,
11
+ "verbatimModuleSyntax": true
12
+ },
13
+ "exclude": ["node_modules", "dist", "./gradio.config.js"]
14
+ }
src/pyproject.toml ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [build-system]
2
+ requires = [
3
+ "hatchling",
4
+ "hatch-requirements-txt",
5
+ "hatch-fancy-pypi-readme>=22.5.0",
6
+ ]
7
+ build-backend = "hatchling.build"
8
+
9
+ [project]
10
+ name = "gradio_iframecomponent"
11
+ version = "0.0.1"
12
+ description = "iframe"
13
+ readme = "README.md"
14
+ license = "apache-2.0"
15
+ requires-python = ">=3.10"
16
+ authors = [{ name = "YOUR NAME", email = "YOUREMAIL@domain.com" }]
17
+ keywords = ["gradio-custom-component", "gradio-template-SimpleTextbox"]
18
+ # Add dependencies here
19
+ dependencies = ["gradio>=4.0,<6.0"]
20
+ classifiers = [
21
+ 'Development Status :: 3 - Alpha',
22
+ 'Operating System :: OS Independent',
23
+ 'Programming Language :: Python :: 3',
24
+ 'Programming Language :: Python :: 3 :: Only',
25
+ 'Programming Language :: Python :: 3.8',
26
+ 'Programming Language :: Python :: 3.9',
27
+ 'Programming Language :: Python :: 3.10',
28
+ 'Programming Language :: Python :: 3.11',
29
+ 'Topic :: Scientific/Engineering',
30
+ 'Topic :: Scientific/Engineering :: Artificial Intelligence',
31
+ 'Topic :: Scientific/Engineering :: Visualization',
32
+ ]
33
+
34
+ # The repository and space URLs are optional, but recommended.
35
+ # Adding a repository URL will create a badge in the auto-generated README that links to the repository.
36
+ # Adding a space URL will create a badge in the auto-generated README that links to the space.
37
+ # This will make it easy for people to find your deployed demo or source code when they
38
+ # encounter your project in the wild.
39
+
40
+ # [project.urls]
41
+ # repository = "your github repository"
42
+ # space = "your space url"
43
+
44
+ [project.optional-dependencies]
45
+ dev = ["build", "twine"]
46
+
47
+ [tool.hatch.build]
48
+ artifacts = ["/backend/gradio_iframecomponent/templates", "*.pyi"]
49
+
50
+ [tool.hatch.build.targets.wheel]
51
+ packages = ["/backend/gradio_iframecomponent"]