jayavibhav commited on
Commit
e1a6cb3
·
verified ·
1 Parent(s): 9c36c7a

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,269 @@
1
  ---
2
- title: Gradio Gradiodesigner
3
- emoji: 🔥
4
- colorFrom: pink
5
- colorTo: purple
 
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, designer, drag and drop, custom designs]
3
+ title: gradio_gradiodesigner
4
+ short_description: gradio designer
5
+ colorFrom: blue
6
+ colorTo: yellow
7
  sdk: gradio
 
 
8
  pinned: false
9
+ app_file: space.py
10
  ---
11
 
12
+ # `gradio_gradiodesigner`
13
+ <img alt="Static Badge" src="https://img.shields.io/badge/version%20-%200.0.1%20-%20orange">
14
+
15
+ gradio designer
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ pip install gradio_gradiodesigner
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ```python
26
+ import gradio as gr
27
+ from gradio_gradiodesigner import GradioDesigner
28
+ import json
29
+
30
+ def analyze_design(design_config):
31
+ """Analyze the design configuration"""
32
+ if not design_config or not isinstance(design_config, dict):
33
+ return "No design configuration provided"
34
+
35
+ components = design_config.get('components', [])
36
+
37
+ # Count components by type
38
+ component_types = {}
39
+ for comp in components:
40
+ comp_type = comp.get('type', 'Unknown')
41
+ component_types[comp_type] = component_types.get(comp_type, 0) + 1
42
+
43
+ # Calculate coverage area
44
+ if components:
45
+ positions = [(comp['position']['x'], comp['position']['y']) for comp in components]
46
+ min_x, min_y = min(pos[0] for pos in positions), min(pos[1] for pos in positions)
47
+ max_x, max_y = max(pos[0] for pos in positions), max(pos[1] for pos in positions)
48
+ coverage = f"{max_x - min_x} x {max_y - min_y} pixels"
49
+ else:
50
+ coverage = "No components"
51
+
52
+ analysis = f"""📊 **Design Analysis**
53
+
54
+ **Component Summary:**
55
+ • Total components: {len(components)}
56
+ • Component types: {dict(component_types)}
57
+ • Canvas coverage: {coverage}
58
+
59
+ **Component Details:**
60
+ """
61
+
62
+ for i, comp in enumerate(components, 1):
63
+ analysis += f"\n{i}. **{comp['type']}** (`{comp['id']}`)"
64
+ analysis += f"\n - Position: ({comp['position']['x']}, {comp['position']['y']})"
65
+ analysis += f"\n - Size: {comp['size']['width']}×{comp['size']['height']}"
66
+ if comp.get('props', {}).get('label'):
67
+ analysis += f"\n - Label: \"{comp['props']['label']}\""
68
+
69
+ return analysis
70
+
71
+ def generate_gradio_code(design_config):
72
+ """Generate complete Gradio code from design"""
73
+ if not design_config or not isinstance(design_config, dict):
74
+ return "# No design to generate code from"
75
+
76
+ components = design_config.get('components', [])
77
+
78
+ code = '''import gradio as gr
79
+
80
+ def process_input(*args):
81
+ """Process the inputs from your app"""
82
+ return "Hello from your generated app!"
83
+
84
+ with gr.Blocks(title="Generated Gradio App") as demo:
85
+ gr.Markdown("# 🚀 Generated Gradio App")
86
+ gr.Markdown("This app was generated from your visual design!")
87
+
88
+ '''
89
+
90
+ # Sort components by position (top to bottom, left to right)
91
+ sorted_components = sorted(components, key=lambda c: (c['position']['y'], c['position']['x']))
92
+
93
+ component_vars = []
94
+
95
+ for comp in sorted_components:
96
+ comp_type = comp.get('type', 'Textbox')
97
+ comp_id = comp.get('id', 'component')
98
+ props = comp.get('props', {})
99
+
100
+ # Build component declaration
101
+ prop_parts = []
102
+ for key, value in props.items():
103
+ if key in ['label', 'placeholder', 'value'] and isinstance(value, str):
104
+ prop_parts.append(f'{key}="{value}"')
105
+ elif key in ['minimum', 'maximum', 'step', 'lines', 'max_length', 'precision'] and isinstance(value, (int, float)):
106
+ prop_parts.append(f'{key}={value}')
107
+ elif key == 'choices' and isinstance(value, list):
108
+ prop_parts.append(f'{key}={value}')
109
+ elif isinstance(value, bool):
110
+ prop_parts.append(f'{key}={value}')
111
+
112
+ prop_string = ", ".join(prop_parts) if prop_parts else ""
113
+
114
+ code += f" {comp_id} = gr.{comp_type}({prop_string})\n"
115
+ component_vars.append(comp_id)
116
+
117
+ # Add a simple interaction if there are components
118
+ if component_vars:
119
+ inputs = [var for var in component_vars if not var.startswith('button')]
120
+ outputs = [var for var in component_vars if var.startswith('button')]
121
+
122
+ if not outputs:
123
+ outputs = inputs[:1] # Use first input as output if no buttons
124
+
125
+ if inputs and outputs:
126
+ code += f"\n # Add interactions\n"
127
+ code += f" # Example: connect inputs to outputs\n"
128
+ code += f" # {outputs[0]}.click(process_input, inputs=[{', '.join(inputs)}], outputs=[{outputs[0]}])\n"
129
+
130
+ code += '''
131
+ if __name__ == "__main__":
132
+ demo.launch()
133
+ '''
134
+
135
+ return code
136
+
137
+ with gr.Blocks(title="Gradio Visual Designer Pro", theme=gr.themes.Soft()) as demo:
138
+ gr.Markdown("""
139
+ # 🎨 Gradio Visual Designer Pro
140
+
141
+ **Build your Gradio apps visually!** Drag and drop components, customize properties, and generate production-ready code.
142
+
143
+ **Features:** 25+ Gradio components • Real-time editing • Code generation • Export options
144
+ """)
145
+
146
+ with gr.Row():
147
+ designer = GradioDesigner(
148
+ label="Visual App Designer",
149
+ value={"components": [], "layout": "blocks"}
150
+ )
151
+
152
+ with gr.Row():
153
+ with gr.Column(scale=1):
154
+ analysis_output = gr.Markdown(
155
+ value="Design analysis will appear here...",
156
+ label="Design Analysis"
157
+ )
158
+
159
+ with gr.Column(scale=1):
160
+ code_output = gr.Code(
161
+ label="Generated Gradio Code",
162
+ language="python",
163
+ value="# Design your app above to see generated code",
164
+ lines=20
165
+ )
166
+
167
+ with gr.Row():
168
+ analyze_btn = gr.Button("📊 Analyze Design", variant="secondary")
169
+ generate_btn = gr.Button("🚀 Generate Code", variant="primary")
170
+ clear_btn = gr.Button("🗑️ Clear All", variant="stop")
171
+
172
+ # Event handlers
173
+ designer.change(
174
+ fn=analyze_design,
175
+ inputs=[designer],
176
+ outputs=[analysis_output]
177
+ )
178
+
179
+ analyze_btn.click(
180
+ fn=analyze_design,
181
+ inputs=[designer],
182
+ outputs=[analysis_output]
183
+ )
184
+
185
+ generate_btn.click(
186
+ fn=generate_gradio_code,
187
+ inputs=[designer],
188
+ outputs=[code_output]
189
+ )
190
+
191
+ clear_btn.click(
192
+ fn=lambda: {"components": [], "layout": "blocks"},
193
+ outputs=[designer]
194
+ )
195
+
196
+ if __name__ == "__main__":
197
+ demo.launch()
198
+
199
+ ```
200
+
201
+ ## `GradioDesigner`
202
+
203
+ ### Initialization
204
+
205
+ <table>
206
+ <thead>
207
+ <tr>
208
+ <th align="left">name</th>
209
+ <th align="left" style="width: 25%;">type</th>
210
+ <th align="left">default</th>
211
+ <th align="left">description</th>
212
+ </tr>
213
+ </thead>
214
+ <tbody>
215
+ <tr>
216
+ <td align="left"><code>value</code></td>
217
+ <td align="left" style="width: 25%;">
218
+
219
+ ```python
220
+ dict | None
221
+ ```
222
+
223
+ </td>
224
+ <td align="left"><code>None</code></td>
225
+ <td align="left">None</td>
226
+ </tr>
227
+
228
+ <tr>
229
+ <td align="left"><code>label</code></td>
230
+ <td align="left" style="width: 25%;">
231
+
232
+ ```python
233
+ str | None
234
+ ```
235
+
236
+ </td>
237
+ <td align="left"><code>None</code></td>
238
+ <td align="left">None</td>
239
+ </tr>
240
+ </tbody></table>
241
+
242
+
243
+ ### Events
244
+
245
+ | name | description |
246
+ |:-----|:------------|
247
+ | `change` | Triggered when the value of the GradioDesigner 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. |
248
+ | `input` | This listener is triggered when the user changes the value of the GradioDesigner. |
249
+
250
+
251
+
252
+ ### User function
253
+
254
+ 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).
255
+
256
+ - When used as an Input, the component only impacts the input signature of the user function.
257
+ - When used as an output, the component only impacts the return signature of the user function.
258
+
259
+ The code snippet below is accurate in cases where the component is used as both an input and an output.
260
+
261
+
262
+
263
+ ```python
264
+ def predict(
265
+ value: dict | None
266
+ ) -> dict | None:
267
+ return value
268
+ ```
269
+
__init__.py ADDED
File without changes
app.py ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from gradio_gradiodesigner import GradioDesigner
3
+ import json
4
+
5
+ def analyze_design(design_config):
6
+ """Analyze the design configuration"""
7
+ if not design_config or not isinstance(design_config, dict):
8
+ return "No design configuration provided"
9
+
10
+ components = design_config.get('components', [])
11
+
12
+ # Count components by type
13
+ component_types = {}
14
+ for comp in components:
15
+ comp_type = comp.get('type', 'Unknown')
16
+ component_types[comp_type] = component_types.get(comp_type, 0) + 1
17
+
18
+ # Calculate coverage area
19
+ if components:
20
+ positions = [(comp['position']['x'], comp['position']['y']) for comp in components]
21
+ min_x, min_y = min(pos[0] for pos in positions), min(pos[1] for pos in positions)
22
+ max_x, max_y = max(pos[0] for pos in positions), max(pos[1] for pos in positions)
23
+ coverage = f"{max_x - min_x} x {max_y - min_y} pixels"
24
+ else:
25
+ coverage = "No components"
26
+
27
+ analysis = f"""📊 **Design Analysis**
28
+
29
+ **Component Summary:**
30
+ • Total components: {len(components)}
31
+ • Component types: {dict(component_types)}
32
+ • Canvas coverage: {coverage}
33
+
34
+ **Component Details:**
35
+ """
36
+
37
+ for i, comp in enumerate(components, 1):
38
+ analysis += f"\n{i}. **{comp['type']}** (`{comp['id']}`)"
39
+ analysis += f"\n - Position: ({comp['position']['x']}, {comp['position']['y']})"
40
+ analysis += f"\n - Size: {comp['size']['width']}×{comp['size']['height']}"
41
+ if comp.get('props', {}).get('label'):
42
+ analysis += f"\n - Label: \"{comp['props']['label']}\""
43
+
44
+ return analysis
45
+
46
+ def generate_gradio_code(design_config):
47
+ """Generate complete Gradio code from design"""
48
+ if not design_config or not isinstance(design_config, dict):
49
+ return "# No design to generate code from"
50
+
51
+ components = design_config.get('components', [])
52
+
53
+ code = '''import gradio as gr
54
+
55
+ def process_input(*args):
56
+ """Process the inputs from your app"""
57
+ return "Hello from your generated app!"
58
+
59
+ with gr.Blocks(title="Generated Gradio App") as demo:
60
+ gr.Markdown("# 🚀 Generated Gradio App")
61
+ gr.Markdown("This app was generated from your visual design!")
62
+
63
+ '''
64
+
65
+ # Sort components by position (top to bottom, left to right)
66
+ sorted_components = sorted(components, key=lambda c: (c['position']['y'], c['position']['x']))
67
+
68
+ component_vars = []
69
+
70
+ for comp in sorted_components:
71
+ comp_type = comp.get('type', 'Textbox')
72
+ comp_id = comp.get('id', 'component')
73
+ props = comp.get('props', {})
74
+
75
+ # Build component declaration
76
+ prop_parts = []
77
+ for key, value in props.items():
78
+ if key in ['label', 'placeholder', 'value'] and isinstance(value, str):
79
+ prop_parts.append(f'{key}="{value}"')
80
+ elif key in ['minimum', 'maximum', 'step', 'lines', 'max_length', 'precision'] and isinstance(value, (int, float)):
81
+ prop_parts.append(f'{key}={value}')
82
+ elif key == 'choices' and isinstance(value, list):
83
+ prop_parts.append(f'{key}={value}')
84
+ elif isinstance(value, bool):
85
+ prop_parts.append(f'{key}={value}')
86
+
87
+ prop_string = ", ".join(prop_parts) if prop_parts else ""
88
+
89
+ code += f" {comp_id} = gr.{comp_type}({prop_string})\n"
90
+ component_vars.append(comp_id)
91
+
92
+ # Add a simple interaction if there are components
93
+ if component_vars:
94
+ inputs = [var for var in component_vars if not var.startswith('button')]
95
+ outputs = [var for var in component_vars if var.startswith('button')]
96
+
97
+ if not outputs:
98
+ outputs = inputs[:1] # Use first input as output if no buttons
99
+
100
+ if inputs and outputs:
101
+ code += f"\n # Add interactions\n"
102
+ code += f" # Example: connect inputs to outputs\n"
103
+ code += f" # {outputs[0]}.click(process_input, inputs=[{', '.join(inputs)}], outputs=[{outputs[0]}])\n"
104
+
105
+ code += '''
106
+ if __name__ == "__main__":
107
+ demo.launch()
108
+ '''
109
+
110
+ return code
111
+
112
+ with gr.Blocks(title="Gradio Visual Designer Pro", theme=gr.themes.Soft()) as demo:
113
+ gr.Markdown("""
114
+ # 🎨 Gradio Visual Designer Pro
115
+
116
+ **Build your Gradio apps visually!** Drag and drop components, customize properties, and generate production-ready code.
117
+
118
+ **Features:** 25+ Gradio components • Real-time editing • Code generation • Export options
119
+ """)
120
+
121
+ with gr.Row():
122
+ designer = GradioDesigner(
123
+ label="Visual App Designer",
124
+ value={"components": [], "layout": "blocks"}
125
+ )
126
+
127
+ with gr.Row():
128
+ with gr.Column(scale=1):
129
+ analysis_output = gr.Markdown(
130
+ value="Design analysis will appear here...",
131
+ label="Design Analysis"
132
+ )
133
+
134
+ with gr.Column(scale=1):
135
+ code_output = gr.Code(
136
+ label="Generated Gradio Code",
137
+ language="python",
138
+ value="# Design your app above to see generated code",
139
+ lines=20
140
+ )
141
+
142
+ with gr.Row():
143
+ analyze_btn = gr.Button("📊 Analyze Design", variant="secondary")
144
+ generate_btn = gr.Button("🚀 Generate Code", variant="primary")
145
+ clear_btn = gr.Button("🗑️ Clear All", variant="stop")
146
+
147
+ # Event handlers
148
+ designer.change(
149
+ fn=analyze_design,
150
+ inputs=[designer],
151
+ outputs=[analysis_output]
152
+ )
153
+
154
+ analyze_btn.click(
155
+ fn=analyze_design,
156
+ inputs=[designer],
157
+ outputs=[analysis_output]
158
+ )
159
+
160
+ generate_btn.click(
161
+ fn=generate_gradio_code,
162
+ inputs=[designer],
163
+ outputs=[code_output]
164
+ )
165
+
166
+ clear_btn.click(
167
+ fn=lambda: {"components": [], "layout": "blocks"},
168
+ outputs=[designer]
169
+ )
170
+
171
+ if __name__ == "__main__":
172
+ 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_gradiodesigner
space.py ADDED
@@ -0,0 +1,293 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import gradio as gr
3
+ from app import demo as app
4
+ import os
5
+
6
+ _docs = {'GradioDesigner': {'description': 'A visual designer component for building Gradio layouts with all components', 'members': {'__init__': {'value': {'type': 'dict | None', 'default': 'None', 'description': None}, 'label': {'type': 'str | None', 'default': 'None', 'description': None}}, 'postprocess': {'value': {'type': 'dict | None', 'description': None}}, 'preprocess': {'return': {'type': 'dict | None', 'description': None}, 'value': None}}, 'events': {'change': {'type': None, 'default': None, 'description': 'Triggered when the value of the GradioDesigner 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 GradioDesigner.'}}}, '__meta__': {'additional_interfaces': {}, 'user_fn_refs': {'GradioDesigner': []}}}
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_gradiodesigner`
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
+ gradio designer
28
+ """, elem_classes=["md-custom"], header_links=True)
29
+ app.render()
30
+ gr.Markdown(
31
+ """
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install gradio_gradiodesigner
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ ```python
41
+ import gradio as gr
42
+ from gradio_gradiodesigner import GradioDesigner
43
+ import json
44
+
45
+ def analyze_design(design_config):
46
+ \"\"\"Analyze the design configuration\"\"\"
47
+ if not design_config or not isinstance(design_config, dict):
48
+ return "No design configuration provided"
49
+
50
+ components = design_config.get('components', [])
51
+
52
+ # Count components by type
53
+ component_types = {}
54
+ for comp in components:
55
+ comp_type = comp.get('type', 'Unknown')
56
+ component_types[comp_type] = component_types.get(comp_type, 0) + 1
57
+
58
+ # Calculate coverage area
59
+ if components:
60
+ positions = [(comp['position']['x'], comp['position']['y']) for comp in components]
61
+ min_x, min_y = min(pos[0] for pos in positions), min(pos[1] for pos in positions)
62
+ max_x, max_y = max(pos[0] for pos in positions), max(pos[1] for pos in positions)
63
+ coverage = f"{max_x - min_x} x {max_y - min_y} pixels"
64
+ else:
65
+ coverage = "No components"
66
+
67
+ analysis = f\"\"\"📊 **Design Analysis**
68
+
69
+ **Component Summary:**
70
+ • Total components: {len(components)}
71
+ • Component types: {dict(component_types)}
72
+ • Canvas coverage: {coverage}
73
+
74
+ **Component Details:**
75
+ \"\"\"
76
+
77
+ for i, comp in enumerate(components, 1):
78
+ analysis += f"\n{i}. **{comp['type']}** (`{comp['id']}`)"
79
+ analysis += f"\n - Position: ({comp['position']['x']}, {comp['position']['y']})"
80
+ analysis += f"\n - Size: {comp['size']['width']}×{comp['size']['height']}"
81
+ if comp.get('props', {}).get('label'):
82
+ analysis += f"\n - Label: \"{comp['props']['label']}\""
83
+
84
+ return analysis
85
+
86
+ def generate_gradio_code(design_config):
87
+ \"\"\"Generate complete Gradio code from design\"\"\"
88
+ if not design_config or not isinstance(design_config, dict):
89
+ return "# No design to generate code from"
90
+
91
+ components = design_config.get('components', [])
92
+
93
+ code = '''import gradio as gr
94
+
95
+ def process_input(*args):
96
+ \"\"\"Process the inputs from your app\"\"\"
97
+ return "Hello from your generated app!"
98
+
99
+ with gr.Blocks(title="Generated Gradio App") as demo:
100
+ gr.Markdown("# 🚀 Generated Gradio App")
101
+ gr.Markdown("This app was generated from your visual design!")
102
+
103
+ '''
104
+
105
+ # Sort components by position (top to bottom, left to right)
106
+ sorted_components = sorted(components, key=lambda c: (c['position']['y'], c['position']['x']))
107
+
108
+ component_vars = []
109
+
110
+ for comp in sorted_components:
111
+ comp_type = comp.get('type', 'Textbox')
112
+ comp_id = comp.get('id', 'component')
113
+ props = comp.get('props', {})
114
+
115
+ # Build component declaration
116
+ prop_parts = []
117
+ for key, value in props.items():
118
+ if key in ['label', 'placeholder', 'value'] and isinstance(value, str):
119
+ prop_parts.append(f'{key}="{value}"')
120
+ elif key in ['minimum', 'maximum', 'step', 'lines', 'max_length', 'precision'] and isinstance(value, (int, float)):
121
+ prop_parts.append(f'{key}={value}')
122
+ elif key == 'choices' and isinstance(value, list):
123
+ prop_parts.append(f'{key}={value}')
124
+ elif isinstance(value, bool):
125
+ prop_parts.append(f'{key}={value}')
126
+
127
+ prop_string = ", ".join(prop_parts) if prop_parts else ""
128
+
129
+ code += f" {comp_id} = gr.{comp_type}({prop_string})\n"
130
+ component_vars.append(comp_id)
131
+
132
+ # Add a simple interaction if there are components
133
+ if component_vars:
134
+ inputs = [var for var in component_vars if not var.startswith('button')]
135
+ outputs = [var for var in component_vars if var.startswith('button')]
136
+
137
+ if not outputs:
138
+ outputs = inputs[:1] # Use first input as output if no buttons
139
+
140
+ if inputs and outputs:
141
+ code += f"\n # Add interactions\n"
142
+ code += f" # Example: connect inputs to outputs\n"
143
+ code += f" # {outputs[0]}.click(process_input, inputs=[{', '.join(inputs)}], outputs=[{outputs[0]}])\n"
144
+
145
+ code += '''
146
+ if __name__ == "__main__":
147
+ demo.launch()
148
+ '''
149
+
150
+ return code
151
+
152
+ with gr.Blocks(title="Gradio Visual Designer Pro", theme=gr.themes.Soft()) as demo:
153
+ gr.Markdown(\"\"\"
154
+ # 🎨 Gradio Visual Designer Pro
155
+
156
+ **Build your Gradio apps visually!** Drag and drop components, customize properties, and generate production-ready code.
157
+
158
+ **Features:** 25+ Gradio components • Real-time editing • Code generation • Export options
159
+ \"\"\")
160
+
161
+ with gr.Row():
162
+ designer = GradioDesigner(
163
+ label="Visual App Designer",
164
+ value={"components": [], "layout": "blocks"}
165
+ )
166
+
167
+ with gr.Row():
168
+ with gr.Column(scale=1):
169
+ analysis_output = gr.Markdown(
170
+ value="Design analysis will appear here...",
171
+ label="Design Analysis"
172
+ )
173
+
174
+ with gr.Column(scale=1):
175
+ code_output = gr.Code(
176
+ label="Generated Gradio Code",
177
+ language="python",
178
+ value="# Design your app above to see generated code",
179
+ lines=20
180
+ )
181
+
182
+ with gr.Row():
183
+ analyze_btn = gr.Button("📊 Analyze Design", variant="secondary")
184
+ generate_btn = gr.Button("🚀 Generate Code", variant="primary")
185
+ clear_btn = gr.Button("🗑️ Clear All", variant="stop")
186
+
187
+ # Event handlers
188
+ designer.change(
189
+ fn=analyze_design,
190
+ inputs=[designer],
191
+ outputs=[analysis_output]
192
+ )
193
+
194
+ analyze_btn.click(
195
+ fn=analyze_design,
196
+ inputs=[designer],
197
+ outputs=[analysis_output]
198
+ )
199
+
200
+ generate_btn.click(
201
+ fn=generate_gradio_code,
202
+ inputs=[designer],
203
+ outputs=[code_output]
204
+ )
205
+
206
+ clear_btn.click(
207
+ fn=lambda: {"components": [], "layout": "blocks"},
208
+ outputs=[designer]
209
+ )
210
+
211
+ if __name__ == "__main__":
212
+ demo.launch()
213
+
214
+ ```
215
+ """, elem_classes=["md-custom"], header_links=True)
216
+
217
+
218
+ gr.Markdown("""
219
+ ## `GradioDesigner`
220
+
221
+ ### Initialization
222
+ """, elem_classes=["md-custom"], header_links=True)
223
+
224
+ gr.ParamViewer(value=_docs["GradioDesigner"]["members"]["__init__"], linkify=[])
225
+
226
+
227
+ gr.Markdown("### Events")
228
+ gr.ParamViewer(value=_docs["GradioDesigner"]["events"], linkify=['Event'])
229
+
230
+
231
+
232
+
233
+ gr.Markdown("""
234
+
235
+ ### User function
236
+
237
+ 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).
238
+
239
+ - When used as an Input, the component only impacts the input signature of the user function.
240
+ - When used as an output, the component only impacts the return signature of the user function.
241
+
242
+ The code snippet below is accurate in cases where the component is used as both an input and an output.
243
+
244
+
245
+
246
+ ```python
247
+ def predict(
248
+ value: dict | None
249
+ ) -> dict | None:
250
+ return value
251
+ ```
252
+ """, elem_classes=["md-custom", "GradioDesigner-user-fn"], header_links=True)
253
+
254
+
255
+
256
+
257
+ demo.load(None, js=r"""function() {
258
+ const refs = {};
259
+ const user_fn_refs = {
260
+ GradioDesigner: [], };
261
+ requestAnimationFrame(() => {
262
+
263
+ Object.entries(user_fn_refs).forEach(([key, refs]) => {
264
+ if (refs.length > 0) {
265
+ const el = document.querySelector(`.${key}-user-fn`);
266
+ if (!el) return;
267
+ refs.forEach(ref => {
268
+ el.innerHTML = el.innerHTML.replace(
269
+ new RegExp("\\b"+ref+"\\b", "g"),
270
+ `<a href="#h-${ref.toLowerCase()}">${ref}</a>`
271
+ );
272
+ })
273
+ }
274
+ })
275
+
276
+ Object.entries(refs).forEach(([key, refs]) => {
277
+ if (refs.length > 0) {
278
+ const el = document.querySelector(`.${key}`);
279
+ if (!el) return;
280
+ refs.forEach(ref => {
281
+ el.innerHTML = el.innerHTML.replace(
282
+ new RegExp("\\b"+ref+"\\b", "g"),
283
+ `<a href="#h-${ref.toLowerCase()}">${ref}</a>`
284
+ );
285
+ })
286
+ }
287
+ })
288
+ })
289
+ }
290
+
291
+ """)
292
+
293
+ 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/README.md ADDED
@@ -0,0 +1,269 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ tags: [gradio-custom-component, SimpleTextbox, designer, drag and drop, custom designs]
3
+ title: gradio_gradiodesigner
4
+ short_description: gradio designer
5
+ colorFrom: blue
6
+ colorTo: yellow
7
+ sdk: gradio
8
+ pinned: false
9
+ app_file: space.py
10
+ ---
11
+
12
+ # `gradio_gradiodesigner`
13
+ <img alt="Static Badge" src="https://img.shields.io/badge/version%20-%200.0.1%20-%20orange">
14
+
15
+ gradio designer
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ pip install gradio_gradiodesigner
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ```python
26
+ import gradio as gr
27
+ from gradio_gradiodesigner import GradioDesigner
28
+ import json
29
+
30
+ def analyze_design(design_config):
31
+ """Analyze the design configuration"""
32
+ if not design_config or not isinstance(design_config, dict):
33
+ return "No design configuration provided"
34
+
35
+ components = design_config.get('components', [])
36
+
37
+ # Count components by type
38
+ component_types = {}
39
+ for comp in components:
40
+ comp_type = comp.get('type', 'Unknown')
41
+ component_types[comp_type] = component_types.get(comp_type, 0) + 1
42
+
43
+ # Calculate coverage area
44
+ if components:
45
+ positions = [(comp['position']['x'], comp['position']['y']) for comp in components]
46
+ min_x, min_y = min(pos[0] for pos in positions), min(pos[1] for pos in positions)
47
+ max_x, max_y = max(pos[0] for pos in positions), max(pos[1] for pos in positions)
48
+ coverage = f"{max_x - min_x} x {max_y - min_y} pixels"
49
+ else:
50
+ coverage = "No components"
51
+
52
+ analysis = f"""📊 **Design Analysis**
53
+
54
+ **Component Summary:**
55
+ • Total components: {len(components)}
56
+ • Component types: {dict(component_types)}
57
+ • Canvas coverage: {coverage}
58
+
59
+ **Component Details:**
60
+ """
61
+
62
+ for i, comp in enumerate(components, 1):
63
+ analysis += f"\n{i}. **{comp['type']}** (`{comp['id']}`)"
64
+ analysis += f"\n - Position: ({comp['position']['x']}, {comp['position']['y']})"
65
+ analysis += f"\n - Size: {comp['size']['width']}×{comp['size']['height']}"
66
+ if comp.get('props', {}).get('label'):
67
+ analysis += f"\n - Label: \"{comp['props']['label']}\""
68
+
69
+ return analysis
70
+
71
+ def generate_gradio_code(design_config):
72
+ """Generate complete Gradio code from design"""
73
+ if not design_config or not isinstance(design_config, dict):
74
+ return "# No design to generate code from"
75
+
76
+ components = design_config.get('components', [])
77
+
78
+ code = '''import gradio as gr
79
+
80
+ def process_input(*args):
81
+ """Process the inputs from your app"""
82
+ return "Hello from your generated app!"
83
+
84
+ with gr.Blocks(title="Generated Gradio App") as demo:
85
+ gr.Markdown("# 🚀 Generated Gradio App")
86
+ gr.Markdown("This app was generated from your visual design!")
87
+
88
+ '''
89
+
90
+ # Sort components by position (top to bottom, left to right)
91
+ sorted_components = sorted(components, key=lambda c: (c['position']['y'], c['position']['x']))
92
+
93
+ component_vars = []
94
+
95
+ for comp in sorted_components:
96
+ comp_type = comp.get('type', 'Textbox')
97
+ comp_id = comp.get('id', 'component')
98
+ props = comp.get('props', {})
99
+
100
+ # Build component declaration
101
+ prop_parts = []
102
+ for key, value in props.items():
103
+ if key in ['label', 'placeholder', 'value'] and isinstance(value, str):
104
+ prop_parts.append(f'{key}="{value}"')
105
+ elif key in ['minimum', 'maximum', 'step', 'lines', 'max_length', 'precision'] and isinstance(value, (int, float)):
106
+ prop_parts.append(f'{key}={value}')
107
+ elif key == 'choices' and isinstance(value, list):
108
+ prop_parts.append(f'{key}={value}')
109
+ elif isinstance(value, bool):
110
+ prop_parts.append(f'{key}={value}')
111
+
112
+ prop_string = ", ".join(prop_parts) if prop_parts else ""
113
+
114
+ code += f" {comp_id} = gr.{comp_type}({prop_string})\n"
115
+ component_vars.append(comp_id)
116
+
117
+ # Add a simple interaction if there are components
118
+ if component_vars:
119
+ inputs = [var for var in component_vars if not var.startswith('button')]
120
+ outputs = [var for var in component_vars if var.startswith('button')]
121
+
122
+ if not outputs:
123
+ outputs = inputs[:1] # Use first input as output if no buttons
124
+
125
+ if inputs and outputs:
126
+ code += f"\n # Add interactions\n"
127
+ code += f" # Example: connect inputs to outputs\n"
128
+ code += f" # {outputs[0]}.click(process_input, inputs=[{', '.join(inputs)}], outputs=[{outputs[0]}])\n"
129
+
130
+ code += '''
131
+ if __name__ == "__main__":
132
+ demo.launch()
133
+ '''
134
+
135
+ return code
136
+
137
+ with gr.Blocks(title="Gradio Visual Designer Pro", theme=gr.themes.Soft()) as demo:
138
+ gr.Markdown("""
139
+ # 🎨 Gradio Visual Designer Pro
140
+
141
+ **Build your Gradio apps visually!** Drag and drop components, customize properties, and generate production-ready code.
142
+
143
+ **Features:** 25+ Gradio components • Real-time editing • Code generation • Export options
144
+ """)
145
+
146
+ with gr.Row():
147
+ designer = GradioDesigner(
148
+ label="Visual App Designer",
149
+ value={"components": [], "layout": "blocks"}
150
+ )
151
+
152
+ with gr.Row():
153
+ with gr.Column(scale=1):
154
+ analysis_output = gr.Markdown(
155
+ value="Design analysis will appear here...",
156
+ label="Design Analysis"
157
+ )
158
+
159
+ with gr.Column(scale=1):
160
+ code_output = gr.Code(
161
+ label="Generated Gradio Code",
162
+ language="python",
163
+ value="# Design your app above to see generated code",
164
+ lines=20
165
+ )
166
+
167
+ with gr.Row():
168
+ analyze_btn = gr.Button("📊 Analyze Design", variant="secondary")
169
+ generate_btn = gr.Button("🚀 Generate Code", variant="primary")
170
+ clear_btn = gr.Button("🗑️ Clear All", variant="stop")
171
+
172
+ # Event handlers
173
+ designer.change(
174
+ fn=analyze_design,
175
+ inputs=[designer],
176
+ outputs=[analysis_output]
177
+ )
178
+
179
+ analyze_btn.click(
180
+ fn=analyze_design,
181
+ inputs=[designer],
182
+ outputs=[analysis_output]
183
+ )
184
+
185
+ generate_btn.click(
186
+ fn=generate_gradio_code,
187
+ inputs=[designer],
188
+ outputs=[code_output]
189
+ )
190
+
191
+ clear_btn.click(
192
+ fn=lambda: {"components": [], "layout": "blocks"},
193
+ outputs=[designer]
194
+ )
195
+
196
+ if __name__ == "__main__":
197
+ demo.launch()
198
+
199
+ ```
200
+
201
+ ## `GradioDesigner`
202
+
203
+ ### Initialization
204
+
205
+ <table>
206
+ <thead>
207
+ <tr>
208
+ <th align="left">name</th>
209
+ <th align="left" style="width: 25%;">type</th>
210
+ <th align="left">default</th>
211
+ <th align="left">description</th>
212
+ </tr>
213
+ </thead>
214
+ <tbody>
215
+ <tr>
216
+ <td align="left"><code>value</code></td>
217
+ <td align="left" style="width: 25%;">
218
+
219
+ ```python
220
+ dict | None
221
+ ```
222
+
223
+ </td>
224
+ <td align="left"><code>None</code></td>
225
+ <td align="left">None</td>
226
+ </tr>
227
+
228
+ <tr>
229
+ <td align="left"><code>label</code></td>
230
+ <td align="left" style="width: 25%;">
231
+
232
+ ```python
233
+ str | None
234
+ ```
235
+
236
+ </td>
237
+ <td align="left"><code>None</code></td>
238
+ <td align="left">None</td>
239
+ </tr>
240
+ </tbody></table>
241
+
242
+
243
+ ### Events
244
+
245
+ | name | description |
246
+ |:-----|:------------|
247
+ | `change` | Triggered when the value of the GradioDesigner 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. |
248
+ | `input` | This listener is triggered when the user changes the value of the GradioDesigner. |
249
+
250
+
251
+
252
+ ### User function
253
+
254
+ 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).
255
+
256
+ - When used as an Input, the component only impacts the input signature of the user function.
257
+ - When used as an output, the component only impacts the return signature of the user function.
258
+
259
+ The code snippet below is accurate in cases where the component is used as both an input and an output.
260
+
261
+
262
+
263
+ ```python
264
+ def predict(
265
+ value: dict | None
266
+ ) -> dict | None:
267
+ return value
268
+ ```
269
+
src/backend/gradio_gradiodesigner/__init__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+
2
+ from .gradiodesigner import GradioDesigner
3
+
4
+ __all__ = ['GradioDesigner']
src/backend/gradio_gradiodesigner/gradiodesigner.py ADDED
@@ -0,0 +1,232 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+ from gradio.components.base import Component
3
+ from gradio.events import Events
4
+ import json
5
+
6
+ class GradioDesigner(Component):
7
+ """
8
+ A visual designer component for building Gradio layouts with all components
9
+ """
10
+
11
+ EVENTS = [Events.change, Events.input]
12
+
13
+ # Complete component definitions with their properties
14
+ COMPONENT_DEFINITIONS = {
15
+ "Textbox": {
16
+ "properties": ["label", "placeholder", "lines", "max_length", "type", "value"],
17
+ "defaults": {"label": "Text Input", "placeholder": "Enter text...", "lines": 1, "value": ""},
18
+ "icon": "📝",
19
+ "category": "Input"
20
+ },
21
+ "TextArea": {
22
+ "properties": ["label", "placeholder", "lines", "max_length", "value"],
23
+ "defaults": {"label": "Text Area", "placeholder": "Enter multiple lines...", "lines": 3, "value": ""},
24
+ "icon": "📄",
25
+ "category": "Input"
26
+ },
27
+ "Button": {
28
+ "properties": ["value", "variant", "size"],
29
+ "defaults": {"value": "Click me", "variant": "secondary", "size": "sm"},
30
+ "icon": "🔘",
31
+ "category": "Action"
32
+ },
33
+ "Slider": {
34
+ "properties": ["minimum", "maximum", "step", "value", "label"],
35
+ "defaults": {"label": "Slider", "minimum": 0, "maximum": 100, "step": 1, "value": 50},
36
+ "icon": "🎚️",
37
+ "category": "Input"
38
+ },
39
+ "Number": {
40
+ "properties": ["label", "value", "precision"],
41
+ "defaults": {"label": "Number", "value": 0, "precision": 0},
42
+ "icon": "🔢",
43
+ "category": "Input"
44
+ },
45
+ "Checkbox": {
46
+ "properties": ["label", "value"],
47
+ "defaults": {"label": "Checkbox", "value": False},
48
+ "icon": "☑️",
49
+ "category": "Input"
50
+ },
51
+ "CheckboxGroup": {
52
+ "properties": ["label", "choices", "value"],
53
+ "defaults": {"label": "Checkbox Group", "choices": ["Option 1", "Option 2"], "value": []},
54
+ "icon": "☑️",
55
+ "category": "Input"
56
+ },
57
+ "Radio": {
58
+ "properties": ["label", "choices", "value"],
59
+ "defaults": {"label": "Radio", "choices": ["Option 1", "Option 2"], "value": "Option 1"},
60
+ "icon": "🔘",
61
+ "category": "Input"
62
+ },
63
+ "Dropdown": {
64
+ "properties": ["label", "choices", "value", "multiselect"],
65
+ "defaults": {"label": "Dropdown", "choices": ["Option 1", "Option 2"], "value": "Option 1", "multiselect": False},
66
+ "icon": "📋",
67
+ "category": "Input"
68
+ },
69
+ "Toggle": {
70
+ "properties": ["label", "value"],
71
+ "defaults": {"label": "Toggle", "value": False},
72
+ "icon": "🔄",
73
+ "category": "Input"
74
+ },
75
+ "ColorPicker": {
76
+ "properties": ["label", "value"],
77
+ "defaults": {"label": "Color Picker", "value": "#ff0000"},
78
+ "icon": "🎨",
79
+ "category": "Input"
80
+ },
81
+ "Date": {
82
+ "properties": ["label", "value"],
83
+ "defaults": {"label": "Date", "value": "2025-01-01"},
84
+ "icon": "📅",
85
+ "category": "Input"
86
+ },
87
+ "Time": {
88
+ "properties": ["label", "value"],
89
+ "defaults": {"label": "Time", "value": "12:00"},
90
+ "icon": "⏰",
91
+ "category": "Input"
92
+ },
93
+ "File": {
94
+ "properties": ["label", "file_types"],
95
+ "defaults": {"label": "Upload File", "file_types": [".txt", ".pdf"]},
96
+ "icon": "📁",
97
+ "category": "Input"
98
+ },
99
+ "Image": {
100
+ "properties": ["label", "type", "tool", "interactive"],
101
+ "defaults": {"label": "Image", "type": "pil", "interactive": True},
102
+ "icon": "🖼️",
103
+ "category": "Media"
104
+ },
105
+ "Video": {
106
+ "properties": ["label", "format"],
107
+ "defaults": {"label": "Video", "format": "mp4"},
108
+ "icon": "🎥",
109
+ "category": "Media"
110
+ },
111
+ "Audio": {
112
+ "properties": ["label"],
113
+ "defaults": {"label": "Audio"},
114
+ "icon": "🎵",
115
+ "category": "Media"
116
+ },
117
+ "Dataframe": {
118
+ "properties": ["headers", "datatype", "value"],
119
+ "defaults": {"headers": ["Column 1", "Column 2"], "datatype": ["str", "str"], "value": []},
120
+ "icon": "📊",
121
+ "category": "Data"
122
+ },
123
+ "JSON": {
124
+ "properties": ["value"],
125
+ "defaults": {"value": "{}"},
126
+ "icon": "📋",
127
+ "category": "Data"
128
+ },
129
+ "Markdown": {
130
+ "properties": ["value"],
131
+ "defaults": {"value": "# Markdown Text"},
132
+ "icon": "📝",
133
+ "category": "Display"
134
+ },
135
+ "HTML": {
136
+ "properties": ["value"],
137
+ "defaults": {"value": "<p>HTML Content</p>"},
138
+ "icon": "🌐",
139
+ "category": "Display"
140
+ },
141
+ "Label": {
142
+ "properties": ["value"],
143
+ "defaults": {"value": "Label Text"},
144
+ "icon": "🏷️",
145
+ "category": "Display"
146
+ },
147
+ "Progress": {
148
+ "properties": ["value"],
149
+ "defaults": {"value": 0.5},
150
+ "icon": "📈",
151
+ "category": "Display"
152
+ }
153
+ }
154
+
155
+ def __init__(
156
+ self,
157
+ value: dict | None = None,
158
+ label: str | None = None,
159
+ **kwargs,
160
+ ):
161
+ self.value = value or {"components": [], "layout": "blocks"}
162
+ super().__init__(label=label, **kwargs)
163
+
164
+ def preprocess(self, payload: dict | None) -> dict | None:
165
+ """Process the layout configuration from frontend"""
166
+ if payload is None:
167
+ return None
168
+ return payload
169
+
170
+ def postprocess(self, value: dict | None) -> dict | None:
171
+ """Send layout configuration to frontend"""
172
+ if value is None:
173
+ return {"components": [], "layout": "blocks"}
174
+ return value
175
+
176
+ def api_info(self) -> dict[str, list[str]]:
177
+ """API info for the component"""
178
+ return {
179
+ "info": {
180
+ "type": "object",
181
+ "properties": {
182
+ "components": {
183
+ "type": "array",
184
+ "items": {
185
+ "type": "object",
186
+ "properties": {
187
+ "id": {"type": "string"},
188
+ "type": {"type": "string"},
189
+ "position": {
190
+ "type": "object",
191
+ "properties": {
192
+ "x": {"type": "number"},
193
+ "y": {"type": "number"}
194
+ }
195
+ },
196
+ "size": {
197
+ "type": "object",
198
+ "properties": {
199
+ "width": {"type": "number"},
200
+ "height": {"type": "number"}
201
+ }
202
+ },
203
+ "props": {"type": "object"}
204
+ }
205
+ }
206
+ },
207
+ "layout": {"type": "string"}
208
+ }
209
+ },
210
+ "serialized_info": False
211
+ }
212
+
213
+ def get_component_definitions(self):
214
+ """Get all component definitions for frontend"""
215
+ return self.COMPONENT_DEFINITIONS
216
+
217
+ def example_payload(self) -> dict:
218
+ return {
219
+ "components": [
220
+ {
221
+ "id": "textbox_1",
222
+ "type": "Textbox",
223
+ "position": {"x": 100, "y": 50},
224
+ "size": {"width": 200, "height": 100},
225
+ "props": {"label": "Input", "placeholder": "Enter text..."}
226
+ }
227
+ ],
228
+ "layout": "blocks"
229
+ }
230
+
231
+ def example_value(self) -> dict:
232
+ return self.example_payload()
src/backend/gradio_gradiodesigner/templates/component/index.js ADDED
@@ -0,0 +1,1450 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const {
2
+ SvelteComponent: Ze,
3
+ add_render_callback: $e,
4
+ append_hydration: f,
5
+ attr: h,
6
+ binding_callbacks: et,
7
+ children: j,
8
+ claim_element: k,
9
+ claim_space: C,
10
+ claim_text: oe,
11
+ destroy_block: tt,
12
+ destroy_each: Ae,
13
+ detach: b,
14
+ element: m,
15
+ empty: Se,
16
+ ensure_array_like: Le,
17
+ get_svelte_dataset: R,
18
+ init: lt,
19
+ insert_hydration: O,
20
+ listen: x,
21
+ noop: Ie,
22
+ run_all: je,
23
+ safe_not_equal: st,
24
+ select_option: xe,
25
+ select_value: nt,
26
+ set_data: Te,
27
+ set_input_value: Pe,
28
+ set_style: we,
29
+ space: y,
30
+ stop_propagation: it,
31
+ text: re,
32
+ toggle_class: Ue,
33
+ update_keyed_each: at
34
+ } = window.__gradio__svelte__internal, { onMount: ot } = window.__gradio__svelte__internal;
35
+ function Be(n, e, l) {
36
+ const i = n.slice();
37
+ return i[50] = e[l], i;
38
+ }
39
+ function Me(n, e, l) {
40
+ const i = n.slice();
41
+ return i[50] = e[l], i;
42
+ }
43
+ function Ve(n, e, l) {
44
+ const i = n.slice();
45
+ return i[55] = e[l], i;
46
+ }
47
+ function Re(n) {
48
+ let e, l = (
49
+ /*category*/
50
+ n[55] + ""
51
+ ), i;
52
+ return {
53
+ c() {
54
+ e = m("option"), i = re(l), this.h();
55
+ },
56
+ l(t) {
57
+ e = k(t, "OPTION", {});
58
+ var r = j(e);
59
+ i = oe(r, l), r.forEach(b), this.h();
60
+ },
61
+ h() {
62
+ e.__value = /*category*/
63
+ n[55], Pe(e, e.__value);
64
+ },
65
+ m(t, r) {
66
+ O(t, e, r), f(e, i);
67
+ },
68
+ p: Ie,
69
+ d(t) {
70
+ t && b(e);
71
+ }
72
+ };
73
+ }
74
+ function He(n) {
75
+ let e, l, i;
76
+ function t(v, s) {
77
+ return s[0] & /*searchFilter*/
78
+ 4 && (l = null), l == null && (l = !!/*searchFilter*/
79
+ v[2].trim()), l ? ut : rt;
80
+ }
81
+ let r = t(n, [-1, -1]), p = r(n);
82
+ return {
83
+ c() {
84
+ e = m("div"), p.c(), i = y(), this.h();
85
+ },
86
+ l(v) {
87
+ e = k(v, "DIV", { class: !0 });
88
+ var s = j(e);
89
+ p.l(s), i = C(s), s.forEach(b), this.h();
90
+ },
91
+ h() {
92
+ h(e, "class", "no-components svelte-zk15k");
93
+ },
94
+ m(v, s) {
95
+ O(v, e, s), p.m(e, null), f(e, i);
96
+ },
97
+ p(v, s) {
98
+ r === (r = t(v, s)) && p ? p.p(v, s) : (p.d(1), p = r(v), p && (p.c(), p.m(e, i)));
99
+ },
100
+ d(v) {
101
+ v && b(e), p.d();
102
+ }
103
+ };
104
+ }
105
+ function rt(n) {
106
+ let e;
107
+ return {
108
+ c() {
109
+ e = re("Loading components...");
110
+ },
111
+ l(l) {
112
+ e = oe(l, "Loading components...");
113
+ },
114
+ m(l, i) {
115
+ O(l, e, i);
116
+ },
117
+ p: Ie,
118
+ d(l) {
119
+ l && b(e);
120
+ }
121
+ };
122
+ }
123
+ function ut(n) {
124
+ let e, l, i;
125
+ return {
126
+ c() {
127
+ e = re('No components match "'), l = re(
128
+ /*searchFilter*/
129
+ n[2]
130
+ ), i = re('"');
131
+ },
132
+ l(t) {
133
+ e = oe(t, 'No components match "'), l = oe(
134
+ t,
135
+ /*searchFilter*/
136
+ n[2]
137
+ ), i = oe(t, '"');
138
+ },
139
+ m(t, r) {
140
+ O(t, e, r), O(t, l, r), O(t, i, r);
141
+ },
142
+ p(t, r) {
143
+ r[0] & /*searchFilter*/
144
+ 4 && Te(
145
+ l,
146
+ /*searchFilter*/
147
+ t[2]
148
+ );
149
+ },
150
+ d(t) {
151
+ t && (b(e), b(l), b(i));
152
+ }
153
+ };
154
+ }
155
+ function Fe(n) {
156
+ let e, l, i = (
157
+ /*component*/
158
+ n[50].icon + ""
159
+ ), t, r, p, v = (
160
+ /*component*/
161
+ n[50].label + ""
162
+ ), s, c, ee, q;
163
+ function S(...D) {
164
+ return (
165
+ /*dragstart_handler*/
166
+ n[29](
167
+ /*component*/
168
+ n[50],
169
+ ...D
170
+ )
171
+ );
172
+ }
173
+ return {
174
+ c() {
175
+ e = m("div"), l = m("span"), t = re(i), r = y(), p = m("span"), s = re(v), c = y(), this.h();
176
+ },
177
+ l(D) {
178
+ e = k(D, "DIV", { class: !0, draggable: !0 });
179
+ var N = j(e);
180
+ l = k(N, "SPAN", { class: !0 });
181
+ var M = j(l);
182
+ t = oe(M, i), M.forEach(b), r = C(N), p = k(N, "SPAN", { class: !0 });
183
+ var g = j(p);
184
+ s = oe(g, v), g.forEach(b), c = C(N), N.forEach(b), this.h();
185
+ },
186
+ h() {
187
+ h(l, "class", "icon svelte-zk15k"), h(p, "class", "label svelte-zk15k"), h(e, "class", "palette-item svelte-zk15k"), h(e, "draggable", "true");
188
+ },
189
+ m(D, N) {
190
+ O(D, e, N), f(e, l), f(l, t), f(e, r), f(e, p), f(p, s), f(e, c), ee || (q = x(e, "dragstart", S), ee = !0);
191
+ },
192
+ p(D, N) {
193
+ n = D, N[0] & /*displayComponents*/
194
+ 64 && i !== (i = /*component*/
195
+ n[50].icon + "") && Te(t, i), N[0] & /*displayComponents*/
196
+ 64 && v !== (v = /*component*/
197
+ n[50].label + "") && Te(s, v);
198
+ },
199
+ d(D) {
200
+ D && b(e), ee = !1, q();
201
+ }
202
+ };
203
+ }
204
+ function Ge(n, e) {
205
+ let l, i, t, r, p = (
206
+ /*component*/
207
+ e[50].type + ""
208
+ ), v, s, c, ee = "❌", q, S, D = (
209
+ /*component*/
210
+ (e[50].props.label || /*component*/
211
+ e[50].props.value || "Component") + ""
212
+ ), N, M, g, G;
213
+ function te() {
214
+ return (
215
+ /*click_handler*/
216
+ e[30](
217
+ /*component*/
218
+ e[50]
219
+ )
220
+ );
221
+ }
222
+ function J() {
223
+ return (
224
+ /*click_handler_1*/
225
+ e[31](
226
+ /*component*/
227
+ e[50]
228
+ )
229
+ );
230
+ }
231
+ function Z(...I) {
232
+ return (
233
+ /*mousedown_handler*/
234
+ e[32](
235
+ /*component*/
236
+ e[50],
237
+ ...I
238
+ )
239
+ );
240
+ }
241
+ return {
242
+ key: n,
243
+ first: null,
244
+ c() {
245
+ l = m("div"), i = m("div"), t = m("div"), r = m("span"), v = re(p), s = y(), c = m("button"), c.textContent = ee, q = y(), S = m("span"), N = re(D), M = y(), this.h();
246
+ },
247
+ l(I) {
248
+ l = k(I, "DIV", { class: !0, style: !0 });
249
+ var T = j(l);
250
+ i = k(T, "DIV", { class: !0 });
251
+ var U = j(i);
252
+ t = k(U, "DIV", { class: !0 });
253
+ var X = j(t);
254
+ r = k(X, "SPAN", { class: !0 });
255
+ var W = j(r);
256
+ v = oe(W, p), W.forEach(b), s = C(X), c = k(X, "BUTTON", {
257
+ class: !0,
258
+ type: !0,
259
+ "data-svelte-h": !0
260
+ }), R(c) !== "svelte-1dvzppr" && (c.textContent = ee), X.forEach(b), q = C(U), S = k(U, "SPAN", { class: !0 });
261
+ var pe = j(S);
262
+ N = oe(pe, D), pe.forEach(b), U.forEach(b), M = C(T), T.forEach(b), this.h();
263
+ },
264
+ h() {
265
+ var I;
266
+ h(r, "class", "type svelte-zk15k"), h(c, "class", "delete-btn svelte-zk15k"), h(c, "type", "button"), h(t, "class", "component-header svelte-zk15k"), h(S, "class", "label svelte-zk15k"), h(i, "class", "component-preview svelte-zk15k"), h(l, "class", "canvas-component svelte-zk15k"), we(
267
+ l,
268
+ "left",
269
+ /*component*/
270
+ e[50].position.x + "px"
271
+ ), we(
272
+ l,
273
+ "top",
274
+ /*component*/
275
+ e[50].position.y + "px"
276
+ ), we(
277
+ l,
278
+ "width",
279
+ /*component*/
280
+ e[50].size.width + "px"
281
+ ), we(
282
+ l,
283
+ "height",
284
+ /*component*/
285
+ e[50].size.height + "px"
286
+ ), Ue(
287
+ l,
288
+ "selected",
289
+ /*selectedComponent*/
290
+ ((I = e[5]) == null ? void 0 : I.id) === /*component*/
291
+ e[50].id
292
+ ), this.first = l;
293
+ },
294
+ m(I, T) {
295
+ O(I, l, T), f(l, i), f(i, t), f(t, r), f(r, v), f(t, s), f(t, c), f(i, q), f(i, S), f(S, N), f(l, M), g || (G = [
296
+ x(c, "click", it(te)),
297
+ x(l, "click", J),
298
+ x(l, "mousedown", Z)
299
+ ], g = !0);
300
+ },
301
+ p(I, T) {
302
+ var U;
303
+ e = I, T[0] & /*value*/
304
+ 1 && p !== (p = /*component*/
305
+ e[50].type + "") && Te(v, p), T[0] & /*value*/
306
+ 1 && D !== (D = /*component*/
307
+ (e[50].props.label || /*component*/
308
+ e[50].props.value || "Component") + "") && Te(N, D), T[0] & /*value*/
309
+ 1 && we(
310
+ l,
311
+ "left",
312
+ /*component*/
313
+ e[50].position.x + "px"
314
+ ), T[0] & /*value*/
315
+ 1 && we(
316
+ l,
317
+ "top",
318
+ /*component*/
319
+ e[50].position.y + "px"
320
+ ), T[0] & /*value*/
321
+ 1 && we(
322
+ l,
323
+ "width",
324
+ /*component*/
325
+ e[50].size.width + "px"
326
+ ), T[0] & /*value*/
327
+ 1 && we(
328
+ l,
329
+ "height",
330
+ /*component*/
331
+ e[50].size.height + "px"
332
+ ), T[0] & /*selectedComponent, value*/
333
+ 33 && Ue(
334
+ l,
335
+ "selected",
336
+ /*selectedComponent*/
337
+ ((U = e[5]) == null ? void 0 : U.id) === /*component*/
338
+ e[50].id
339
+ );
340
+ },
341
+ d(I) {
342
+ I && b(l), g = !1, je(G);
343
+ }
344
+ };
345
+ }
346
+ function pt(n) {
347
+ let e, l = "Select a component to edit properties", i, t, r = '<strong>How to use:</strong> <ul class="svelte-zk15k"><li class="svelte-zk15k">Drag components from the palette to the canvas</li> <li class="svelte-zk15k">Click components to select and edit them</li> <li class="svelte-zk15k">Drag components around the canvas to reposition</li> <li class="svelte-zk15k">Use the properties panel to customize</li></ul>';
348
+ return {
349
+ c() {
350
+ e = m("p"), e.textContent = l, i = y(), t = m("div"), t.innerHTML = r, this.h();
351
+ },
352
+ l(p) {
353
+ e = k(p, "P", { "data-svelte-h": !0 }), R(e) !== "svelte-ilodow" && (e.textContent = l), i = C(p), t = k(p, "DIV", { class: !0, "data-svelte-h": !0 }), R(t) !== "svelte-15cgtbi" && (t.innerHTML = r), this.h();
354
+ },
355
+ h() {
356
+ h(t, "class", "help-text svelte-zk15k");
357
+ },
358
+ m(p, v) {
359
+ O(p, e, v), O(p, i, v), O(p, t, v);
360
+ },
361
+ p: Ie,
362
+ d(p) {
363
+ p && (b(e), b(i), b(t));
364
+ }
365
+ };
366
+ }
367
+ function ct(n) {
368
+ let e, l, i, t = "Type:", r, p = (
369
+ /*selectedComponent*/
370
+ n[5].type + ""
371
+ ), v, s, c, ee, q, S, D = (
372
+ /*selectedComponent*/
373
+ n[5].id + ""
374
+ ), N, M, g, G, te, J, Z, I, T, U, X, W = "Size & Position", pe, L, H, _e = "Width:", ke, F, fe, K, le, Ce = "Height:", Q, ie, he, se, $, Oe = "X Position:", ge, ne, me, ce, A, ae = "Y Position:", B, P, de, ye, De, o = (
375
+ /*selectedComponent*/
376
+ n[5].props.label !== void 0 && Je(n)
377
+ ), d = (
378
+ /*selectedComponent*/
379
+ n[5].props.placeholder !== void 0 && Xe(n)
380
+ ), u = (
381
+ /*selectedComponent*/
382
+ n[5].props.value !== void 0 && Ye(n)
383
+ ), _ = (
384
+ /*selectedComponent*/
385
+ n[5].props.choices !== void 0 && qe(n)
386
+ ), a = (
387
+ /*selectedComponent*/
388
+ n[5].props.minimum !== void 0 && We(n)
389
+ ), E = (
390
+ /*selectedComponent*/
391
+ n[5].props.maximum !== void 0 && Ke(n)
392
+ ), V = (
393
+ /*selectedComponent*/
394
+ n[5].props.step !== void 0 && Qe(n)
395
+ );
396
+ return {
397
+ c() {
398
+ e = m("div"), l = m("div"), i = m("strong"), i.textContent = t, r = y(), v = re(p), s = y(), c = m("br"), ee = y(), q = m("small"), S = re("ID: "), N = re(D), M = y(), o && o.c(), g = y(), d && d.c(), G = y(), u && u.c(), te = y(), _ && _.c(), J = y(), a && a.c(), Z = y(), E && E.c(), I = y(), V && V.c(), T = y(), U = m("div"), X = m("h5"), X.textContent = W, pe = y(), L = m("div"), H = m("label"), H.textContent = _e, ke = y(), F = m("input"), K = y(), le = m("label"), le.textContent = Ce, Q = y(), ie = m("input"), se = y(), $ = m("label"), $.textContent = Oe, ge = y(), ne = m("input"), ce = y(), A = m("label"), A.textContent = ae, B = y(), P = m("input"), this.h();
399
+ },
400
+ l(w) {
401
+ e = k(w, "DIV", { class: !0 });
402
+ var z = j(e);
403
+ l = k(z, "DIV", { class: !0 });
404
+ var ue = j(l);
405
+ i = k(ue, "STRONG", { "data-svelte-h": !0 }), R(i) !== "svelte-1y9dw9w" && (i.textContent = t), r = C(ue), v = oe(ue, p), s = C(ue), c = k(ue, "BR", {}), ee = C(ue), q = k(ue, "SMALL", {});
406
+ var be = j(q);
407
+ S = oe(be, "ID: "), N = oe(be, D), be.forEach(b), ue.forEach(b), M = C(z), o && o.l(z), g = C(z), d && d.l(z), G = C(z), u && u.l(z), te = C(z), _ && _.l(z), J = C(z), a && a.l(z), Z = C(z), E && E.l(z), I = C(z), V && V.l(z), T = C(z), U = k(z, "DIV", { class: !0 });
408
+ var ze = j(U);
409
+ X = k(ze, "H5", { class: !0, "data-svelte-h": !0 }), R(X) !== "svelte-u9anyo" && (X.textContent = W), pe = C(ze), L = k(ze, "DIV", { class: !0 });
410
+ var Y = j(L);
411
+ H = k(Y, "LABEL", { class: !0, "data-svelte-h": !0 }), R(H) !== "svelte-19lukby" && (H.textContent = _e), ke = C(Y), F = k(Y, "INPUT", { type: !0, class: !0 }), K = C(Y), le = k(Y, "LABEL", { class: !0, "data-svelte-h": !0 }), R(le) !== "svelte-1ls0h4v" && (le.textContent = Ce), Q = C(Y), ie = k(Y, "INPUT", { type: !0, class: !0 }), se = C(Y), $ = k(Y, "LABEL", { class: !0, "data-svelte-h": !0 }), R($) !== "svelte-1wkby0j" && ($.textContent = Oe), ge = C(Y), ne = k(Y, "INPUT", { type: !0, class: !0 }), ce = C(Y), A = k(Y, "LABEL", { class: !0, "data-svelte-h": !0 }), R(A) !== "svelte-t7u7hk" && (A.textContent = ae), B = C(Y), P = k(Y, "INPUT", { type: !0, class: !0 }), Y.forEach(b), ze.forEach(b), z.forEach(b), this.h();
412
+ },
413
+ h() {
414
+ h(l, "class", "property-header svelte-zk15k"), h(X, "class", "svelte-zk15k"), h(H, "class", "svelte-zk15k"), h(F, "type", "number"), F.value = fe = /*selectedComponent*/
415
+ n[5].size.width, h(F, "class", "svelte-zk15k"), h(le, "class", "svelte-zk15k"), h(ie, "type", "number"), ie.value = he = /*selectedComponent*/
416
+ n[5].size.height, h(ie, "class", "svelte-zk15k"), h($, "class", "svelte-zk15k"), h(ne, "type", "number"), ne.value = me = /*selectedComponent*/
417
+ n[5].position.x, h(ne, "class", "svelte-zk15k"), h(A, "class", "svelte-zk15k"), h(P, "type", "number"), P.value = de = /*selectedComponent*/
418
+ n[5].position.y, h(P, "class", "svelte-zk15k"), h(L, "class", "size-controls svelte-zk15k"), h(U, "class", "size-section svelte-zk15k"), h(e, "class", "property-group svelte-zk15k");
419
+ },
420
+ m(w, z) {
421
+ O(w, e, z), f(e, l), f(l, i), f(l, r), f(l, v), f(l, s), f(l, c), f(l, ee), f(l, q), f(q, S), f(q, N), f(e, M), o && o.m(e, null), f(e, g), d && d.m(e, null), f(e, G), u && u.m(e, null), f(e, te), _ && _.m(e, null), f(e, J), a && a.m(e, null), f(e, Z), E && E.m(e, null), f(e, I), V && V.m(e, null), f(e, T), f(e, U), f(U, X), f(U, pe), f(U, L), f(L, H), f(L, ke), f(L, F), f(L, K), f(L, le), f(L, Q), f(L, ie), f(L, se), f(L, $), f(L, ge), f(L, ne), f(L, ce), f(L, A), f(L, B), f(L, P), ye || (De = [
422
+ x(
423
+ F,
424
+ "input",
425
+ /*input_handler_8*/
426
+ n[43]
427
+ ),
428
+ x(
429
+ ie,
430
+ "input",
431
+ /*input_handler_9*/
432
+ n[44]
433
+ ),
434
+ x(
435
+ ne,
436
+ "input",
437
+ /*input_handler_10*/
438
+ n[45]
439
+ ),
440
+ x(
441
+ P,
442
+ "input",
443
+ /*input_handler_11*/
444
+ n[46]
445
+ )
446
+ ], ye = !0);
447
+ },
448
+ p(w, z) {
449
+ z[0] & /*selectedComponent*/
450
+ 32 && p !== (p = /*selectedComponent*/
451
+ w[5].type + "") && Te(v, p), z[0] & /*selectedComponent*/
452
+ 32 && D !== (D = /*selectedComponent*/
453
+ w[5].id + "") && Te(N, D), /*selectedComponent*/
454
+ w[5].props.label !== void 0 ? o ? o.p(w, z) : (o = Je(w), o.c(), o.m(e, g)) : o && (o.d(1), o = null), /*selectedComponent*/
455
+ w[5].props.placeholder !== void 0 ? d ? d.p(w, z) : (d = Xe(w), d.c(), d.m(e, G)) : d && (d.d(1), d = null), /*selectedComponent*/
456
+ w[5].props.value !== void 0 ? u ? u.p(w, z) : (u = Ye(w), u.c(), u.m(e, te)) : u && (u.d(1), u = null), /*selectedComponent*/
457
+ w[5].props.choices !== void 0 ? _ ? _.p(w, z) : (_ = qe(w), _.c(), _.m(e, J)) : _ && (_.d(1), _ = null), /*selectedComponent*/
458
+ w[5].props.minimum !== void 0 ? a ? a.p(w, z) : (a = We(w), a.c(), a.m(e, Z)) : a && (a.d(1), a = null), /*selectedComponent*/
459
+ w[5].props.maximum !== void 0 ? E ? E.p(w, z) : (E = Ke(w), E.c(), E.m(e, I)) : E && (E.d(1), E = null), /*selectedComponent*/
460
+ w[5].props.step !== void 0 ? V ? V.p(w, z) : (V = Qe(w), V.c(), V.m(e, T)) : V && (V.d(1), V = null), z[0] & /*selectedComponent*/
461
+ 32 && fe !== (fe = /*selectedComponent*/
462
+ w[5].size.width) && F.value !== fe && (F.value = fe), z[0] & /*selectedComponent*/
463
+ 32 && he !== (he = /*selectedComponent*/
464
+ w[5].size.height) && ie.value !== he && (ie.value = he), z[0] & /*selectedComponent*/
465
+ 32 && me !== (me = /*selectedComponent*/
466
+ w[5].position.x) && ne.value !== me && (ne.value = me), z[0] & /*selectedComponent*/
467
+ 32 && de !== (de = /*selectedComponent*/
468
+ w[5].position.y) && P.value !== de && (P.value = de);
469
+ },
470
+ d(w) {
471
+ w && b(e), o && o.d(), d && d.d(), u && u.d(), _ && _.d(), a && a.d(), E && E.d(), V && V.d(), ye = !1, je(De);
472
+ }
473
+ };
474
+ }
475
+ function Je(n) {
476
+ let e, l = "Label:", i, t, r, p, v;
477
+ return {
478
+ c() {
479
+ e = m("label"), e.textContent = l, i = y(), t = m("input"), this.h();
480
+ },
481
+ l(s) {
482
+ e = k(s, "LABEL", { class: !0, "data-svelte-h": !0 }), R(e) !== "svelte-1mvyv0k" && (e.textContent = l), i = C(s), t = k(s, "INPUT", {
483
+ type: !0,
484
+ placeholder: !0,
485
+ class: !0
486
+ }), this.h();
487
+ },
488
+ h() {
489
+ h(e, "class", "svelte-zk15k"), h(t, "type", "text"), h(t, "placeholder", "Label"), t.value = r = /*selectedComponent*/
490
+ n[5].props.label, h(t, "class", "svelte-zk15k");
491
+ },
492
+ m(s, c) {
493
+ O(s, e, c), O(s, i, c), O(s, t, c), p || (v = x(
494
+ t,
495
+ "input",
496
+ /*input_handler*/
497
+ n[34]
498
+ ), p = !0);
499
+ },
500
+ p(s, c) {
501
+ c[0] & /*selectedComponent*/
502
+ 32 && r !== (r = /*selectedComponent*/
503
+ s[5].props.label) && t.value !== r && (t.value = r);
504
+ },
505
+ d(s) {
506
+ s && (b(e), b(i), b(t)), p = !1, v();
507
+ }
508
+ };
509
+ }
510
+ function Xe(n) {
511
+ let e, l = "Placeholder:", i, t, r, p, v;
512
+ return {
513
+ c() {
514
+ e = m("label"), e.textContent = l, i = y(), t = m("input"), this.h();
515
+ },
516
+ l(s) {
517
+ e = k(s, "LABEL", { class: !0, "data-svelte-h": !0 }), R(e) !== "svelte-s3gzvr" && (e.textContent = l), i = C(s), t = k(s, "INPUT", {
518
+ type: !0,
519
+ placeholder: !0,
520
+ class: !0
521
+ }), this.h();
522
+ },
523
+ h() {
524
+ h(e, "class", "svelte-zk15k"), h(t, "type", "text"), h(t, "placeholder", "Placeholder"), t.value = r = /*selectedComponent*/
525
+ n[5].props.placeholder, h(t, "class", "svelte-zk15k");
526
+ },
527
+ m(s, c) {
528
+ O(s, e, c), O(s, i, c), O(s, t, c), p || (v = x(
529
+ t,
530
+ "input",
531
+ /*input_handler_1*/
532
+ n[35]
533
+ ), p = !0);
534
+ },
535
+ p(s, c) {
536
+ c[0] & /*selectedComponent*/
537
+ 32 && r !== (r = /*selectedComponent*/
538
+ s[5].props.placeholder) && t.value !== r && (t.value = r);
539
+ },
540
+ d(s) {
541
+ s && (b(e), b(i), b(t)), p = !1, v();
542
+ }
543
+ };
544
+ }
545
+ function Ye(n) {
546
+ let e, l = "Value:", i, t;
547
+ function r(s, c) {
548
+ return typeof /*selectedComponent*/
549
+ s[5].props.value == "boolean" ? ht : typeof /*selectedComponent*/
550
+ s[5].props.value == "number" ? ft : dt;
551
+ }
552
+ let p = r(n), v = p(n);
553
+ return {
554
+ c() {
555
+ e = m("label"), e.textContent = l, i = y(), v.c(), t = Se(), this.h();
556
+ },
557
+ l(s) {
558
+ e = k(s, "LABEL", { class: !0, "data-svelte-h": !0 }), R(e) !== "svelte-1m0lw4v" && (e.textContent = l), i = C(s), v.l(s), t = Se(), this.h();
559
+ },
560
+ h() {
561
+ h(e, "class", "svelte-zk15k");
562
+ },
563
+ m(s, c) {
564
+ O(s, e, c), O(s, i, c), v.m(s, c), O(s, t, c);
565
+ },
566
+ p(s, c) {
567
+ p === (p = r(s)) && v ? v.p(s, c) : (v.d(1), v = p(s), v && (v.c(), v.m(t.parentNode, t)));
568
+ },
569
+ d(s) {
570
+ s && (b(e), b(i), b(t)), v.d(s);
571
+ }
572
+ };
573
+ }
574
+ function dt(n) {
575
+ let e, l, i, t;
576
+ return {
577
+ c() {
578
+ e = m("input"), this.h();
579
+ },
580
+ l(r) {
581
+ e = k(r, "INPUT", {
582
+ type: !0,
583
+ placeholder: !0,
584
+ class: !0
585
+ }), this.h();
586
+ },
587
+ h() {
588
+ h(e, "type", "text"), h(e, "placeholder", "Value"), e.value = l = /*selectedComponent*/
589
+ n[5].props.value, h(e, "class", "svelte-zk15k");
590
+ },
591
+ m(r, p) {
592
+ O(r, e, p), i || (t = x(
593
+ e,
594
+ "input",
595
+ /*input_handler_3*/
596
+ n[38]
597
+ ), i = !0);
598
+ },
599
+ p(r, p) {
600
+ p[0] & /*selectedComponent*/
601
+ 32 && l !== (l = /*selectedComponent*/
602
+ r[5].props.value) && e.value !== l && (e.value = l);
603
+ },
604
+ d(r) {
605
+ r && b(e), i = !1, t();
606
+ }
607
+ };
608
+ }
609
+ function ft(n) {
610
+ let e, l, i, t;
611
+ return {
612
+ c() {
613
+ e = m("input"), this.h();
614
+ },
615
+ l(r) {
616
+ e = k(r, "INPUT", { type: !0, class: !0 }), this.h();
617
+ },
618
+ h() {
619
+ h(e, "type", "number"), e.value = l = /*selectedComponent*/
620
+ n[5].props.value, h(e, "class", "svelte-zk15k");
621
+ },
622
+ m(r, p) {
623
+ O(r, e, p), i || (t = x(
624
+ e,
625
+ "input",
626
+ /*input_handler_2*/
627
+ n[37]
628
+ ), i = !0);
629
+ },
630
+ p(r, p) {
631
+ p[0] & /*selectedComponent*/
632
+ 32 && l !== (l = /*selectedComponent*/
633
+ r[5].props.value) && e.value !== l && (e.value = l);
634
+ },
635
+ d(r) {
636
+ r && b(e), i = !1, t();
637
+ }
638
+ };
639
+ }
640
+ function ht(n) {
641
+ let e, l, i, t;
642
+ return {
643
+ c() {
644
+ e = m("input"), this.h();
645
+ },
646
+ l(r) {
647
+ e = k(r, "INPUT", { type: !0, class: !0 }), this.h();
648
+ },
649
+ h() {
650
+ h(e, "type", "checkbox"), e.checked = l = /*selectedComponent*/
651
+ n[5].props.value, h(e, "class", "svelte-zk15k");
652
+ },
653
+ m(r, p) {
654
+ O(r, e, p), i || (t = x(
655
+ e,
656
+ "change",
657
+ /*change_handler*/
658
+ n[36]
659
+ ), i = !0);
660
+ },
661
+ p(r, p) {
662
+ p[0] & /*selectedComponent*/
663
+ 32 && l !== (l = /*selectedComponent*/
664
+ r[5].props.value) && (e.checked = l);
665
+ },
666
+ d(r) {
667
+ r && b(e), i = !1, t();
668
+ }
669
+ };
670
+ }
671
+ function qe(n) {
672
+ let e, l = "Choices (comma-separated):", i, t, r, p, v;
673
+ return {
674
+ c() {
675
+ e = m("label"), e.textContent = l, i = y(), t = m("input"), this.h();
676
+ },
677
+ l(s) {
678
+ e = k(s, "LABEL", { class: !0, "data-svelte-h": !0 }), R(e) !== "svelte-s5zbc2" && (e.textContent = l), i = C(s), t = k(s, "INPUT", {
679
+ type: !0,
680
+ placeholder: !0,
681
+ class: !0
682
+ }), this.h();
683
+ },
684
+ h() {
685
+ h(e, "class", "svelte-zk15k"), h(t, "type", "text"), h(t, "placeholder", "Option 1, Option 2, Option 3"), t.value = r = Array.isArray(
686
+ /*selectedComponent*/
687
+ n[5].props.choices
688
+ ) ? (
689
+ /*selectedComponent*/
690
+ n[5].props.choices.join(", ")
691
+ ) : (
692
+ /*selectedComponent*/
693
+ n[5].props.choices
694
+ ), h(t, "class", "svelte-zk15k");
695
+ },
696
+ m(s, c) {
697
+ O(s, e, c), O(s, i, c), O(s, t, c), p || (v = x(
698
+ t,
699
+ "input",
700
+ /*input_handler_4*/
701
+ n[39]
702
+ ), p = !0);
703
+ },
704
+ p(s, c) {
705
+ c[0] & /*selectedComponent*/
706
+ 32 && r !== (r = Array.isArray(
707
+ /*selectedComponent*/
708
+ s[5].props.choices
709
+ ) ? (
710
+ /*selectedComponent*/
711
+ s[5].props.choices.join(", ")
712
+ ) : (
713
+ /*selectedComponent*/
714
+ s[5].props.choices
715
+ )) && t.value !== r && (t.value = r);
716
+ },
717
+ d(s) {
718
+ s && (b(e), b(i), b(t)), p = !1, v();
719
+ }
720
+ };
721
+ }
722
+ function We(n) {
723
+ let e, l = "Minimum:", i, t, r, p, v;
724
+ return {
725
+ c() {
726
+ e = m("label"), e.textContent = l, i = y(), t = m("input"), this.h();
727
+ },
728
+ l(s) {
729
+ e = k(s, "LABEL", { class: !0, "data-svelte-h": !0 }), R(e) !== "svelte-v7nxz2" && (e.textContent = l), i = C(s), t = k(s, "INPUT", { type: !0, class: !0 }), this.h();
730
+ },
731
+ h() {
732
+ h(e, "class", "svelte-zk15k"), h(t, "type", "number"), t.value = r = /*selectedComponent*/
733
+ n[5].props.minimum, h(t, "class", "svelte-zk15k");
734
+ },
735
+ m(s, c) {
736
+ O(s, e, c), O(s, i, c), O(s, t, c), p || (v = x(
737
+ t,
738
+ "input",
739
+ /*input_handler_5*/
740
+ n[40]
741
+ ), p = !0);
742
+ },
743
+ p(s, c) {
744
+ c[0] & /*selectedComponent*/
745
+ 32 && r !== (r = /*selectedComponent*/
746
+ s[5].props.minimum) && t.value !== r && (t.value = r);
747
+ },
748
+ d(s) {
749
+ s && (b(e), b(i), b(t)), p = !1, v();
750
+ }
751
+ };
752
+ }
753
+ function Ke(n) {
754
+ let e, l = "Maximum:", i, t, r, p, v;
755
+ return {
756
+ c() {
757
+ e = m("label"), e.textContent = l, i = y(), t = m("input"), this.h();
758
+ },
759
+ l(s) {
760
+ e = k(s, "LABEL", { class: !0, "data-svelte-h": !0 }), R(e) !== "svelte-elhw0w" && (e.textContent = l), i = C(s), t = k(s, "INPUT", { type: !0, class: !0 }), this.h();
761
+ },
762
+ h() {
763
+ h(e, "class", "svelte-zk15k"), h(t, "type", "number"), t.value = r = /*selectedComponent*/
764
+ n[5].props.maximum, h(t, "class", "svelte-zk15k");
765
+ },
766
+ m(s, c) {
767
+ O(s, e, c), O(s, i, c), O(s, t, c), p || (v = x(
768
+ t,
769
+ "input",
770
+ /*input_handler_6*/
771
+ n[41]
772
+ ), p = !0);
773
+ },
774
+ p(s, c) {
775
+ c[0] & /*selectedComponent*/
776
+ 32 && r !== (r = /*selectedComponent*/
777
+ s[5].props.maximum) && t.value !== r && (t.value = r);
778
+ },
779
+ d(s) {
780
+ s && (b(e), b(i), b(t)), p = !1, v();
781
+ }
782
+ };
783
+ }
784
+ function Qe(n) {
785
+ let e, l = "Step:", i, t, r, p, v;
786
+ return {
787
+ c() {
788
+ e = m("label"), e.textContent = l, i = y(), t = m("input"), this.h();
789
+ },
790
+ l(s) {
791
+ e = k(s, "LABEL", { class: !0, "data-svelte-h": !0 }), R(e) !== "svelte-rqjdj4" && (e.textContent = l), i = C(s), t = k(s, "INPUT", { type: !0, class: !0 }), this.h();
792
+ },
793
+ h() {
794
+ h(e, "class", "svelte-zk15k"), h(t, "type", "number"), t.value = r = /*selectedComponent*/
795
+ n[5].props.step, h(t, "class", "svelte-zk15k");
796
+ },
797
+ m(s, c) {
798
+ O(s, e, c), O(s, i, c), O(s, t, c), p || (v = x(
799
+ t,
800
+ "input",
801
+ /*input_handler_7*/
802
+ n[42]
803
+ ), p = !0);
804
+ },
805
+ p(s, c) {
806
+ c[0] & /*selectedComponent*/
807
+ 32 && r !== (r = /*selectedComponent*/
808
+ s[5].props.step) && t.value !== r && (t.value = r);
809
+ },
810
+ d(s) {
811
+ s && (b(e), b(i), b(t)), p = !1, v();
812
+ }
813
+ };
814
+ }
815
+ function vt(n) {
816
+ let e, l, i, t, r = "🎨 Gradio Designer", p, v, s = (
817
+ /*value*/
818
+ n[0].components.length + ""
819
+ ), c, ee, q, S, D, N = "📄 Export JSON", M, g, G = "🖼️ Export PNG", te, J, Z, I, T, U = "Components", X, W, pe, L, H, _e = "All Categories", ke, F, fe, K, le, Ce, Q = [], ie = /* @__PURE__ */ new Map(), he, se, $, Oe = "Properties", ge, ne, me, ce = Le(Object.keys(
820
+ /*componentsByCategory*/
821
+ n[7]
822
+ )), A = [];
823
+ for (let u = 0; u < ce.length; u += 1)
824
+ A[u] = Re(Ve(n, ce, u));
825
+ let ae = Le(
826
+ /*displayComponents*/
827
+ n[6]
828
+ ), B = [];
829
+ for (let u = 0; u < ae.length; u += 1)
830
+ B[u] = Fe(Me(n, ae, u));
831
+ let P = null;
832
+ ae.length || (P = He(n));
833
+ let de = Le(
834
+ /*value*/
835
+ n[0].components
836
+ );
837
+ const ye = (u) => (
838
+ /*component*/
839
+ u[50].id
840
+ );
841
+ for (let u = 0; u < de.length; u += 1) {
842
+ let _ = Be(n, de, u), a = ye(_);
843
+ ie.set(a, Q[u] = Ge(a, _));
844
+ }
845
+ function De(u, _) {
846
+ return (
847
+ /*selectedComponent*/
848
+ u[5] ? ct : pt
849
+ );
850
+ }
851
+ let o = De(n), d = o(n);
852
+ return {
853
+ c() {
854
+ e = m("div"), l = m("div"), i = m("div"), t = m("h3"), t.textContent = r, p = y(), v = m("span"), c = re(s), ee = re(" components"), q = y(), S = m("div"), D = m("button"), D.textContent = N, M = y(), g = m("button"), g.textContent = G, te = y(), J = m("div"), Z = m("div"), I = m("div"), T = m("h4"), T.textContent = U, X = y(), W = m("input"), pe = y(), L = m("select"), H = m("option"), H.textContent = _e;
855
+ for (let u = 0; u < A.length; u += 1)
856
+ A[u].c();
857
+ ke = y(), F = m("div");
858
+ for (let u = 0; u < B.length; u += 1)
859
+ B[u].c();
860
+ P && P.c(), fe = y(), K = m("div"), le = m("div"), Ce = y();
861
+ for (let u = 0; u < Q.length; u += 1)
862
+ Q[u].c();
863
+ he = y(), se = m("div"), $ = m("h4"), $.textContent = Oe, ge = y(), d.c(), this.h();
864
+ },
865
+ l(u) {
866
+ e = k(u, "DIV", { class: !0, id: !0 });
867
+ var _ = j(e);
868
+ l = k(_, "DIV", { class: !0 });
869
+ var a = j(l);
870
+ i = k(a, "DIV", { class: !0 });
871
+ var E = j(i);
872
+ t = k(E, "H3", { class: !0, "data-svelte-h": !0 }), R(t) !== "svelte-1dsn5ql" && (t.textContent = r), p = C(E), v = k(E, "SPAN", { class: !0 });
873
+ var V = j(v);
874
+ c = oe(V, s), ee = oe(V, " components"), V.forEach(b), E.forEach(b), q = C(a), S = k(a, "DIV", { class: !0 });
875
+ var w = j(S);
876
+ D = k(w, "BUTTON", {
877
+ class: !0,
878
+ type: !0,
879
+ "data-svelte-h": !0
880
+ }), R(D) !== "svelte-1n26als" && (D.textContent = N), M = C(w), g = k(w, "BUTTON", {
881
+ class: !0,
882
+ type: !0,
883
+ "data-svelte-h": !0
884
+ }), R(g) !== "svelte-1yzlvvh" && (g.textContent = G), w.forEach(b), a.forEach(b), te = C(_), J = k(_, "DIV", { class: !0 });
885
+ var z = j(J);
886
+ Z = k(z, "DIV", { class: !0 });
887
+ var ue = j(Z);
888
+ I = k(ue, "DIV", { class: !0 });
889
+ var be = j(I);
890
+ T = k(be, "H4", { class: !0, "data-svelte-h": !0 }), R(T) !== "svelte-6fxyga" && (T.textContent = U), X = C(be), W = k(be, "INPUT", {
891
+ type: !0,
892
+ placeholder: !0,
893
+ class: !0
894
+ }), pe = C(be), L = k(be, "SELECT", { class: !0 });
895
+ var ze = j(L);
896
+ H = k(ze, "OPTION", { "data-svelte-h": !0 }), R(H) !== "svelte-1dzjcyu" && (H.textContent = _e);
897
+ for (let ve = 0; ve < A.length; ve += 1)
898
+ A[ve].l(ze);
899
+ ze.forEach(b), be.forEach(b), ke = C(ue), F = k(ue, "DIV", { class: !0 });
900
+ var Y = j(F);
901
+ for (let ve = 0; ve < B.length; ve += 1)
902
+ B[ve].l(Y);
903
+ P && P.l(Y), Y.forEach(b), ue.forEach(b), fe = C(z), K = k(z, "DIV", { class: !0 });
904
+ var Ee = j(K);
905
+ le = k(Ee, "DIV", { class: !0 }), j(le).forEach(b), Ce = C(Ee);
906
+ for (let ve = 0; ve < Q.length; ve += 1)
907
+ Q[ve].l(Ee);
908
+ Ee.forEach(b), he = C(z), se = k(z, "DIV", { class: !0 });
909
+ var Ne = j(se);
910
+ $ = k(Ne, "H4", { class: !0, "data-svelte-h": !0 }), R($) !== "svelte-100vz0b" && ($.textContent = Oe), ge = C(Ne), d.l(Ne), Ne.forEach(b), z.forEach(b), _.forEach(b), this.h();
911
+ },
912
+ h() {
913
+ h(t, "class", "svelte-zk15k"), h(v, "class", "component-count svelte-zk15k"), h(i, "class", "toolbar-left svelte-zk15k"), h(D, "class", "export-btn svelte-zk15k"), h(D, "type", "button"), h(g, "class", "export-btn svelte-zk15k"), h(g, "type", "button"), h(S, "class", "toolbar-right svelte-zk15k"), h(l, "class", "toolbar svelte-zk15k"), h(T, "class", "svelte-zk15k"), h(W, "type", "text"), h(W, "placeholder", "Search components..."), h(W, "class", "search-input svelte-zk15k"), H.__value = "All", Pe(H, H.__value), h(L, "class", "category-select svelte-zk15k"), /*selectedCategory*/
914
+ n[3] === void 0 && $e(() => (
915
+ /*select_change_handler*/
916
+ n[28].call(L)
917
+ )), h(I, "class", "palette-header svelte-zk15k"), h(F, "class", "palette-content svelte-zk15k"), h(Z, "class", "palette svelte-zk15k"), h(le, "class", "canvas-grid svelte-zk15k"), h(K, "class", "canvas svelte-zk15k"), h($, "class", "svelte-zk15k"), h(se, "class", "properties svelte-zk15k"), h(J, "class", "designer-content svelte-zk15k"), h(e, "class", "designer-container svelte-zk15k"), h(
918
+ e,
919
+ "id",
920
+ /*elem_id*/
921
+ n[1]
922
+ );
923
+ },
924
+ m(u, _) {
925
+ O(u, e, _), f(e, l), f(l, i), f(i, t), f(i, p), f(i, v), f(v, c), f(v, ee), f(l, q), f(l, S), f(S, D), f(S, M), f(S, g), f(e, te), f(e, J), f(J, Z), f(Z, I), f(I, T), f(I, X), f(I, W), Pe(
926
+ W,
927
+ /*searchFilter*/
928
+ n[2]
929
+ ), f(I, pe), f(I, L), f(L, H);
930
+ for (let a = 0; a < A.length; a += 1)
931
+ A[a] && A[a].m(L, null);
932
+ xe(
933
+ L,
934
+ /*selectedCategory*/
935
+ n[3],
936
+ !0
937
+ ), f(Z, ke), f(Z, F);
938
+ for (let a = 0; a < B.length; a += 1)
939
+ B[a] && B[a].m(F, null);
940
+ P && P.m(F, null), f(J, fe), f(J, K), f(K, le), f(K, Ce);
941
+ for (let a = 0; a < Q.length; a += 1)
942
+ Q[a] && Q[a].m(K, null);
943
+ n[33](K), f(J, he), f(J, se), f(se, $), f(se, ge), d.m(se, null), ne || (me = [
944
+ x(
945
+ window,
946
+ "mousemove",
947
+ /*onCanvasMouseMove*/
948
+ n[18]
949
+ ),
950
+ x(
951
+ window,
952
+ "mouseup",
953
+ /*onCanvasMouseUp*/
954
+ n[19]
955
+ ),
956
+ x(
957
+ D,
958
+ "click",
959
+ /*exportAsJSON*/
960
+ n[15]
961
+ ),
962
+ x(
963
+ g,
964
+ "click",
965
+ /*exportAsPNG*/
966
+ n[16]
967
+ ),
968
+ x(
969
+ W,
970
+ "input",
971
+ /*input_input_handler*/
972
+ n[27]
973
+ ),
974
+ x(
975
+ L,
976
+ "change",
977
+ /*select_change_handler*/
978
+ n[28]
979
+ ),
980
+ x(K, "dragover", _t),
981
+ x(
982
+ K,
983
+ "drop",
984
+ /*onDrop*/
985
+ n[9]
986
+ )
987
+ ], ne = !0);
988
+ },
989
+ p(u, _) {
990
+ if (_[0] & /*value*/
991
+ 1 && s !== (s = /*value*/
992
+ u[0].components.length + "") && Te(c, s), _[0] & /*searchFilter*/
993
+ 4 && W.value !== /*searchFilter*/
994
+ u[2] && Pe(
995
+ W,
996
+ /*searchFilter*/
997
+ u[2]
998
+ ), _[0] & /*componentsByCategory*/
999
+ 128) {
1000
+ ce = Le(Object.keys(
1001
+ /*componentsByCategory*/
1002
+ u[7]
1003
+ ));
1004
+ let a;
1005
+ for (a = 0; a < ce.length; a += 1) {
1006
+ const E = Ve(u, ce, a);
1007
+ A[a] ? A[a].p(E, _) : (A[a] = Re(E), A[a].c(), A[a].m(L, null));
1008
+ }
1009
+ for (; a < A.length; a += 1)
1010
+ A[a].d(1);
1011
+ A.length = ce.length;
1012
+ }
1013
+ if (_[0] & /*selectedCategory, componentsByCategory*/
1014
+ 136 && xe(
1015
+ L,
1016
+ /*selectedCategory*/
1017
+ u[3]
1018
+ ), _[0] & /*onDragStart, displayComponents, searchFilter*/
1019
+ 324) {
1020
+ ae = Le(
1021
+ /*displayComponents*/
1022
+ u[6]
1023
+ );
1024
+ let a;
1025
+ for (a = 0; a < ae.length; a += 1) {
1026
+ const E = Me(u, ae, a);
1027
+ B[a] ? B[a].p(E, _) : (B[a] = Fe(E), B[a].c(), B[a].m(F, null));
1028
+ }
1029
+ for (; a < B.length; a += 1)
1030
+ B[a].d(1);
1031
+ B.length = ae.length, !ae.length && P ? P.p(u, _) : ae.length ? P && (P.d(1), P = null) : (P = He(u), P.c(), P.m(F, null));
1032
+ }
1033
+ _[0] & /*value, selectedComponent, selectComponent, onComponentMouseDown, deleteComponent*/
1034
+ 148513 && (de = Le(
1035
+ /*value*/
1036
+ u[0].components
1037
+ ), Q = at(Q, _, ye, 1, u, de, ie, K, tt, Ge, null, Be)), o === (o = De(u)) && d ? d.p(u, _) : (d.d(1), d = o(u), d && (d.c(), d.m(se, null))), _[0] & /*elem_id*/
1038
+ 2 && h(
1039
+ e,
1040
+ "id",
1041
+ /*elem_id*/
1042
+ u[1]
1043
+ );
1044
+ },
1045
+ i: Ie,
1046
+ o: Ie,
1047
+ d(u) {
1048
+ u && b(e), Ae(A, u), Ae(B, u), P && P.d();
1049
+ for (let _ = 0; _ < Q.length; _ += 1)
1050
+ Q[_].d();
1051
+ n[33](null), d.d(), ne = !1, je(me);
1052
+ }
1053
+ };
1054
+ }
1055
+ function _t(n) {
1056
+ n.preventDefault(), n.dataTransfer && (n.dataTransfer.dropEffect = "copy");
1057
+ }
1058
+ function kt(n) {
1059
+ return {
1060
+ Textbox: {
1061
+ label: "Text Input",
1062
+ placeholder: "Enter text...",
1063
+ value: ""
1064
+ },
1065
+ TextArea: {
1066
+ label: "Text Area",
1067
+ placeholder: "Enter multiple lines...",
1068
+ lines: 3,
1069
+ value: ""
1070
+ },
1071
+ Button: {
1072
+ value: "Click me",
1073
+ variant: "secondary",
1074
+ size: "sm"
1075
+ },
1076
+ Slider: {
1077
+ label: "Slider",
1078
+ minimum: 0,
1079
+ maximum: 100,
1080
+ step: 1,
1081
+ value: 50
1082
+ },
1083
+ Number: { label: "Number", value: 0, precision: 0 },
1084
+ Checkbox: { label: "Checkbox", value: !1 },
1085
+ CheckboxGroup: {
1086
+ label: "Checkbox Group",
1087
+ choices: ["Option 1", "Option 2"],
1088
+ value: []
1089
+ },
1090
+ Radio: {
1091
+ label: "Radio",
1092
+ choices: ["Option 1", "Option 2"],
1093
+ value: "Option 1"
1094
+ },
1095
+ Dropdown: {
1096
+ label: "Dropdown",
1097
+ choices: ["Option 1", "Option 2"],
1098
+ value: "Option 1",
1099
+ multiselect: !1
1100
+ },
1101
+ Toggle: { label: "Toggle", value: !1 },
1102
+ ColorPicker: { label: "Color Picker", value: "#ff0000" },
1103
+ Date: { label: "Date", value: "2025-01-01" },
1104
+ Time: { label: "Time", value: "12:00" },
1105
+ File: {
1106
+ label: "Upload File",
1107
+ file_types: [".txt", ".pdf"]
1108
+ },
1109
+ Image: {
1110
+ label: "Image",
1111
+ type: "pil",
1112
+ interactive: !0
1113
+ },
1114
+ Video: { label: "Video", format: "mp4" },
1115
+ Audio: { label: "Audio" },
1116
+ Dataframe: {
1117
+ headers: ["Column 1", "Column 2"],
1118
+ datatype: ["str", "str"],
1119
+ value: []
1120
+ },
1121
+ JSON: { value: "{}" },
1122
+ Markdown: { value: "# Markdown Text" },
1123
+ HTML: { value: "<p>HTML Content</p>" },
1124
+ Label: { value: "Label Text" },
1125
+ Progress: { value: 0.5 }
1126
+ }[n] || {};
1127
+ }
1128
+ function mt(n, e, l) {
1129
+ let i, t, r, { gradio: p } = e, { elem_id: v = "" } = e;
1130
+ const s = [];
1131
+ let { value: c = { components: [], layout: "blocks" } } = e;
1132
+ const ee = void 0, q = "interactive", S = {
1133
+ Input: [
1134
+ {
1135
+ type: "Textbox",
1136
+ label: "Text Input",
1137
+ icon: "📝"
1138
+ },
1139
+ {
1140
+ type: "TextArea",
1141
+ label: "Text Area",
1142
+ icon: "📄"
1143
+ },
1144
+ {
1145
+ type: "Number",
1146
+ label: "Number",
1147
+ icon: "🔢"
1148
+ },
1149
+ {
1150
+ type: "Slider",
1151
+ label: "Slider",
1152
+ icon: "🎚️"
1153
+ },
1154
+ {
1155
+ type: "Checkbox",
1156
+ label: "Checkbox",
1157
+ icon: "☑️"
1158
+ },
1159
+ {
1160
+ type: "CheckboxGroup",
1161
+ label: "Checkbox Group",
1162
+ icon: "☑️"
1163
+ },
1164
+ {
1165
+ type: "Radio",
1166
+ label: "Radio",
1167
+ icon: "🔘"
1168
+ },
1169
+ {
1170
+ type: "Dropdown",
1171
+ label: "Dropdown",
1172
+ icon: "📋"
1173
+ },
1174
+ {
1175
+ type: "Toggle",
1176
+ label: "Toggle",
1177
+ icon: "🔄"
1178
+ },
1179
+ {
1180
+ type: "ColorPicker",
1181
+ label: "Color Picker",
1182
+ icon: "🎨"
1183
+ },
1184
+ { type: "Date", label: "Date", icon: "📅" },
1185
+ { type: "Time", label: "Time", icon: "⏰" },
1186
+ {
1187
+ type: "File",
1188
+ label: "File Upload",
1189
+ icon: "📁"
1190
+ }
1191
+ ],
1192
+ Action: [
1193
+ {
1194
+ type: "Button",
1195
+ label: "Button",
1196
+ icon: "🔘"
1197
+ }
1198
+ ],
1199
+ Media: [
1200
+ {
1201
+ type: "Image",
1202
+ label: "Image",
1203
+ icon: "🖼️"
1204
+ },
1205
+ {
1206
+ type: "Video",
1207
+ label: "Video",
1208
+ icon: "🎥"
1209
+ },
1210
+ {
1211
+ type: "Audio",
1212
+ label: "Audio",
1213
+ icon: "🎵"
1214
+ }
1215
+ ],
1216
+ Data: [
1217
+ {
1218
+ type: "Dataframe",
1219
+ label: "Dataframe",
1220
+ icon: "📊"
1221
+ },
1222
+ { type: "JSON", label: "JSON", icon: "📋" }
1223
+ ],
1224
+ Display: [
1225
+ {
1226
+ type: "Markdown",
1227
+ label: "Markdown",
1228
+ icon: "📝"
1229
+ },
1230
+ { type: "HTML", label: "HTML", icon: "🌐" },
1231
+ {
1232
+ type: "Label",
1233
+ label: "Label",
1234
+ icon: "🏷️"
1235
+ },
1236
+ {
1237
+ type: "Progress",
1238
+ label: "Progress",
1239
+ icon: "📈"
1240
+ }
1241
+ ]
1242
+ };
1243
+ let D = !1;
1244
+ ot(() => {
1245
+ l(24, D = !0);
1246
+ });
1247
+ let N = null, M, g = null, G = "", te = "All";
1248
+ function J(o, d) {
1249
+ N = d, o.dataTransfer && (o.dataTransfer.effectAllowed = "copy");
1250
+ }
1251
+ function Z(o) {
1252
+ if (o.preventDefault(), !N) return;
1253
+ const d = M.getBoundingClientRect(), u = o.clientX - d.left, _ = o.clientY - d.top, a = {
1254
+ id: `${N.type.toLowerCase()}_${Date.now()}`,
1255
+ type: N.type,
1256
+ position: { x: u, y: _ },
1257
+ size: { width: 200, height: 100 },
1258
+ props: kt(N.type)
1259
+ };
1260
+ l(0, c = Object.assign(Object.assign({}, c), {
1261
+ components: [...c.components, a]
1262
+ })), p.dispatch("change", c), N = null;
1263
+ }
1264
+ function I(o) {
1265
+ l(5, g = o);
1266
+ }
1267
+ function T(o, d) {
1268
+ if (!g) return;
1269
+ o === "choices" && typeof d == "string" ? d = d.split(",").map((_) => _.trim()).filter((_) => _) : o === "file_types" && typeof d == "string" && (d = d.split(",").map((_) => _.trim()).filter((_) => _));
1270
+ const u = c.components.map((_) => _.id === g.id ? Object.assign(Object.assign({}, _), {
1271
+ props: Object.assign(Object.assign({}, _.props), { [o]: d })
1272
+ }) : _);
1273
+ l(5, g = Object.assign(Object.assign({}, g), {
1274
+ props: Object.assign(Object.assign({}, g.props), { [o]: d })
1275
+ })), l(0, c = Object.assign(Object.assign({}, c), { components: u })), p.dispatch("change", c);
1276
+ }
1277
+ function U(o, d, u) {
1278
+ const _ = c.components.map((a) => a.id === o.id ? Object.assign(Object.assign({}, a), { position: { x: d, y: u } }) : a);
1279
+ l(0, c = Object.assign(Object.assign({}, c), { components: _ })), p.dispatch("change", c);
1280
+ }
1281
+ function X(o, d, u) {
1282
+ const _ = c.components.map((a) => a.id === o.id ? Object.assign(Object.assign({}, a), {
1283
+ size: { width: d, height: u }
1284
+ }) : a);
1285
+ (g == null ? void 0 : g.id) === o.id && l(5, g = Object.assign(Object.assign({}, g), {
1286
+ size: { width: d, height: u }
1287
+ })), l(0, c = Object.assign(Object.assign({}, c), { components: _ })), p.dispatch("change", c);
1288
+ }
1289
+ function W(o) {
1290
+ const d = c.components.filter((u) => u.id !== o);
1291
+ l(0, c = Object.assign(Object.assign({}, c), { components: d })), l(5, g = null), p.dispatch("change", c);
1292
+ }
1293
+ function pe() {
1294
+ const o = Object.assign(Object.assign({}, c), {
1295
+ metadata: {
1296
+ version: "1.0",
1297
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
1298
+ app_type: "gradio_interface",
1299
+ component_count: c.components.length
1300
+ }
1301
+ }), d = JSON.stringify(o, null, 2), u = new Blob([d], { type: "application/json" }), _ = URL.createObjectURL(u), a = document.createElement("a");
1302
+ a.href = _, a.download = "gradio-design.json", a.click(), URL.revokeObjectURL(_);
1303
+ }
1304
+ function L() {
1305
+ try {
1306
+ const o = document.createElement("canvas"), d = o.getContext("2d"), u = M.getBoundingClientRect();
1307
+ o.width = u.width * 2, o.height = u.height * 2, d.scale(2, 2), d.fillStyle = "#ffffff", d.fillRect(0, 0, u.width, u.height), d.strokeStyle = "rgba(0,0,0,0.1)", d.lineWidth = 1;
1308
+ for (let a = 0; a <= u.width; a += 20)
1309
+ d.moveTo(a, 0), d.lineTo(a, u.height);
1310
+ for (let a = 0; a <= u.height; a += 20)
1311
+ d.moveTo(0, a), d.lineTo(u.width, a);
1312
+ d.stroke(), c.components.forEach((a) => {
1313
+ const E = i.find((V) => V.type === a.type);
1314
+ d.fillStyle = "#ffffff", d.strokeStyle = "#ddd", d.lineWidth = 2, d.fillRect(a.position.x, a.position.y, a.size.width, a.size.height), d.strokeRect(a.position.x, a.position.y, a.size.width, a.size.height), d.fillStyle = "#333", d.font = "16px Arial", d.textAlign = "center", d.fillText(
1315
+ (E == null ? void 0 : E.icon) || "📦",
1316
+ a.position.x + a.size.width / 2,
1317
+ a.position.y + 25
1318
+ ), d.font = "12px Arial", d.fillText(a.type, a.position.x + a.size.width / 2, a.position.y + a.size.height / 2), d.fillText(a.props.label || a.props.value || "", a.position.x + a.size.width / 2, a.position.y + a.size.height / 2 + 15);
1319
+ });
1320
+ const _ = document.createElement("a");
1321
+ _.download = "gradio-design.png", _.href = o.toDataURL("image/png"), _.click();
1322
+ } catch (o) {
1323
+ console.error("Canvas export failed:", o), alert("PNG export failed. Check console for details.");
1324
+ }
1325
+ }
1326
+ let H = !1, _e = { x: 0, y: 0 };
1327
+ function ke(o, d) {
1328
+ if (o.button !== 0) return;
1329
+ H = !0, l(5, g = d);
1330
+ const u = M.getBoundingClientRect();
1331
+ _e.x = o.clientX - u.left - d.position.x, _e.y = o.clientY - u.top - d.position.y, o.preventDefault();
1332
+ }
1333
+ function F(o) {
1334
+ if (!H || !g) return;
1335
+ const d = M.getBoundingClientRect(), u = o.clientX - d.left - _e.x, _ = o.clientY - d.top - _e.y;
1336
+ U(g, Math.max(0, u), Math.max(0, _));
1337
+ }
1338
+ function fe() {
1339
+ H = !1;
1340
+ }
1341
+ function K() {
1342
+ G = this.value, l(2, G);
1343
+ }
1344
+ function le() {
1345
+ te = nt(this), l(3, te), l(7, S);
1346
+ }
1347
+ const Ce = (o, d) => J(d, o), Q = (o) => W(o.id), ie = (o) => I(o), he = (o, d) => ke(d, o);
1348
+ function se(o) {
1349
+ et[o ? "unshift" : "push"](() => {
1350
+ M = o, l(4, M);
1351
+ });
1352
+ }
1353
+ const $ = (o) => T("label", o.target.value), Oe = (o) => T("placeholder", o.target.value), ge = (o) => T("value", o.target.checked), ne = (o) => T("value", parseFloat(o.target.value) || 0), me = (o) => T("value", o.target.value), ce = (o) => T("choices", o.target.value), A = (o) => T("minimum", parseFloat(o.target.value) || 0), ae = (o) => T("maximum", parseFloat(o.target.value) || 100), B = (o) => T("step", parseFloat(o.target.value) || 1), P = (o) => X(g, parseInt(o.target.value) || 200, g.size.height), de = (o) => X(g, g.size.width, parseInt(o.target.value) || 100), ye = (o) => U(g, parseInt(o.target.value) || 0, g.position.y), De = (o) => U(g, g.position.x, parseInt(o.target.value) || 0);
1354
+ return n.$$set = (o) => {
1355
+ "gradio" in o && l(20, p = o.gradio), "elem_id" in o && l(1, v = o.elem_id), "value" in o && l(0, c = o.value);
1356
+ }, n.$$.update = () => {
1357
+ n.$$.dirty[0] & /*selectedCategory, allComponents, searchFilter*/
1358
+ 33554444 && l(26, t = (() => {
1359
+ if (te === "All") {
1360
+ let o = i;
1361
+ return G.trim() ? o.filter((d) => d.type.toLowerCase().includes(G.toLowerCase()) || d.label.toLowerCase().includes(G.toLowerCase())) : o;
1362
+ } else {
1363
+ let o = S[te] || [];
1364
+ return G.trim() ? o.filter((d) => d.type.toLowerCase().includes(G.toLowerCase()) || d.label.toLowerCase().includes(G.toLowerCase())) : o;
1365
+ }
1366
+ })()), n.$$.dirty[0] & /*mounted, filteredComponents, allComponents*/
1367
+ 117440512 && l(6, r = D ? t : i);
1368
+ }, l(25, i = Object.values(S).flat()), [
1369
+ c,
1370
+ v,
1371
+ G,
1372
+ te,
1373
+ M,
1374
+ g,
1375
+ r,
1376
+ S,
1377
+ J,
1378
+ Z,
1379
+ I,
1380
+ T,
1381
+ U,
1382
+ X,
1383
+ W,
1384
+ pe,
1385
+ L,
1386
+ ke,
1387
+ F,
1388
+ fe,
1389
+ p,
1390
+ s,
1391
+ ee,
1392
+ q,
1393
+ D,
1394
+ i,
1395
+ t,
1396
+ K,
1397
+ le,
1398
+ Ce,
1399
+ Q,
1400
+ ie,
1401
+ he,
1402
+ se,
1403
+ $,
1404
+ Oe,
1405
+ ge,
1406
+ ne,
1407
+ me,
1408
+ ce,
1409
+ A,
1410
+ ae,
1411
+ B,
1412
+ P,
1413
+ de,
1414
+ ye,
1415
+ De
1416
+ ];
1417
+ }
1418
+ class bt extends Ze {
1419
+ constructor(e) {
1420
+ super(), lt(
1421
+ this,
1422
+ e,
1423
+ mt,
1424
+ vt,
1425
+ st,
1426
+ {
1427
+ gradio: 20,
1428
+ elem_id: 1,
1429
+ elem_classes: 21,
1430
+ value: 0,
1431
+ loading_status: 22,
1432
+ mode: 23
1433
+ },
1434
+ null,
1435
+ [-1, -1]
1436
+ );
1437
+ }
1438
+ get elem_classes() {
1439
+ return this.$$.ctx[21];
1440
+ }
1441
+ get loading_status() {
1442
+ return this.$$.ctx[22];
1443
+ }
1444
+ get mode() {
1445
+ return this.$$.ctx[23];
1446
+ }
1447
+ }
1448
+ export {
1449
+ bt as default
1450
+ };
src/backend/gradio_gradiodesigner/templates/component/style.css ADDED
@@ -0,0 +1 @@
 
 
1
+ .designer-container.svelte-zk15k.svelte-zk15k{display:flex;flex-direction:column;height:700px;border:1px solid #ddd;border-radius:8px;overflow:hidden;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.toolbar.svelte-zk15k.svelte-zk15k{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;background:#f8f9fa;border-bottom:1px solid #ddd}.toolbar-left.svelte-zk15k.svelte-zk15k{display:flex;align-items:center;gap:12px}.toolbar.svelte-zk15k h3.svelte-zk15k{margin:0;font-size:16px;font-weight:600}.component-count.svelte-zk15k.svelte-zk15k{background:#e9ecef;padding:2px 8px;border-radius:12px;font-size:12px;color:#495057}.toolbar-right.svelte-zk15k.svelte-zk15k{display:flex;gap:8px}.export-btn.svelte-zk15k.svelte-zk15k{padding:6px 12px;background:#007bff;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:12px}.export-btn.svelte-zk15k.svelte-zk15k:hover{background:#0056b3}.designer-content.svelte-zk15k.svelte-zk15k{display:grid!important;grid-template-columns:250px 1fr 280px!important;grid-template-areas:"palette canvas properties"!important;flex:1;height:100%;min-height:0}.palette.svelte-zk15k.svelte-zk15k{grid-area:palette!important;background:#f8f9fa;border-right:1px solid #ddd;display:flex;flex-direction:column;overflow:hidden}.canvas.svelte-zk15k.svelte-zk15k{grid-area:canvas!important;position:relative;background:#fff;overflow:hidden;-webkit-user-select:none;user-select:none}.properties.svelte-zk15k.svelte-zk15k{grid-area:properties!important;background:#f8f9fa;padding:16px;border-left:1px solid #ddd;overflow-y:auto}.palette-header.svelte-zk15k.svelte-zk15k{padding:12px 16px;border-bottom:1px solid #ddd;background:#fff;flex-shrink:0;min-height:120px;max-height:120px;overflow:hidden}.palette.svelte-zk15k h4.svelte-zk15k{margin:0 0 8px;font-size:14px;font-weight:600}.search-input.svelte-zk15k.svelte-zk15k,.category-select.svelte-zk15k.svelte-zk15k{width:100%;padding:6px 8px;border:1px solid #ddd;border-radius:4px;font-size:12px;margin-bottom:6px;box-sizing:border-box}.palette-content.svelte-zk15k.svelte-zk15k{flex:1;overflow-y:auto;padding:8px;min-height:0;background:#f8f9fa}.palette-item.svelte-zk15k.svelte-zk15k{display:flex;align-items:center;padding:8px;margin-bottom:4px;background:#fff;border:1px solid #e1e5e9;border-radius:4px;cursor:grab;-webkit-user-select:none;user-select:none}.palette-item.svelte-zk15k.svelte-zk15k:hover{background:#f0f0f0}.no-components.svelte-zk15k.svelte-zk15k{padding:20px;text-align:center;color:#666;font-size:12px;background:#fff;border-radius:4px;border:1px solid #e1e5e9}.icon.svelte-zk15k.svelte-zk15k{margin-right:8px;font-size:16px}.label.svelte-zk15k.svelte-zk15k{font-size:12px}.canvas-grid.svelte-zk15k.svelte-zk15k{position:absolute;top:0;left:0;right:0;bottom:0;background-image:linear-gradient(rgba(0,0,0,.1) 1px,transparent 1px),linear-gradient(90deg,rgba(0,0,0,.1) 1px,transparent 1px);background-size:20px 20px;opacity:.3}.canvas-component.svelte-zk15k.svelte-zk15k{position:absolute;border:2px solid #ddd;border-radius:4px;background:#fff;cursor:move;padding:8px;box-sizing:border-box}.canvas-component.svelte-zk15k.svelte-zk15k:hover{border-color:#007bff}.canvas-component.selected.svelte-zk15k.svelte-zk15k{border-color:#ff6b6b;box-shadow:0 0 0 2px #ff6b6b4d}.component-preview.svelte-zk15k.svelte-zk15k{display:flex;flex-direction:column;height:100%;text-align:center;pointer-events:none}.component-header.svelte-zk15k.svelte-zk15k{display:flex;justify-content:space-between;align-items:center;margin-bottom:4px}.type.svelte-zk15k.svelte-zk15k{font-weight:700;font-size:12px;color:#666}.delete-btn.svelte-zk15k.svelte-zk15k{background:none;border:none;cursor:pointer;font-size:10px;padding:2px;opacity:.7;pointer-events:auto}.delete-btn.svelte-zk15k.svelte-zk15k:hover{opacity:1}.properties.svelte-zk15k h4.svelte-zk15k{margin:0 0 16px;font-size:14px;font-weight:600}.property-group.svelte-zk15k.svelte-zk15k{display:flex;flex-direction:column;gap:8px}.property-header.svelte-zk15k.svelte-zk15k{padding:12px;background:#fff;border-radius:4px;border:1px solid #e1e5e9;margin-bottom:12px}.size-section.svelte-zk15k.svelte-zk15k{margin-top:16px;padding-top:16px;border-top:1px solid #ddd}.size-section.svelte-zk15k h5.svelte-zk15k{margin:0 0 8px;font-size:12px;font-weight:600}.size-controls.svelte-zk15k.svelte-zk15k{display:grid;grid-template-columns:1fr 1fr;gap:8px}.property-group.svelte-zk15k label.svelte-zk15k{font-size:12px;font-weight:500;color:#333}.property-group.svelte-zk15k input.svelte-zk15k{padding:6px 8px;border:1px solid #ddd;border-radius:4px;font-size:12px}.help-text.svelte-zk15k.svelte-zk15k{margin-top:20px;padding:12px;background:#fff;border-radius:4px;border:1px solid #e1e5e9}.help-text.svelte-zk15k ul.svelte-zk15k{margin:8px 0 0;padding-left:16px}.help-text.svelte-zk15k li.svelte-zk15k{font-size:11px;margin-bottom:4px}
src/backend/gradio_gradiodesigner/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_gradiodesigner/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,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from gradio_gradiodesigner import GradioDesigner
3
+ import json
4
+
5
+ def analyze_design(design_config):
6
+ """Analyze the design configuration"""
7
+ if not design_config or not isinstance(design_config, dict):
8
+ return "No design configuration provided"
9
+
10
+ components = design_config.get('components', [])
11
+
12
+ # Count components by type
13
+ component_types = {}
14
+ for comp in components:
15
+ comp_type = comp.get('type', 'Unknown')
16
+ component_types[comp_type] = component_types.get(comp_type, 0) + 1
17
+
18
+ # Calculate coverage area
19
+ if components:
20
+ positions = [(comp['position']['x'], comp['position']['y']) for comp in components]
21
+ min_x, min_y = min(pos[0] for pos in positions), min(pos[1] for pos in positions)
22
+ max_x, max_y = max(pos[0] for pos in positions), max(pos[1] for pos in positions)
23
+ coverage = f"{max_x - min_x} x {max_y - min_y} pixels"
24
+ else:
25
+ coverage = "No components"
26
+
27
+ analysis = f"""📊 **Design Analysis**
28
+
29
+ **Component Summary:**
30
+ • Total components: {len(components)}
31
+ • Component types: {dict(component_types)}
32
+ • Canvas coverage: {coverage}
33
+
34
+ **Component Details:**
35
+ """
36
+
37
+ for i, comp in enumerate(components, 1):
38
+ analysis += f"\n{i}. **{comp['type']}** (`{comp['id']}`)"
39
+ analysis += f"\n - Position: ({comp['position']['x']}, {comp['position']['y']})"
40
+ analysis += f"\n - Size: {comp['size']['width']}×{comp['size']['height']}"
41
+ if comp.get('props', {}).get('label'):
42
+ analysis += f"\n - Label: \"{comp['props']['label']}\""
43
+
44
+ return analysis
45
+
46
+ def generate_gradio_code(design_config):
47
+ """Generate complete Gradio code from design"""
48
+ if not design_config or not isinstance(design_config, dict):
49
+ return "# No design to generate code from"
50
+
51
+ components = design_config.get('components', [])
52
+
53
+ code = '''import gradio as gr
54
+
55
+ def process_input(*args):
56
+ """Process the inputs from your app"""
57
+ return "Hello from your generated app!"
58
+
59
+ with gr.Blocks(title="Generated Gradio App") as demo:
60
+ gr.Markdown("# 🚀 Generated Gradio App")
61
+ gr.Markdown("This app was generated from your visual design!")
62
+
63
+ '''
64
+
65
+ # Sort components by position (top to bottom, left to right)
66
+ sorted_components = sorted(components, key=lambda c: (c['position']['y'], c['position']['x']))
67
+
68
+ component_vars = []
69
+
70
+ for comp in sorted_components:
71
+ comp_type = comp.get('type', 'Textbox')
72
+ comp_id = comp.get('id', 'component')
73
+ props = comp.get('props', {})
74
+
75
+ # Build component declaration
76
+ prop_parts = []
77
+ for key, value in props.items():
78
+ if key in ['label', 'placeholder', 'value'] and isinstance(value, str):
79
+ prop_parts.append(f'{key}="{value}"')
80
+ elif key in ['minimum', 'maximum', 'step', 'lines', 'max_length', 'precision'] and isinstance(value, (int, float)):
81
+ prop_parts.append(f'{key}={value}')
82
+ elif key == 'choices' and isinstance(value, list):
83
+ prop_parts.append(f'{key}={value}')
84
+ elif isinstance(value, bool):
85
+ prop_parts.append(f'{key}={value}')
86
+
87
+ prop_string = ", ".join(prop_parts) if prop_parts else ""
88
+
89
+ code += f" {comp_id} = gr.{comp_type}({prop_string})\n"
90
+ component_vars.append(comp_id)
91
+
92
+ # Add a simple interaction if there are components
93
+ if component_vars:
94
+ inputs = [var for var in component_vars if not var.startswith('button')]
95
+ outputs = [var for var in component_vars if var.startswith('button')]
96
+
97
+ if not outputs:
98
+ outputs = inputs[:1] # Use first input as output if no buttons
99
+
100
+ if inputs and outputs:
101
+ code += f"\n # Add interactions\n"
102
+ code += f" # Example: connect inputs to outputs\n"
103
+ code += f" # {outputs[0]}.click(process_input, inputs=[{', '.join(inputs)}], outputs=[{outputs[0]}])\n"
104
+
105
+ code += '''
106
+ if __name__ == "__main__":
107
+ demo.launch()
108
+ '''
109
+
110
+ return code
111
+
112
+ with gr.Blocks(title="Gradio Visual Designer Pro", theme=gr.themes.Soft()) as demo:
113
+ gr.Markdown("""
114
+ # 🎨 Gradio Visual Designer Pro
115
+
116
+ **Build your Gradio apps visually!** Drag and drop components, customize properties, and generate production-ready code.
117
+
118
+ **Features:** 25+ Gradio components • Real-time editing • Code generation • Export options
119
+ """)
120
+
121
+ with gr.Row():
122
+ designer = GradioDesigner(
123
+ label="Visual App Designer",
124
+ value={"components": [], "layout": "blocks"}
125
+ )
126
+
127
+ with gr.Row():
128
+ with gr.Column(scale=1):
129
+ analysis_output = gr.Markdown(
130
+ value="Design analysis will appear here...",
131
+ label="Design Analysis"
132
+ )
133
+
134
+ with gr.Column(scale=1):
135
+ code_output = gr.Code(
136
+ label="Generated Gradio Code",
137
+ language="python",
138
+ value="# Design your app above to see generated code",
139
+ lines=20
140
+ )
141
+
142
+ with gr.Row():
143
+ analyze_btn = gr.Button("📊 Analyze Design", variant="secondary")
144
+ generate_btn = gr.Button("🚀 Generate Code", variant="primary")
145
+ clear_btn = gr.Button("🗑️ Clear All", variant="stop")
146
+
147
+ # Event handlers
148
+ designer.change(
149
+ fn=analyze_design,
150
+ inputs=[designer],
151
+ outputs=[analysis_output]
152
+ )
153
+
154
+ analyze_btn.click(
155
+ fn=analyze_design,
156
+ inputs=[designer],
157
+ outputs=[analysis_output]
158
+ )
159
+
160
+ generate_btn.click(
161
+ fn=generate_gradio_code,
162
+ inputs=[designer],
163
+ outputs=[code_output]
164
+ )
165
+
166
+ clear_btn.click(
167
+ fn=lambda: {"components": [], "layout": "blocks"},
168
+ outputs=[designer]
169
+ )
170
+
171
+ if __name__ == "__main__":
172
+ 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_gradiodesigner
src/demo/space.py ADDED
@@ -0,0 +1,293 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import gradio as gr
3
+ from app import demo as app
4
+ import os
5
+
6
+ _docs = {'GradioDesigner': {'description': 'A visual designer component for building Gradio layouts with all components', 'members': {'__init__': {'value': {'type': 'dict | None', 'default': 'None', 'description': None}, 'label': {'type': 'str | None', 'default': 'None', 'description': None}}, 'postprocess': {'value': {'type': 'dict | None', 'description': None}}, 'preprocess': {'return': {'type': 'dict | None', 'description': None}, 'value': None}}, 'events': {'change': {'type': None, 'default': None, 'description': 'Triggered when the value of the GradioDesigner 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 GradioDesigner.'}}}, '__meta__': {'additional_interfaces': {}, 'user_fn_refs': {'GradioDesigner': []}}}
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_gradiodesigner`
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
+ gradio designer
28
+ """, elem_classes=["md-custom"], header_links=True)
29
+ app.render()
30
+ gr.Markdown(
31
+ """
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install gradio_gradiodesigner
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ ```python
41
+ import gradio as gr
42
+ from gradio_gradiodesigner import GradioDesigner
43
+ import json
44
+
45
+ def analyze_design(design_config):
46
+ \"\"\"Analyze the design configuration\"\"\"
47
+ if not design_config or not isinstance(design_config, dict):
48
+ return "No design configuration provided"
49
+
50
+ components = design_config.get('components', [])
51
+
52
+ # Count components by type
53
+ component_types = {}
54
+ for comp in components:
55
+ comp_type = comp.get('type', 'Unknown')
56
+ component_types[comp_type] = component_types.get(comp_type, 0) + 1
57
+
58
+ # Calculate coverage area
59
+ if components:
60
+ positions = [(comp['position']['x'], comp['position']['y']) for comp in components]
61
+ min_x, min_y = min(pos[0] for pos in positions), min(pos[1] for pos in positions)
62
+ max_x, max_y = max(pos[0] for pos in positions), max(pos[1] for pos in positions)
63
+ coverage = f"{max_x - min_x} x {max_y - min_y} pixels"
64
+ else:
65
+ coverage = "No components"
66
+
67
+ analysis = f\"\"\"📊 **Design Analysis**
68
+
69
+ **Component Summary:**
70
+ • Total components: {len(components)}
71
+ • Component types: {dict(component_types)}
72
+ • Canvas coverage: {coverage}
73
+
74
+ **Component Details:**
75
+ \"\"\"
76
+
77
+ for i, comp in enumerate(components, 1):
78
+ analysis += f"\n{i}. **{comp['type']}** (`{comp['id']}`)"
79
+ analysis += f"\n - Position: ({comp['position']['x']}, {comp['position']['y']})"
80
+ analysis += f"\n - Size: {comp['size']['width']}×{comp['size']['height']}"
81
+ if comp.get('props', {}).get('label'):
82
+ analysis += f"\n - Label: \"{comp['props']['label']}\""
83
+
84
+ return analysis
85
+
86
+ def generate_gradio_code(design_config):
87
+ \"\"\"Generate complete Gradio code from design\"\"\"
88
+ if not design_config or not isinstance(design_config, dict):
89
+ return "# No design to generate code from"
90
+
91
+ components = design_config.get('components', [])
92
+
93
+ code = '''import gradio as gr
94
+
95
+ def process_input(*args):
96
+ \"\"\"Process the inputs from your app\"\"\"
97
+ return "Hello from your generated app!"
98
+
99
+ with gr.Blocks(title="Generated Gradio App") as demo:
100
+ gr.Markdown("# 🚀 Generated Gradio App")
101
+ gr.Markdown("This app was generated from your visual design!")
102
+
103
+ '''
104
+
105
+ # Sort components by position (top to bottom, left to right)
106
+ sorted_components = sorted(components, key=lambda c: (c['position']['y'], c['position']['x']))
107
+
108
+ component_vars = []
109
+
110
+ for comp in sorted_components:
111
+ comp_type = comp.get('type', 'Textbox')
112
+ comp_id = comp.get('id', 'component')
113
+ props = comp.get('props', {})
114
+
115
+ # Build component declaration
116
+ prop_parts = []
117
+ for key, value in props.items():
118
+ if key in ['label', 'placeholder', 'value'] and isinstance(value, str):
119
+ prop_parts.append(f'{key}="{value}"')
120
+ elif key in ['minimum', 'maximum', 'step', 'lines', 'max_length', 'precision'] and isinstance(value, (int, float)):
121
+ prop_parts.append(f'{key}={value}')
122
+ elif key == 'choices' and isinstance(value, list):
123
+ prop_parts.append(f'{key}={value}')
124
+ elif isinstance(value, bool):
125
+ prop_parts.append(f'{key}={value}')
126
+
127
+ prop_string = ", ".join(prop_parts) if prop_parts else ""
128
+
129
+ code += f" {comp_id} = gr.{comp_type}({prop_string})\n"
130
+ component_vars.append(comp_id)
131
+
132
+ # Add a simple interaction if there are components
133
+ if component_vars:
134
+ inputs = [var for var in component_vars if not var.startswith('button')]
135
+ outputs = [var for var in component_vars if var.startswith('button')]
136
+
137
+ if not outputs:
138
+ outputs = inputs[:1] # Use first input as output if no buttons
139
+
140
+ if inputs and outputs:
141
+ code += f"\n # Add interactions\n"
142
+ code += f" # Example: connect inputs to outputs\n"
143
+ code += f" # {outputs[0]}.click(process_input, inputs=[{', '.join(inputs)}], outputs=[{outputs[0]}])\n"
144
+
145
+ code += '''
146
+ if __name__ == "__main__":
147
+ demo.launch()
148
+ '''
149
+
150
+ return code
151
+
152
+ with gr.Blocks(title="Gradio Visual Designer Pro", theme=gr.themes.Soft()) as demo:
153
+ gr.Markdown(\"\"\"
154
+ # 🎨 Gradio Visual Designer Pro
155
+
156
+ **Build your Gradio apps visually!** Drag and drop components, customize properties, and generate production-ready code.
157
+
158
+ **Features:** 25+ Gradio components • Real-time editing • Code generation • Export options
159
+ \"\"\")
160
+
161
+ with gr.Row():
162
+ designer = GradioDesigner(
163
+ label="Visual App Designer",
164
+ value={"components": [], "layout": "blocks"}
165
+ )
166
+
167
+ with gr.Row():
168
+ with gr.Column(scale=1):
169
+ analysis_output = gr.Markdown(
170
+ value="Design analysis will appear here...",
171
+ label="Design Analysis"
172
+ )
173
+
174
+ with gr.Column(scale=1):
175
+ code_output = gr.Code(
176
+ label="Generated Gradio Code",
177
+ language="python",
178
+ value="# Design your app above to see generated code",
179
+ lines=20
180
+ )
181
+
182
+ with gr.Row():
183
+ analyze_btn = gr.Button("📊 Analyze Design", variant="secondary")
184
+ generate_btn = gr.Button("🚀 Generate Code", variant="primary")
185
+ clear_btn = gr.Button("🗑️ Clear All", variant="stop")
186
+
187
+ # Event handlers
188
+ designer.change(
189
+ fn=analyze_design,
190
+ inputs=[designer],
191
+ outputs=[analysis_output]
192
+ )
193
+
194
+ analyze_btn.click(
195
+ fn=analyze_design,
196
+ inputs=[designer],
197
+ outputs=[analysis_output]
198
+ )
199
+
200
+ generate_btn.click(
201
+ fn=generate_gradio_code,
202
+ inputs=[designer],
203
+ outputs=[code_output]
204
+ )
205
+
206
+ clear_btn.click(
207
+ fn=lambda: {"components": [], "layout": "blocks"},
208
+ outputs=[designer]
209
+ )
210
+
211
+ if __name__ == "__main__":
212
+ demo.launch()
213
+
214
+ ```
215
+ """, elem_classes=["md-custom"], header_links=True)
216
+
217
+
218
+ gr.Markdown("""
219
+ ## `GradioDesigner`
220
+
221
+ ### Initialization
222
+ """, elem_classes=["md-custom"], header_links=True)
223
+
224
+ gr.ParamViewer(value=_docs["GradioDesigner"]["members"]["__init__"], linkify=[])
225
+
226
+
227
+ gr.Markdown("### Events")
228
+ gr.ParamViewer(value=_docs["GradioDesigner"]["events"], linkify=['Event'])
229
+
230
+
231
+
232
+
233
+ gr.Markdown("""
234
+
235
+ ### User function
236
+
237
+ 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).
238
+
239
+ - When used as an Input, the component only impacts the input signature of the user function.
240
+ - When used as an output, the component only impacts the return signature of the user function.
241
+
242
+ The code snippet below is accurate in cases where the component is used as both an input and an output.
243
+
244
+
245
+
246
+ ```python
247
+ def predict(
248
+ value: dict | None
249
+ ) -> dict | None:
250
+ return value
251
+ ```
252
+ """, elem_classes=["md-custom", "GradioDesigner-user-fn"], header_links=True)
253
+
254
+
255
+
256
+
257
+ demo.load(None, js=r"""function() {
258
+ const refs = {};
259
+ const user_fn_refs = {
260
+ GradioDesigner: [], };
261
+ requestAnimationFrame(() => {
262
+
263
+ Object.entries(user_fn_refs).forEach(([key, refs]) => {
264
+ if (refs.length > 0) {
265
+ const el = document.querySelector(`.${key}-user-fn`);
266
+ if (!el) return;
267
+ refs.forEach(ref => {
268
+ el.innerHTML = el.innerHTML.replace(
269
+ new RegExp("\\b"+ref+"\\b", "g"),
270
+ `<a href="#h-${ref.toLowerCase()}">${ref}</a>`
271
+ );
272
+ })
273
+ }
274
+ })
275
+
276
+ Object.entries(refs).forEach(([key, refs]) => {
277
+ if (refs.length > 0) {
278
+ const el = document.querySelector(`.${key}`);
279
+ if (!el) return;
280
+ refs.forEach(ref => {
281
+ el.innerHTML = el.innerHTML.replace(
282
+ new RegExp("\\b"+ref+"\\b", "g"),
283
+ `<a href="#h-${ref.toLowerCase()}">${ref}</a>`
284
+ );
285
+ })
286
+ }
287
+ })
288
+ })
289
+ }
290
+
291
+ """)
292
+
293
+ 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,890 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import type { LoadingStatus } from "@gradio/statustracker";
3
+ import type { Gradio } from "@gradio/utils";
4
+ import { onMount } from 'svelte';
5
+
6
+ export let gradio: Gradio<{
7
+ change: never;
8
+ input: never;
9
+ }>;
10
+ export let elem_id = "";
11
+ export const elem_classes: string[] = [];
12
+ export let value: any = { components: [], layout: "blocks" };
13
+ export const loading_status: LoadingStatus | undefined = undefined;
14
+ export const mode: "static" | "interactive" = "interactive";
15
+
16
+ // Complete component definitions organized by category
17
+ const componentsByCategory = {
18
+ "Input": [
19
+ { type: "Textbox", label: "Text Input", icon: "📝" },
20
+ { type: "TextArea", label: "Text Area", icon: "📄" },
21
+ { type: "Number", label: "Number", icon: "🔢" },
22
+ { type: "Slider", label: "Slider", icon: "🎚️" },
23
+ { type: "Checkbox", label: "Checkbox", icon: "☑️" },
24
+ { type: "CheckboxGroup", label: "Checkbox Group", icon: "☑️" },
25
+ { type: "Radio", label: "Radio", icon: "🔘" },
26
+ { type: "Dropdown", label: "Dropdown", icon: "📋" },
27
+ { type: "Toggle", label: "Toggle", icon: "🔄" },
28
+ { type: "ColorPicker", label: "Color Picker", icon: "🎨" },
29
+ { type: "Date", label: "Date", icon: "📅" },
30
+ { type: "Time", label: "Time", icon: "⏰" },
31
+ { type: "File", label: "File Upload", icon: "📁" }
32
+ ],
33
+ "Action": [
34
+ { type: "Button", label: "Button", icon: "🔘" }
35
+ ],
36
+ "Media": [
37
+ { type: "Image", label: "Image", icon: "🖼️" },
38
+ { type: "Video", label: "Video", icon: "🎥" },
39
+ { type: "Audio", label: "Audio", icon: "🎵" }
40
+ ],
41
+ "Data": [
42
+ { type: "Dataframe", label: "Dataframe", icon: "📊" },
43
+ { type: "JSON", label: "JSON", icon: "📋" }
44
+ ],
45
+ "Display": [
46
+ { type: "Markdown", label: "Markdown", icon: "📝" },
47
+ { type: "HTML", label: "HTML", icon: "🌐" },
48
+ { type: "Label", label: "Label", icon: "🏷️" },
49
+ { type: "Progress", label: "Progress", icon: "📈" }
50
+ ]
51
+ };
52
+
53
+ // Force components to show immediately on mount
54
+ let mounted = false;
55
+ onMount(() => {
56
+ mounted = true;
57
+ });
58
+
59
+ let draggedComponent: any = null;
60
+ let canvasRef: HTMLElement;
61
+ let selectedComponent: any = null;
62
+ let searchFilter = "";
63
+ let selectedCategory = "All";
64
+
65
+ // Ensure components are always available
66
+ $: allComponents = Object.values(componentsByCategory).flat();
67
+
68
+ $: filteredComponents = (() => {
69
+ if (selectedCategory === "All") {
70
+ let components = allComponents;
71
+
72
+ if (searchFilter.trim()) {
73
+ return components.filter(comp =>
74
+ comp.type.toLowerCase().includes(searchFilter.toLowerCase()) ||
75
+ comp.label.toLowerCase().includes(searchFilter.toLowerCase())
76
+ );
77
+ }
78
+
79
+ return components;
80
+ } else {
81
+ let components = componentsByCategory[selectedCategory] || [];
82
+
83
+ if (searchFilter.trim()) {
84
+ return components.filter(comp =>
85
+ comp.type.toLowerCase().includes(searchFilter.toLowerCase()) ||
86
+ comp.label.toLowerCase().includes(searchFilter.toLowerCase())
87
+ );
88
+ }
89
+
90
+ return components;
91
+ }
92
+ })();
93
+
94
+ // Use this to display components on initial load
95
+ $: displayComponents = mounted ? filteredComponents : allComponents;
96
+
97
+ function onDragStart(event: DragEvent, componentType: any) {
98
+ draggedComponent = componentType;
99
+ if (event.dataTransfer) {
100
+ event.dataTransfer.effectAllowed = "copy";
101
+ }
102
+ }
103
+
104
+ function onDragOver(event: DragEvent) {
105
+ event.preventDefault();
106
+ if (event.dataTransfer) {
107
+ event.dataTransfer.dropEffect = "copy";
108
+ }
109
+ }
110
+
111
+ function onDrop(event: DragEvent) {
112
+ event.preventDefault();
113
+ if (!draggedComponent) return;
114
+
115
+ const rect = canvasRef.getBoundingClientRect();
116
+ const x = event.clientX - rect.left;
117
+ const y = event.clientY - rect.top;
118
+
119
+ const newComponent = {
120
+ id: `${draggedComponent.type.toLowerCase()}_${Date.now()}`,
121
+ type: draggedComponent.type,
122
+ position: { x, y },
123
+ size: { width: 200, height: 100 },
124
+ props: getDefaultProps(draggedComponent.type)
125
+ };
126
+
127
+ value = {
128
+ ...value,
129
+ components: [...value.components, newComponent]
130
+ };
131
+
132
+ gradio.dispatch("change", value);
133
+ draggedComponent = null;
134
+ }
135
+
136
+ function getDefaultProps(type: string) {
137
+ const defaults = {
138
+ Textbox: { label: "Text Input", placeholder: "Enter text...", value: "" },
139
+ TextArea: { label: "Text Area", placeholder: "Enter multiple lines...", lines: 3, value: "" },
140
+ Button: { value: "Click me", variant: "secondary", size: "sm" },
141
+ Slider: { label: "Slider", minimum: 0, maximum: 100, step: 1, value: 50 },
142
+ Number: { label: "Number", value: 0, precision: 0 },
143
+ Checkbox: { label: "Checkbox", value: false },
144
+ CheckboxGroup: { label: "Checkbox Group", choices: ["Option 1", "Option 2"], value: [] },
145
+ Radio: { label: "Radio", choices: ["Option 1", "Option 2"], value: "Option 1" },
146
+ Dropdown: { label: "Dropdown", choices: ["Option 1", "Option 2"], value: "Option 1", multiselect: false },
147
+ Toggle: { label: "Toggle", value: false },
148
+ ColorPicker: { label: "Color Picker", value: "#ff0000" },
149
+ Date: { label: "Date", value: "2025-01-01" },
150
+ Time: { label: "Time", value: "12:00" },
151
+ File: { label: "Upload File", file_types: [".txt", ".pdf"] },
152
+ Image: { label: "Image", type: "pil", interactive: true },
153
+ Video: { label: "Video", format: "mp4" },
154
+ Audio: { label: "Audio" },
155
+ Dataframe: { headers: ["Column 1", "Column 2"], datatype: ["str", "str"], value: [] },
156
+ JSON: { value: "{}" },
157
+ Markdown: { value: "# Markdown Text" },
158
+ HTML: { value: "<p>HTML Content</p>" },
159
+ Label: { value: "Label Text" },
160
+ Progress: { value: 0.5 }
161
+ };
162
+ return defaults[type] || {};
163
+ }
164
+
165
+ function selectComponent(component: any) {
166
+ selectedComponent = component;
167
+ }
168
+
169
+ function updateComponentProp(prop: string, newValue: any) {
170
+ if (!selectedComponent) return;
171
+
172
+ // Handle special input types
173
+ if (prop === "choices" && typeof newValue === "string") {
174
+ newValue = newValue.split(",").map(s => s.trim()).filter(s => s);
175
+ } else if (prop === "file_types" && typeof newValue === "string") {
176
+ newValue = newValue.split(",").map(s => s.trim()).filter(s => s);
177
+ }
178
+
179
+ const updatedComponents = value.components.map(comp =>
180
+ comp.id === selectedComponent.id
181
+ ? { ...comp, props: { ...comp.props, [prop]: newValue }}
182
+ : comp
183
+ );
184
+
185
+ selectedComponent = { ...selectedComponent, props: { ...selectedComponent.props, [prop]: newValue }};
186
+ value = { ...value, components: updatedComponents };
187
+ gradio.dispatch("change", value);
188
+ }
189
+
190
+ function updateComponentPosition(component: any, newX: number, newY: number) {
191
+ const updatedComponents = value.components.map(comp =>
192
+ comp.id === component.id
193
+ ? { ...comp, position: { x: newX, y: newY }}
194
+ : comp
195
+ );
196
+
197
+ value = { ...value, components: updatedComponents };
198
+ gradio.dispatch("change", value);
199
+ }
200
+
201
+ function updateComponentSize(component: any, newWidth: number, newHeight: number) {
202
+ const updatedComponents = value.components.map(comp =>
203
+ comp.id === component.id
204
+ ? { ...comp, size: { width: newWidth, height: newHeight }}
205
+ : comp
206
+ );
207
+
208
+ if (selectedComponent?.id === component.id) {
209
+ selectedComponent = { ...selectedComponent, size: { width: newWidth, height: newHeight }};
210
+ }
211
+
212
+ value = { ...value, components: updatedComponents };
213
+ gradio.dispatch("change", value);
214
+ }
215
+
216
+ function deleteComponent(componentId: string) {
217
+ const updatedComponents = value.components.filter(comp => comp.id !== componentId);
218
+ value = { ...value, components: updatedComponents };
219
+ selectedComponent = null;
220
+ gradio.dispatch("change", value);
221
+ }
222
+
223
+ function exportAsJSON() {
224
+ const exportData = {
225
+ ...value,
226
+ metadata: {
227
+ version: "1.0",
228
+ created_at: new Date().toISOString(),
229
+ app_type: "gradio_interface",
230
+ component_count: value.components.length
231
+ }
232
+ };
233
+
234
+ const jsonString = JSON.stringify(exportData, null, 2);
235
+ const blob = new Blob([jsonString], { type: 'application/json' });
236
+ const url = URL.createObjectURL(blob);
237
+ const a = document.createElement('a');
238
+ a.href = url;
239
+ a.download = 'gradio-design.json';
240
+ a.click();
241
+ URL.revokeObjectURL(url);
242
+ }
243
+
244
+ function exportAsPNG() {
245
+ try {
246
+ const canvas = document.createElement('canvas');
247
+ const ctx = canvas.getContext('2d');
248
+
249
+ const rect = canvasRef.getBoundingClientRect();
250
+ canvas.width = rect.width * 2;
251
+ canvas.height = rect.height * 2;
252
+
253
+ ctx.scale(2, 2);
254
+
255
+ // White background
256
+ ctx.fillStyle = '#ffffff';
257
+ ctx.fillRect(0, 0, rect.width, rect.height);
258
+
259
+ // Draw grid
260
+ ctx.strokeStyle = 'rgba(0,0,0,0.1)';
261
+ ctx.lineWidth = 1;
262
+ for (let x = 0; x <= rect.width; x += 20) {
263
+ ctx.moveTo(x, 0);
264
+ ctx.lineTo(x, rect.height);
265
+ }
266
+ for (let y = 0; y <= rect.height; y += 20) {
267
+ ctx.moveTo(0, y);
268
+ ctx.lineTo(rect.width, y);
269
+ }
270
+ ctx.stroke();
271
+
272
+ // Draw components
273
+ value.components.forEach(component => {
274
+ const componentDef = allComponents.find(c => c.type === component.type);
275
+
276
+ ctx.fillStyle = '#ffffff';
277
+ ctx.strokeStyle = '#ddd';
278
+ ctx.lineWidth = 2;
279
+
280
+ ctx.fillRect(component.position.x, component.position.y, component.size.width, component.size.height);
281
+ ctx.strokeRect(component.position.x, component.position.y, component.size.width, component.size.height);
282
+
283
+ // Component icon and text
284
+ ctx.fillStyle = '#333';
285
+ ctx.font = '16px Arial';
286
+ ctx.textAlign = 'center';
287
+ ctx.fillText(
288
+ componentDef?.icon || '📦',
289
+ component.position.x + component.size.width/2,
290
+ component.position.y + 25
291
+ );
292
+
293
+ ctx.font = '12px Arial';
294
+ ctx.fillText(
295
+ component.type,
296
+ component.position.x + component.size.width/2,
297
+ component.position.y + component.size.height/2
298
+ );
299
+
300
+ ctx.fillText(
301
+ component.props.label || component.props.value || '',
302
+ component.position.x + component.size.width/2,
303
+ component.position.y + component.size.height/2 + 15
304
+ );
305
+ });
306
+
307
+ const link = document.createElement('a');
308
+ link.download = 'gradio-design.png';
309
+ link.href = canvas.toDataURL('image/png');
310
+ link.click();
311
+
312
+ } catch (error) {
313
+ console.error('Canvas export failed:', error);
314
+ alert('PNG export failed. Check console for details.');
315
+ }
316
+ }
317
+
318
+ // Make components draggable within canvas
319
+ let isDragging = false;
320
+ let dragOffset = { x: 0, y: 0 };
321
+
322
+ function onComponentMouseDown(event: MouseEvent, component: any) {
323
+ if (event.button !== 0) return; // Only left click
324
+
325
+ isDragging = true;
326
+ selectedComponent = component;
327
+
328
+ const rect = canvasRef.getBoundingClientRect();
329
+ dragOffset.x = event.clientX - rect.left - component.position.x;
330
+ dragOffset.y = event.clientY - rect.top - component.position.y;
331
+
332
+ event.preventDefault();
333
+ }
334
+
335
+ function onCanvasMouseMove(event: MouseEvent) {
336
+ if (!isDragging || !selectedComponent) return;
337
+
338
+ const rect = canvasRef.getBoundingClientRect();
339
+ const newX = event.clientX - rect.left - dragOffset.x;
340
+ const newY = event.clientY - rect.top - dragOffset.y;
341
+
342
+ updateComponentPosition(selectedComponent, Math.max(0, newX), Math.max(0, newY));
343
+ }
344
+
345
+ function onCanvasMouseUp() {
346
+ isDragging = false;
347
+ }
348
+ </script>
349
+
350
+ <svelte:window on:mousemove={onCanvasMouseMove} on:mouseup={onCanvasMouseUp} />
351
+
352
+ <div class="designer-container" id={elem_id}>
353
+ <!-- Top Toolbar -->
354
+ <div class="toolbar">
355
+ <div class="toolbar-left">
356
+ <h3>🎨 Gradio Designer</h3>
357
+ <span class="component-count">{value.components.length} components</span>
358
+ </div>
359
+ <div class="toolbar-right">
360
+ <button class="export-btn" on:click={exportAsJSON} type="button">
361
+ 📄 Export JSON
362
+ </button>
363
+ <button class="export-btn" on:click={exportAsPNG} type="button">
364
+ 🖼️ Export PNG
365
+ </button>
366
+ </div>
367
+ </div>
368
+
369
+ <div class="designer-content">
370
+ <!-- Component Palette - Always on the left -->
371
+ <div class="palette">
372
+ <div class="palette-header">
373
+ <h4>Components</h4>
374
+ <input
375
+ type="text"
376
+ placeholder="Search components..."
377
+ bind:value={searchFilter}
378
+ class="search-input"
379
+ />
380
+ <select bind:value={selectedCategory} class="category-select">
381
+ <option value="All">All Categories</option>
382
+ {#each Object.keys(componentsByCategory) as category}
383
+ <option value={category}>{category}</option>
384
+ {/each}
385
+ </select>
386
+ </div>
387
+
388
+ <div class="palette-content">
389
+ {#each displayComponents as component}
390
+ <div
391
+ class="palette-item"
392
+ draggable="true"
393
+ on:dragstart={(e) => onDragStart(e, component)}
394
+ >
395
+ <span class="icon">{component.icon}</span>
396
+ <span class="label">{component.label}</span>
397
+ </div>
398
+ {:else}
399
+ <div class="no-components">
400
+ {#if searchFilter.trim()}
401
+ No components match "{searchFilter}"
402
+ {:else}
403
+ Loading components...
404
+ {/if}
405
+ </div>
406
+ {/each}
407
+ </div>
408
+ </div>
409
+
410
+ <!-- Design Canvas -->
411
+ <div
412
+ class="canvas"
413
+ bind:this={canvasRef}
414
+ on:dragover={onDragOver}
415
+ on:drop={onDrop}
416
+ >
417
+ <div class="canvas-grid"></div>
418
+ {#each value.components as component (component.id)}
419
+ <div
420
+ class="canvas-component"
421
+ class:selected={selectedComponent?.id === component.id}
422
+ style="
423
+ left: {component.position.x}px;
424
+ top: {component.position.y}px;
425
+ width: {component.size.width}px;
426
+ height: {component.size.height}px;
427
+ "
428
+ on:click={() => selectComponent(component)}
429
+ on:mousedown={(e) => onComponentMouseDown(e, component)}
430
+ >
431
+ <div class="component-preview">
432
+ <div class="component-header">
433
+ <span class="type">{component.type}</span>
434
+ <button
435
+ class="delete-btn"
436
+ on:click|stopPropagation={() => deleteComponent(component.id)}
437
+ type="button"
438
+ >
439
+
440
+ </button>
441
+ </div>
442
+ <span class="label">{component.props.label || component.props.value || 'Component'}</span>
443
+ </div>
444
+ </div>
445
+ {/each}
446
+ </div>
447
+
448
+ <!-- Properties Panel -->
449
+ <div class="properties">
450
+ <h4>Properties</h4>
451
+ {#if selectedComponent}
452
+ <div class="property-group">
453
+ <div class="property-header">
454
+ <strong>Type:</strong> {selectedComponent.type}
455
+ <br>
456
+ <small>ID: {selectedComponent.id}</small>
457
+ </div>
458
+
459
+ <!-- Component Properties -->
460
+ {#if selectedComponent.props.label !== undefined}
461
+ <label>Label:</label>
462
+ <input
463
+ type="text"
464
+ placeholder="Label"
465
+ value={selectedComponent.props.label}
466
+ on:input={(e) => updateComponentProp('label', e.target.value)}
467
+ />
468
+ {/if}
469
+
470
+ {#if selectedComponent.props.placeholder !== undefined}
471
+ <label>Placeholder:</label>
472
+ <input
473
+ type="text"
474
+ placeholder="Placeholder"
475
+ value={selectedComponent.props.placeholder}
476
+ on:input={(e) => updateComponentProp('placeholder', e.target.value)}
477
+ />
478
+ {/if}
479
+
480
+ {#if selectedComponent.props.value !== undefined}
481
+ <label>Value:</label>
482
+ {#if typeof selectedComponent.props.value === 'boolean'}
483
+ <input
484
+ type="checkbox"
485
+ checked={selectedComponent.props.value}
486
+ on:change={(e) => updateComponentProp('value', e.target.checked)}
487
+ />
488
+ {:else if typeof selectedComponent.props.value === 'number'}
489
+ <input
490
+ type="number"
491
+ value={selectedComponent.props.value}
492
+ on:input={(e) => updateComponentProp('value', parseFloat(e.target.value) || 0)}
493
+ />
494
+ {:else}
495
+ <input
496
+ type="text"
497
+ placeholder="Value"
498
+ value={selectedComponent.props.value}
499
+ on:input={(e) => updateComponentProp('value', e.target.value)}
500
+ />
501
+ {/if}
502
+ {/if}
503
+
504
+ {#if selectedComponent.props.choices !== undefined}
505
+ <label>Choices (comma-separated):</label>
506
+ <input
507
+ type="text"
508
+ placeholder="Option 1, Option 2, Option 3"
509
+ value={Array.isArray(selectedComponent.props.choices) ? selectedComponent.props.choices.join(", ") : selectedComponent.props.choices}
510
+ on:input={(e) => updateComponentProp('choices', e.target.value)}
511
+ />
512
+ {/if}
513
+
514
+ {#if selectedComponent.props.minimum !== undefined}
515
+ <label>Minimum:</label>
516
+ <input
517
+ type="number"
518
+ value={selectedComponent.props.minimum}
519
+ on:input={(e) => updateComponentProp('minimum', parseFloat(e.target.value) || 0)}
520
+ />
521
+ {/if}
522
+
523
+ {#if selectedComponent.props.maximum !== undefined}
524
+ <label>Maximum:</label>
525
+ <input
526
+ type="number"
527
+ value={selectedComponent.props.maximum}
528
+ on:input={(e) => updateComponentProp('maximum', parseFloat(e.target.value) || 100)}
529
+ />
530
+ {/if}
531
+
532
+ {#if selectedComponent.props.step !== undefined}
533
+ <label>Step:</label>
534
+ <input
535
+ type="number"
536
+ value={selectedComponent.props.step}
537
+ on:input={(e) => updateComponentProp('step', parseFloat(e.target.value) || 1)}
538
+ />
539
+ {/if}
540
+
541
+ <!-- Size Controls -->
542
+ <div class="size-section">
543
+ <h5>Size & Position</h5>
544
+ <div class="size-controls">
545
+ <label>Width:</label>
546
+ <input
547
+ type="number"
548
+ value={selectedComponent.size.width}
549
+ on:input={(e) => updateComponentSize(selectedComponent, parseInt(e.target.value) || 200, selectedComponent.size.height)}
550
+ />
551
+
552
+ <label>Height:</label>
553
+ <input
554
+ type="number"
555
+ value={selectedComponent.size.height}
556
+ on:input={(e) => updateComponentSize(selectedComponent, selectedComponent.size.width, parseInt(e.target.value) || 100)}
557
+ />
558
+
559
+ <label>X Position:</label>
560
+ <input
561
+ type="number"
562
+ value={selectedComponent.position.x}
563
+ on:input={(e) => updateComponentPosition(selectedComponent, parseInt(e.target.value) || 0, selectedComponent.position.y)}
564
+ />
565
+
566
+ <label>Y Position:</label>
567
+ <input
568
+ type="number"
569
+ value={selectedComponent.position.y}
570
+ on:input={(e) => updateComponentPosition(selectedComponent, selectedComponent.position.x, parseInt(e.target.value) || 0)}
571
+ />
572
+ </div>
573
+ </div>
574
+ </div>
575
+ {:else}
576
+ <p>Select a component to edit properties</p>
577
+ <div class="help-text">
578
+ <strong>How to use:</strong>
579
+ <ul>
580
+ <li>Drag components from the palette to the canvas</li>
581
+ <li>Click components to select and edit them</li>
582
+ <li>Drag components around the canvas to reposition</li>
583
+ <li>Use the properties panel to customize</li>
584
+ </ul>
585
+ </div>
586
+ {/if}
587
+ </div>
588
+ </div>
589
+ </div>
590
+
591
+ <style>
592
+ .designer-container {
593
+ display: flex;
594
+ flex-direction: column;
595
+ height: 700px;
596
+ border: 1px solid #ddd;
597
+ border-radius: 8px;
598
+ overflow: hidden;
599
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
600
+ }
601
+
602
+ .toolbar {
603
+ display: flex;
604
+ justify-content: space-between;
605
+ align-items: center;
606
+ padding: 12px 16px;
607
+ background: #f8f9fa;
608
+ border-bottom: 1px solid #ddd;
609
+ }
610
+
611
+ .toolbar-left {
612
+ display: flex;
613
+ align-items: center;
614
+ gap: 12px;
615
+ }
616
+
617
+ .toolbar h3 {
618
+ margin: 0;
619
+ font-size: 16px;
620
+ font-weight: 600;
621
+ }
622
+
623
+ .component-count {
624
+ background: #e9ecef;
625
+ padding: 2px 8px;
626
+ border-radius: 12px;
627
+ font-size: 12px;
628
+ color: #495057;
629
+ }
630
+
631
+ .toolbar-right {
632
+ display: flex;
633
+ gap: 8px;
634
+ }
635
+
636
+ .export-btn {
637
+ padding: 6px 12px;
638
+ background: #007bff;
639
+ color: white;
640
+ border: none;
641
+ border-radius: 4px;
642
+ cursor: pointer;
643
+ font-size: 12px;
644
+ }
645
+
646
+ .export-btn:hover {
647
+ background: #0056b3;
648
+ }
649
+
650
+ /* CRITICAL FIX: Force grid layout with !important to ensure initial render is correct */
651
+ .designer-content {
652
+ display: grid !important;
653
+ grid-template-columns: 250px 1fr 280px !important;
654
+ grid-template-areas: "palette canvas properties" !important;
655
+ flex: 1;
656
+ height: 100%;
657
+ min-height: 0; /* Force grid to work immediately */
658
+ }
659
+
660
+ /* CRITICAL FIX: Use grid-area with !important to lock positions */
661
+ .palette {
662
+ grid-area: palette !important;
663
+ background: #f8f9fa;
664
+ border-right: 1px solid #ddd;
665
+ display: flex;
666
+ flex-direction: column;
667
+ overflow: hidden;
668
+ }
669
+
670
+ .canvas {
671
+ grid-area: canvas !important;
672
+ position: relative;
673
+ background: white;
674
+ overflow: hidden;
675
+ user-select: none;
676
+ }
677
+
678
+ .properties {
679
+ grid-area: properties !important;
680
+ background: #f8f9fa;
681
+ padding: 16px;
682
+ border-left: 1px solid #ddd;
683
+ overflow-y: auto;
684
+ }
685
+
686
+ .palette-header {
687
+ padding: 12px 16px;
688
+ border-bottom: 1px solid #ddd;
689
+ background: white;
690
+ flex-shrink: 0;
691
+ min-height: 120px;
692
+ max-height: 120px;
693
+ overflow: hidden;
694
+ }
695
+
696
+ .palette h4 {
697
+ margin: 0 0 8px 0;
698
+ font-size: 14px;
699
+ font-weight: 600;
700
+ }
701
+
702
+ .search-input, .category-select {
703
+ width: 100%;
704
+ padding: 6px 8px;
705
+ border: 1px solid #ddd;
706
+ border-radius: 4px;
707
+ font-size: 12px;
708
+ margin-bottom: 6px;
709
+ box-sizing: border-box;
710
+ }
711
+
712
+ .palette-content {
713
+ flex: 1;
714
+ overflow-y: auto;
715
+ padding: 8px;
716
+ min-height: 0;
717
+ background: #f8f9fa;
718
+ }
719
+
720
+ .palette-item {
721
+ display: flex;
722
+ align-items: center;
723
+ padding: 8px;
724
+ margin-bottom: 4px;
725
+ background: white;
726
+ border: 1px solid #e1e5e9;
727
+ border-radius: 4px;
728
+ cursor: grab;
729
+ user-select: none;
730
+ }
731
+
732
+ .palette-item:hover {
733
+ background: #f0f0f0;
734
+ }
735
+
736
+ .no-components {
737
+ padding: 20px;
738
+ text-align: center;
739
+ color: #666;
740
+ font-size: 12px;
741
+ background: white;
742
+ border-radius: 4px;
743
+ border: 1px solid #e1e5e9;
744
+ }
745
+
746
+ .icon {
747
+ margin-right: 8px;
748
+ font-size: 16px;
749
+ }
750
+
751
+ .label {
752
+ font-size: 12px;
753
+ }
754
+
755
+ .canvas-grid {
756
+ position: absolute;
757
+ top: 0;
758
+ left: 0;
759
+ right: 0;
760
+ bottom: 0;
761
+ background-image:
762
+ linear-gradient(rgba(0,0,0,0.1) 1px, transparent 1px),
763
+ linear-gradient(90deg, rgba(0,0,0,0.1) 1px, transparent 1px);
764
+ background-size: 20px 20px;
765
+ opacity: 0.3;
766
+ }
767
+
768
+ .canvas-component {
769
+ position: absolute;
770
+ border: 2px solid #ddd;
771
+ border-radius: 4px;
772
+ background: white;
773
+ cursor: move;
774
+ padding: 8px;
775
+ box-sizing: border-box;
776
+ }
777
+
778
+ .canvas-component:hover {
779
+ border-color: #007bff;
780
+ }
781
+
782
+ .canvas-component.selected {
783
+ border-color: #ff6b6b;
784
+ box-shadow: 0 0 0 2px rgba(255, 107, 107, 0.3);
785
+ }
786
+
787
+ .component-preview {
788
+ display: flex;
789
+ flex-direction: column;
790
+ height: 100%;
791
+ text-align: center;
792
+ pointer-events: none;
793
+ }
794
+
795
+ .component-header {
796
+ display: flex;
797
+ justify-content: space-between;
798
+ align-items: center;
799
+ margin-bottom: 4px;
800
+ }
801
+
802
+ .type {
803
+ font-weight: bold;
804
+ font-size: 12px;
805
+ color: #666;
806
+ }
807
+
808
+ .delete-btn {
809
+ background: none;
810
+ border: none;
811
+ cursor: pointer;
812
+ font-size: 10px;
813
+ padding: 2px;
814
+ opacity: 0.7;
815
+ pointer-events: auto;
816
+ }
817
+
818
+ .delete-btn:hover {
819
+ opacity: 1;
820
+ }
821
+
822
+ .properties h4 {
823
+ margin: 0 0 16px 0;
824
+ font-size: 14px;
825
+ font-weight: 600;
826
+ }
827
+
828
+ .property-group {
829
+ display: flex;
830
+ flex-direction: column;
831
+ gap: 8px;
832
+ }
833
+
834
+ .property-header {
835
+ padding: 12px;
836
+ background: white;
837
+ border-radius: 4px;
838
+ border: 1px solid #e1e5e9;
839
+ margin-bottom: 12px;
840
+ }
841
+
842
+ .size-section {
843
+ margin-top: 16px;
844
+ padding-top: 16px;
845
+ border-top: 1px solid #ddd;
846
+ }
847
+
848
+ .size-section h5 {
849
+ margin: 0 0 8px 0;
850
+ font-size: 12px;
851
+ font-weight: 600;
852
+ }
853
+
854
+ .size-controls {
855
+ display: grid;
856
+ grid-template-columns: 1fr 1fr;
857
+ gap: 8px;
858
+ }
859
+
860
+ .property-group label {
861
+ font-size: 12px;
862
+ font-weight: 500;
863
+ color: #333;
864
+ }
865
+
866
+ .property-group input, .property-group select {
867
+ padding: 6px 8px;
868
+ border: 1px solid #ddd;
869
+ border-radius: 4px;
870
+ font-size: 12px;
871
+ }
872
+
873
+ .help-text {
874
+ margin-top: 20px;
875
+ padding: 12px;
876
+ background: white;
877
+ border-radius: 4px;
878
+ border: 1px solid #e1e5e9;
879
+ }
880
+
881
+ .help-text ul {
882
+ margin: 8px 0 0 0;
883
+ padding-left: 16px;
884
+ }
885
+
886
+ .help-text li {
887
+ font-size: 11px;
888
+ margin-bottom: 4px;
889
+ }
890
+ </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,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "gradio_gradiodesigner",
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
+ "svelte-moveable": "^0.45.0",
29
+ "html-to-image": "^1.9.0"
30
+ },
31
+ "devDependencies": {
32
+ "@gradio/preview": "0.13.1"
33
+ },
34
+ "peerDependencies": {
35
+ "svelte": "^4.0.0"
36
+ },
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "git+https://github.com/gradio-app/gradio.git",
40
+ "directory": "js/simpletextbox"
41
+ }
42
+ }
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_gradiodesigner"
11
+ version = "0.0.1"
12
+ description = "gradio designer"
13
+ readme = "README.md"
14
+ license = "apache-2.0"
15
+ requires-python = ">=3.10"
16
+ authors = [{ name = "YOUR NAME", email = "[email protected]" }]
17
+ keywords = ["gradio-custom-component", "gradio-template-SimpleTextbox", "designer", "drag and drop", "custom designs"]
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_gradiodesigner/templates", "*.pyi"]
49
+
50
+ [tool.hatch.build.targets.wheel]
51
+ packages = ["/backend/gradio_gradiodesigner"]