elismasilva commited on
Commit
0f12e5c
·
verified ·
1 Parent(s): 224d6fb

Upload folder using huggingface_hub

Browse files
.gitignore ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .eggs/
2
+ dist/
3
+ .vscode/
4
+ *.pyc
5
+ __pycache__/
6
+ *.py[cod]
7
+ *$py.class
8
+ __tmp/*
9
+ *.pyi
10
+ .mypycache
11
+ .ruff_cache
12
+ node_modules
13
+ backend/**/templates/
14
+ README_TEMPLATE.md
README.md CHANGED
@@ -1,12 +1,308 @@
1
- ---
2
- title: Gradio Buttonplus
3
- emoji: 🏃
4
- colorFrom: green
5
- colorTo: yellow
6
- sdk: gradio
7
- sdk_version: 5.49.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, Button]
3
+ title: gradio_buttonplus
4
+ short_description: Advanced Button Component for Gradio UI
5
+ colorFrom: blue
6
+ colorTo: yellow
7
+ sdk: gradio
8
+ pinned: false
9
+ app_file: space.py
10
+ ---
11
+
12
+ # `gradio_buttonplus`
13
+ <img alt="Static Badge" src="https://img.shields.io/badge/version%20-%200.0.1%20-%20orange">
14
+
15
+ Advanced Button Component for Gradio UI
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ pip install gradio_buttonplus
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ```python
26
+
27
+ import gradio as gr
28
+ from gradio_buttonplus import ButtonPlus
29
+
30
+
31
+ with gr.Blocks(theme=gr.themes.Ocean()) as demo:
32
+ gr.HTML("<h1><center>ButtonPlus Component Demo</center></h1>")
33
+ with gr.Row():
34
+ with gr.Column():
35
+ btn = ButtonPlus("⚙️", help="This button triggers an action.")
36
+ btn_2 = ButtonPlus("Another Test", help="This is a demo test")
37
+
38
+
39
+
40
+ if __name__ == "__main__":
41
+ demo.launch()
42
+
43
+ ```
44
+
45
+ ## `ButtonPlus`
46
+
47
+ ### Initialization
48
+
49
+ <table>
50
+ <thead>
51
+ <tr>
52
+ <th align="left">name</th>
53
+ <th align="left" style="width: 25%;">type</th>
54
+ <th align="left">default</th>
55
+ <th align="left">description</th>
56
+ </tr>
57
+ </thead>
58
+ <tbody>
59
+ <tr>
60
+ <td align="left"><code>value</code></td>
61
+ <td align="left" style="width: 25%;">
62
+
63
+ ```python
64
+ str | I18nData | Callable
65
+ ```
66
+
67
+ </td>
68
+ <td align="left"><code>"Run"</code></td>
69
+ <td align="left">default text for the button to display. If a function is provided, the function will be called each time the app loads to set the initial value of this component.</td>
70
+ </tr>
71
+
72
+ <tr>
73
+ <td align="left"><code>every</code></td>
74
+ <td align="left" style="width: 25%;">
75
+
76
+ ```python
77
+ Timer | float | None
78
+ ```
79
+
80
+ </td>
81
+ <td align="left"><code>None</code></td>
82
+ <td align="left">continuously calls `value` to recalculate it if `value` is a function (has no effect otherwise). Can provide a Timer whose tick resets `value`, or a float that provides the regular interval for the reset Timer.</td>
83
+ </tr>
84
+
85
+ <tr>
86
+ <td align="left"><code>inputs</code></td>
87
+ <td align="left" style="width: 25%;">
88
+
89
+ ```python
90
+ Component | Sequence[Component] | set[Component] | None
91
+ ```
92
+
93
+ </td>
94
+ <td align="left"><code>None</code></td>
95
+ <td align="left">components that are used as inputs to calculate `value` if `value` is a function (has no effect otherwise). `value` is recalculated any time the inputs change.</td>
96
+ </tr>
97
+
98
+ <tr>
99
+ <td align="left"><code>variant</code></td>
100
+ <td align="left" style="width: 25%;">
101
+
102
+ ```python
103
+ Literal["primary", "secondary", "stop", "huggingface"]
104
+ ```
105
+
106
+ </td>
107
+ <td align="left"><code>"secondary"</code></td>
108
+ <td align="left">sets the background and text color of the button. Use 'primary' for main call-to-action buttons, 'secondary' for a more subdued style, 'stop' for a stop button, 'huggingface' for a black background with white text, consistent with Hugging Face's button styles.</td>
109
+ </tr>
110
+
111
+ <tr>
112
+ <td align="left"><code>size</code></td>
113
+ <td align="left" style="width: 25%;">
114
+
115
+ ```python
116
+ Literal["sm", "md", "lg"]
117
+ ```
118
+
119
+ </td>
120
+ <td align="left"><code>"lg"</code></td>
121
+ <td align="left">size of the button. Can be "sm", "md", or "lg".</td>
122
+ </tr>
123
+
124
+ <tr>
125
+ <td align="left"><code>icon</code></td>
126
+ <td align="left" style="width: 25%;">
127
+
128
+ ```python
129
+ str | Path | None
130
+ ```
131
+
132
+ </td>
133
+ <td align="left"><code>None</code></td>
134
+ <td align="left">URL or path to the icon file to display within the button. If None, no icon will be displayed.</td>
135
+ </tr>
136
+
137
+ <tr>
138
+ <td align="left"><code>link</code></td>
139
+ <td align="left" style="width: 25%;">
140
+
141
+ ```python
142
+ str | None
143
+ ```
144
+
145
+ </td>
146
+ <td align="left"><code>None</code></td>
147
+ <td align="left">URL to open when the button is clicked. If None, no link will be used.</td>
148
+ </tr>
149
+
150
+ <tr>
151
+ <td align="left"><code>visible</code></td>
152
+ <td align="left" style="width: 25%;">
153
+
154
+ ```python
155
+ bool | Literal["hidden"]
156
+ ```
157
+
158
+ </td>
159
+ <td align="left"><code>True</code></td>
160
+ <td align="left">If False, component will be hidden. If "hidden", component will be visually hidden and not take up space in the layout but still exist in the DOM.</td>
161
+ </tr>
162
+
163
+ <tr>
164
+ <td align="left"><code>interactive</code></td>
165
+ <td align="left" style="width: 25%;">
166
+
167
+ ```python
168
+ bool
169
+ ```
170
+
171
+ </td>
172
+ <td align="left"><code>True</code></td>
173
+ <td align="left">if False, the ButtonPlus will be in a disabled state.</td>
174
+ </tr>
175
+
176
+ <tr>
177
+ <td align="left"><code>elem_id</code></td>
178
+ <td align="left" style="width: 25%;">
179
+
180
+ ```python
181
+ str | None
182
+ ```
183
+
184
+ </td>
185
+ <td align="left"><code>None</code></td>
186
+ <td align="left">an optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.</td>
187
+ </tr>
188
+
189
+ <tr>
190
+ <td align="left"><code>elem_classes</code></td>
191
+ <td align="left" style="width: 25%;">
192
+
193
+ ```python
194
+ list[str] | str | None
195
+ ```
196
+
197
+ </td>
198
+ <td align="left"><code>None</code></td>
199
+ <td align="left">an optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.</td>
200
+ </tr>
201
+
202
+ <tr>
203
+ <td align="left"><code>render</code></td>
204
+ <td align="left" style="width: 25%;">
205
+
206
+ ```python
207
+ bool
208
+ ```
209
+
210
+ </td>
211
+ <td align="left"><code>True</code></td>
212
+ <td align="left">if False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.</td>
213
+ </tr>
214
+
215
+ <tr>
216
+ <td align="left"><code>key</code></td>
217
+ <td align="left" style="width: 25%;">
218
+
219
+ ```python
220
+ int | str | tuple[int | str, ...] | None
221
+ ```
222
+
223
+ </td>
224
+ <td align="left"><code>None</code></td>
225
+ <td align="left">in a gr.render, Components with the same key across re-renders are treated as the same component, not a new component. Properties set in 'preserved_by_key' are not reset across a re-render.</td>
226
+ </tr>
227
+
228
+ <tr>
229
+ <td align="left"><code>preserved_by_key</code></td>
230
+ <td align="left" style="width: 25%;">
231
+
232
+ ```python
233
+ list[str] | str | None
234
+ ```
235
+
236
+ </td>
237
+ <td align="left"><code>"value"</code></td>
238
+ <td align="left">A list of parameters from this component's constructor. Inside a gr.render() function, if a component is re-rendered with the same key, these (and only these) parameters will be preserved in the UI (if they have been changed by the user or an event listener) instead of re-rendered based on the values provided during constructor.</td>
239
+ </tr>
240
+
241
+ <tr>
242
+ <td align="left"><code>scale</code></td>
243
+ <td align="left" style="width: 25%;">
244
+
245
+ ```python
246
+ int | None
247
+ ```
248
+
249
+ </td>
250
+ <td align="left"><code>None</code></td>
251
+ <td align="left">relative size compared to adjacent Components. For example if Components A and B are in a Row, and A has scale=2, and B has scale=1, A will be twice as wide as B. Should be an integer. scale applies in Rows, and to top-level Components in Blocks where fill_height=True.</td>
252
+ </tr>
253
+
254
+ <tr>
255
+ <td align="left"><code>min_width</code></td>
256
+ <td align="left" style="width: 25%;">
257
+
258
+ ```python
259
+ int | None
260
+ ```
261
+
262
+ </td>
263
+ <td align="left"><code>None</code></td>
264
+ <td align="left">minimum pixel width, will wrap if not sufficient screen space to satisfy this value. If a certain scale value results in this Component being narrower than min_width, the min_width parameter will be respected first.</td>
265
+ </tr>
266
+
267
+ <tr>
268
+ <td align="left"><code>help</code></td>
269
+ <td align="left" style="width: 25%;">
270
+
271
+ ```python
272
+ str | I18nData | None
273
+ ```
274
+
275
+ </td>
276
+ <td align="left"><code>None</code></td>
277
+ <td align="left">A string of help text to display in a tooltip when hovering over the button.</td>
278
+ </tr>
279
+ </tbody></table>
280
+
281
+
282
+ ### Events
283
+
284
+ | name | description |
285
+ |:-----|:------------|
286
+ | `click` | Triggered when the ButtonPlus is clicked. |
287
+
288
+
289
+
290
+ ### User function
291
+
292
+ 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).
293
+
294
+ - When used as an Input, the component only impacts the input signature of the user function.
295
+ - When used as an output, the component only impacts the return signature of the user function.
296
+
297
+ The code snippet below is accurate in cases where the component is used as both an input and an output.
298
+
299
+ - **As output:** Is passed, (Rarely used) the `str` corresponding to the button label when the button is clicked.
300
+ - **As input:** Should return, string corresponding to the button label.
301
+
302
+ ```python
303
+ def predict(
304
+ value: str | None
305
+ ) -> str | None:
306
+ return value
307
+ ```
308
+
__init__.py ADDED
File without changes
app.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import gradio as gr
3
+ from gradio_buttonplus import ButtonPlus
4
+
5
+
6
+ with gr.Blocks(theme=gr.themes.Ocean()) as demo:
7
+ gr.HTML("<h1><center>ButtonPlus Component Demo</center></h1>")
8
+ with gr.Row():
9
+ with gr.Column():
10
+ btn = ButtonPlus("⚙️", help="This button triggers an action.")
11
+ btn_2 = ButtonPlus("Another Test", help="This is a demo test")
12
+
13
+
14
+
15
+ if __name__ == "__main__":
16
+ 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_buttonplus
space.py ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import gradio as gr
3
+ from app import demo as app
4
+ import os
5
+
6
+ _docs = {'ButtonPlus': {'description': 'Creates a button that can be assigned arbitrary .click() events. The value (label) of the button can be used as an input to the function (rarely used) or set via the output of a function.', 'members': {'__init__': {'value': {'type': 'str | I18nData | Callable', 'default': '"Run"', 'description': 'default text for the button to display. If a function is provided, the function will be called each time the app loads to set the initial value of this component.'}, 'every': {'type': 'Timer | float | None', 'default': 'None', 'description': 'continuously calls `value` to recalculate it if `value` is a function (has no effect otherwise). Can provide a Timer whose tick resets `value`, or a float that provides the regular interval for the reset Timer.'}, 'inputs': {'type': 'Component | Sequence[Component] | set[Component] | None', 'default': 'None', 'description': 'components that are used as inputs to calculate `value` if `value` is a function (has no effect otherwise). `value` is recalculated any time the inputs change.'}, 'variant': {'type': 'Literal["primary", "secondary", "stop", "huggingface"]', 'default': '"secondary"', 'description': "sets the background and text color of the button. Use 'primary' for main call-to-action buttons, 'secondary' for a more subdued style, 'stop' for a stop button, 'huggingface' for a black background with white text, consistent with Hugging Face's button styles."}, 'size': {'type': 'Literal["sm", "md", "lg"]', 'default': '"lg"', 'description': 'size of the button. Can be "sm", "md", or "lg".'}, 'icon': {'type': 'str | Path | None', 'default': 'None', 'description': 'URL or path to the icon file to display within the button. If None, no icon will be displayed.'}, 'link': {'type': 'str | None', 'default': 'None', 'description': 'URL to open when the button is clicked. If None, no link will be used.'}, 'visible': {'type': 'bool | Literal["hidden"]', 'default': 'True', 'description': 'If False, component will be hidden. If "hidden", component will be visually hidden and not take up space in the layout but still exist in the DOM.'}, 'interactive': {'type': 'bool', 'default': 'True', 'description': 'if False, the ButtonPlus will be in a disabled state.'}, 'elem_id': {'type': 'str | None', 'default': 'None', 'description': 'an optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.'}, 'elem_classes': {'type': 'list[str] | str | None', 'default': 'None', 'description': 'an optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.'}, 'render': {'type': 'bool', 'default': 'True', 'description': 'if False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.'}, 'key': {'type': 'int | str | tuple[int | str, ...] | None', 'default': 'None', 'description': "in a gr.render, Components with the same key across re-renders are treated as the same component, not a new component. Properties set in 'preserved_by_key' are not reset across a re-render."}, 'preserved_by_key': {'type': 'list[str] | str | None', 'default': '"value"', 'description': "A list of parameters from this component's constructor. Inside a gr.render() function, if a component is re-rendered with the same key, these (and only these) parameters will be preserved in the UI (if they have been changed by the user or an event listener) instead of re-rendered based on the values provided during constructor."}, 'scale': {'type': 'int | None', 'default': 'None', 'description': 'relative size compared to adjacent Components. For example if Components A and B are in a Row, and A has scale=2, and B has scale=1, A will be twice as wide as B. Should be an integer. scale applies in Rows, and to top-level Components in Blocks where fill_height=True.'}, 'min_width': {'type': 'int | None', 'default': 'None', 'description': 'minimum pixel width, will wrap if not sufficient screen space to satisfy this value. If a certain scale value results in this Component being narrower than min_width, the min_width parameter will be respected first.'}, 'help': {'type': 'str | I18nData | None', 'default': 'None', 'description': 'A string of help text to display in a tooltip when hovering over the button.'}}, 'postprocess': {'value': {'type': 'str | None', 'description': 'string corresponding to the button label'}}, 'preprocess': {'return': {'type': 'str | None', 'description': '(Rarely used) the `str` corresponding to the button label when the button is clicked'}, 'value': None}}, 'events': {'click': {'type': None, 'default': None, 'description': 'Triggered when the ButtonPlus is clicked.'}}}, '__meta__': {'additional_interfaces': {}, 'user_fn_refs': {'ButtonPlus': []}}}
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.Ocean(
13
+ font_mono=[
14
+ gr.themes.GoogleFont("Inconsolata"),
15
+ "monospace",
16
+ ],
17
+ ),
18
+ ) as demo:
19
+ gr.Markdown(
20
+ """
21
+ # `gradio_buttonplus`
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
+ Advanced Button Component for Gradio UI
28
+ """, elem_classes=["md-custom"], header_links=True)
29
+ app.render()
30
+ gr.Markdown(
31
+ """
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install gradio_buttonplus
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ ```python
41
+
42
+ import gradio as gr
43
+ from gradio_buttonplus import ButtonPlus
44
+
45
+
46
+ with gr.Blocks(theme=gr.themes.Ocean()) as demo:
47
+ gr.HTML("<h1><center>ButtonPlus Component Demo</center></h1>")
48
+ with gr.Row():
49
+ with gr.Column():
50
+ btn = ButtonPlus("⚙️", help="This button triggers an action.")
51
+ btn_2 = ButtonPlus("Another Test", help="This is a demo test")
52
+
53
+
54
+
55
+ if __name__ == "__main__":
56
+ demo.launch()
57
+
58
+ ```
59
+ """, elem_classes=["md-custom"], header_links=True)
60
+
61
+
62
+ gr.Markdown("""
63
+ ## `ButtonPlus`
64
+
65
+ ### Initialization
66
+ """, elem_classes=["md-custom"], header_links=True)
67
+
68
+ gr.ParamViewer(value=_docs["ButtonPlus"]["members"]["__init__"], linkify=[])
69
+
70
+
71
+ gr.Markdown("### Events")
72
+ gr.ParamViewer(value=_docs["ButtonPlus"]["events"], linkify=['Event'])
73
+
74
+
75
+
76
+
77
+ gr.Markdown("""
78
+
79
+ ### User function
80
+
81
+ 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).
82
+
83
+ - When used as an Input, the component only impacts the input signature of the user function.
84
+ - When used as an output, the component only impacts the return signature of the user function.
85
+
86
+ The code snippet below is accurate in cases where the component is used as both an input and an output.
87
+
88
+ - **As input:** Is passed, (Rarely used) the `str` corresponding to the button label when the button is clicked.
89
+ - **As output:** Should return, string corresponding to the button label.
90
+
91
+ ```python
92
+ def predict(
93
+ value: str | None
94
+ ) -> str | None:
95
+ return value
96
+ ```
97
+ """, elem_classes=["md-custom", "ButtonPlus-user-fn"], header_links=True)
98
+
99
+
100
+
101
+
102
+ demo.load(None, js=r"""function() {
103
+ const refs = {};
104
+ const user_fn_refs = {
105
+ ButtonPlus: [], };
106
+ requestAnimationFrame(() => {
107
+
108
+ Object.entries(user_fn_refs).forEach(([key, refs]) => {
109
+ if (refs.length > 0) {
110
+ const el = document.querySelector(`.${key}-user-fn`);
111
+ if (!el) return;
112
+ refs.forEach(ref => {
113
+ el.innerHTML = el.innerHTML.replace(
114
+ new RegExp("\\b"+ref+"\\b", "g"),
115
+ `<a href="#h-${ref.toLowerCase()}">${ref}</a>`
116
+ );
117
+ })
118
+ }
119
+ })
120
+
121
+ Object.entries(refs).forEach(([key, refs]) => {
122
+ if (refs.length > 0) {
123
+ const el = document.querySelector(`.${key}`);
124
+ if (!el) return;
125
+ refs.forEach(ref => {
126
+ el.innerHTML = el.innerHTML.replace(
127
+ new RegExp("\\b"+ref+"\\b", "g"),
128
+ `<a href="#h-${ref.toLowerCase()}">${ref}</a>`
129
+ );
130
+ })
131
+ }
132
+ })
133
+ })
134
+ }
135
+
136
+ """)
137
+
138
+ demo.launch()
src/.gitignore ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .eggs/
2
+ dist/
3
+ .vscode/
4
+ *.pyc
5
+ __pycache__/
6
+ *.py[cod]
7
+ *$py.class
8
+ __tmp/*
9
+ *.pyi
10
+ .mypycache
11
+ .ruff_cache
12
+ node_modules
13
+ backend/**/templates/
14
+ README_TEMPLATE.md
src/.vscode/launch.json ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ // Use IntelliSense to learn about possible attributes.
3
+ // Hover to view descriptions of existing attributes.
4
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
+ "version": "0.2.0",
6
+ "configurations": [
7
+ {
8
+ "name": "Python Debugger: Current File",
9
+ "type": "debugpy",
10
+ "request": "launch",
11
+ "program": "${file}",
12
+ "console": "integratedTerminal",
13
+ "justMyCode": false
14
+ },
15
+ {
16
+ "name": "Gradio dev (Python attach)",
17
+ "type": "debugpy",
18
+ "request": "attach",
19
+ "processId": "${command:pickProcess}",
20
+ "justMyCode": false
21
+ },
22
+ {
23
+ "name": "Gradio dev (Svelte attach)",
24
+ "type": "chrome",
25
+ "request": "attach",
26
+ "port": 9222,
27
+ }
28
+ ]
29
+ }
src/README.md ADDED
@@ -0,0 +1,308 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ tags: [gradio-custom-component, Button]
3
+ title: gradio_buttonplus
4
+ short_description: Advanced Button Component for Gradio UI
5
+ colorFrom: blue
6
+ colorTo: yellow
7
+ sdk: gradio
8
+ pinned: false
9
+ app_file: space.py
10
+ ---
11
+
12
+ # `gradio_buttonplus`
13
+ <img alt="Static Badge" src="https://img.shields.io/badge/version%20-%200.0.1%20-%20orange">
14
+
15
+ Advanced Button Component for Gradio UI
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ pip install gradio_buttonplus
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ```python
26
+
27
+ import gradio as gr
28
+ from gradio_buttonplus import ButtonPlus
29
+
30
+
31
+ with gr.Blocks(theme=gr.themes.Ocean()) as demo:
32
+ gr.HTML("<h1><center>ButtonPlus Component Demo</center></h1>")
33
+ with gr.Row():
34
+ with gr.Column():
35
+ btn = ButtonPlus("⚙️", help="This button triggers an action.")
36
+ btn_2 = ButtonPlus("Another Test", help="This is a demo test")
37
+
38
+
39
+
40
+ if __name__ == "__main__":
41
+ demo.launch()
42
+
43
+ ```
44
+
45
+ ## `ButtonPlus`
46
+
47
+ ### Initialization
48
+
49
+ <table>
50
+ <thead>
51
+ <tr>
52
+ <th align="left">name</th>
53
+ <th align="left" style="width: 25%;">type</th>
54
+ <th align="left">default</th>
55
+ <th align="left">description</th>
56
+ </tr>
57
+ </thead>
58
+ <tbody>
59
+ <tr>
60
+ <td align="left"><code>value</code></td>
61
+ <td align="left" style="width: 25%;">
62
+
63
+ ```python
64
+ str | I18nData | Callable
65
+ ```
66
+
67
+ </td>
68
+ <td align="left"><code>"Run"</code></td>
69
+ <td align="left">default text for the button to display. If a function is provided, the function will be called each time the app loads to set the initial value of this component.</td>
70
+ </tr>
71
+
72
+ <tr>
73
+ <td align="left"><code>every</code></td>
74
+ <td align="left" style="width: 25%;">
75
+
76
+ ```python
77
+ Timer | float | None
78
+ ```
79
+
80
+ </td>
81
+ <td align="left"><code>None</code></td>
82
+ <td align="left">continuously calls `value` to recalculate it if `value` is a function (has no effect otherwise). Can provide a Timer whose tick resets `value`, or a float that provides the regular interval for the reset Timer.</td>
83
+ </tr>
84
+
85
+ <tr>
86
+ <td align="left"><code>inputs</code></td>
87
+ <td align="left" style="width: 25%;">
88
+
89
+ ```python
90
+ Component | Sequence[Component] | set[Component] | None
91
+ ```
92
+
93
+ </td>
94
+ <td align="left"><code>None</code></td>
95
+ <td align="left">components that are used as inputs to calculate `value` if `value` is a function (has no effect otherwise). `value` is recalculated any time the inputs change.</td>
96
+ </tr>
97
+
98
+ <tr>
99
+ <td align="left"><code>variant</code></td>
100
+ <td align="left" style="width: 25%;">
101
+
102
+ ```python
103
+ Literal["primary", "secondary", "stop", "huggingface"]
104
+ ```
105
+
106
+ </td>
107
+ <td align="left"><code>"secondary"</code></td>
108
+ <td align="left">sets the background and text color of the button. Use 'primary' for main call-to-action buttons, 'secondary' for a more subdued style, 'stop' for a stop button, 'huggingface' for a black background with white text, consistent with Hugging Face's button styles.</td>
109
+ </tr>
110
+
111
+ <tr>
112
+ <td align="left"><code>size</code></td>
113
+ <td align="left" style="width: 25%;">
114
+
115
+ ```python
116
+ Literal["sm", "md", "lg"]
117
+ ```
118
+
119
+ </td>
120
+ <td align="left"><code>"lg"</code></td>
121
+ <td align="left">size of the button. Can be "sm", "md", or "lg".</td>
122
+ </tr>
123
+
124
+ <tr>
125
+ <td align="left"><code>icon</code></td>
126
+ <td align="left" style="width: 25%;">
127
+
128
+ ```python
129
+ str | Path | None
130
+ ```
131
+
132
+ </td>
133
+ <td align="left"><code>None</code></td>
134
+ <td align="left">URL or path to the icon file to display within the button. If None, no icon will be displayed.</td>
135
+ </tr>
136
+
137
+ <tr>
138
+ <td align="left"><code>link</code></td>
139
+ <td align="left" style="width: 25%;">
140
+
141
+ ```python
142
+ str | None
143
+ ```
144
+
145
+ </td>
146
+ <td align="left"><code>None</code></td>
147
+ <td align="left">URL to open when the button is clicked. If None, no link will be used.</td>
148
+ </tr>
149
+
150
+ <tr>
151
+ <td align="left"><code>visible</code></td>
152
+ <td align="left" style="width: 25%;">
153
+
154
+ ```python
155
+ bool | Literal["hidden"]
156
+ ```
157
+
158
+ </td>
159
+ <td align="left"><code>True</code></td>
160
+ <td align="left">If False, component will be hidden. If "hidden", component will be visually hidden and not take up space in the layout but still exist in the DOM.</td>
161
+ </tr>
162
+
163
+ <tr>
164
+ <td align="left"><code>interactive</code></td>
165
+ <td align="left" style="width: 25%;">
166
+
167
+ ```python
168
+ bool
169
+ ```
170
+
171
+ </td>
172
+ <td align="left"><code>True</code></td>
173
+ <td align="left">if False, the ButtonPlus will be in a disabled state.</td>
174
+ </tr>
175
+
176
+ <tr>
177
+ <td align="left"><code>elem_id</code></td>
178
+ <td align="left" style="width: 25%;">
179
+
180
+ ```python
181
+ str | None
182
+ ```
183
+
184
+ </td>
185
+ <td align="left"><code>None</code></td>
186
+ <td align="left">an optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.</td>
187
+ </tr>
188
+
189
+ <tr>
190
+ <td align="left"><code>elem_classes</code></td>
191
+ <td align="left" style="width: 25%;">
192
+
193
+ ```python
194
+ list[str] | str | None
195
+ ```
196
+
197
+ </td>
198
+ <td align="left"><code>None</code></td>
199
+ <td align="left">an optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.</td>
200
+ </tr>
201
+
202
+ <tr>
203
+ <td align="left"><code>render</code></td>
204
+ <td align="left" style="width: 25%;">
205
+
206
+ ```python
207
+ bool
208
+ ```
209
+
210
+ </td>
211
+ <td align="left"><code>True</code></td>
212
+ <td align="left">if False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.</td>
213
+ </tr>
214
+
215
+ <tr>
216
+ <td align="left"><code>key</code></td>
217
+ <td align="left" style="width: 25%;">
218
+
219
+ ```python
220
+ int | str | tuple[int | str, ...] | None
221
+ ```
222
+
223
+ </td>
224
+ <td align="left"><code>None</code></td>
225
+ <td align="left">in a gr.render, Components with the same key across re-renders are treated as the same component, not a new component. Properties set in 'preserved_by_key' are not reset across a re-render.</td>
226
+ </tr>
227
+
228
+ <tr>
229
+ <td align="left"><code>preserved_by_key</code></td>
230
+ <td align="left" style="width: 25%;">
231
+
232
+ ```python
233
+ list[str] | str | None
234
+ ```
235
+
236
+ </td>
237
+ <td align="left"><code>"value"</code></td>
238
+ <td align="left">A list of parameters from this component's constructor. Inside a gr.render() function, if a component is re-rendered with the same key, these (and only these) parameters will be preserved in the UI (if they have been changed by the user or an event listener) instead of re-rendered based on the values provided during constructor.</td>
239
+ </tr>
240
+
241
+ <tr>
242
+ <td align="left"><code>scale</code></td>
243
+ <td align="left" style="width: 25%;">
244
+
245
+ ```python
246
+ int | None
247
+ ```
248
+
249
+ </td>
250
+ <td align="left"><code>None</code></td>
251
+ <td align="left">relative size compared to adjacent Components. For example if Components A and B are in a Row, and A has scale=2, and B has scale=1, A will be twice as wide as B. Should be an integer. scale applies in Rows, and to top-level Components in Blocks where fill_height=True.</td>
252
+ </tr>
253
+
254
+ <tr>
255
+ <td align="left"><code>min_width</code></td>
256
+ <td align="left" style="width: 25%;">
257
+
258
+ ```python
259
+ int | None
260
+ ```
261
+
262
+ </td>
263
+ <td align="left"><code>None</code></td>
264
+ <td align="left">minimum pixel width, will wrap if not sufficient screen space to satisfy this value. If a certain scale value results in this Component being narrower than min_width, the min_width parameter will be respected first.</td>
265
+ </tr>
266
+
267
+ <tr>
268
+ <td align="left"><code>help</code></td>
269
+ <td align="left" style="width: 25%;">
270
+
271
+ ```python
272
+ str | I18nData | None
273
+ ```
274
+
275
+ </td>
276
+ <td align="left"><code>None</code></td>
277
+ <td align="left">A string of help text to display in a tooltip when hovering over the button.</td>
278
+ </tr>
279
+ </tbody></table>
280
+
281
+
282
+ ### Events
283
+
284
+ | name | description |
285
+ |:-----|:------------|
286
+ | `click` | Triggered when the ButtonPlus is clicked. |
287
+
288
+
289
+
290
+ ### User function
291
+
292
+ 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).
293
+
294
+ - When used as an Input, the component only impacts the input signature of the user function.
295
+ - When used as an output, the component only impacts the return signature of the user function.
296
+
297
+ The code snippet below is accurate in cases where the component is used as both an input and an output.
298
+
299
+ - **As output:** Is passed, (Rarely used) the `str` corresponding to the button label when the button is clicked.
300
+ - **As input:** Should return, string corresponding to the button label.
301
+
302
+ ```python
303
+ def predict(
304
+ value: str | None
305
+ ) -> str | None:
306
+ return value
307
+ ```
308
+
src/backend/gradio_buttonplus/__init__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+
2
+ from .buttonplus import ButtonPlus
3
+
4
+ __all__ = ['ButtonPlus']
src/backend/gradio_buttonplus/buttonplus.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Callable, Sequence
4
+ from pathlib import Path
5
+ from typing import TYPE_CHECKING, Any, Literal
6
+
7
+ from gradio_client.documentation import document
8
+
9
+ from gradio.components.base import Component
10
+ from gradio.events import Events
11
+ from gradio.i18n import I18nData
12
+
13
+ if TYPE_CHECKING:
14
+ from gradio.components import Timer
15
+
16
+
17
+ class ButtonPlus(Component):
18
+ """
19
+ Creates a button that can be assigned arbitrary .click() events. The value (label) of the button can be used as an input to the function (rarely used) or set via the output of a function.
20
+ """
21
+
22
+ EVENTS = [Events.click]
23
+
24
+ def __init__(
25
+ self,
26
+ value: str | I18nData | Callable = "Run",
27
+ *,
28
+ every: Timer | float | None = None,
29
+ inputs: Component | Sequence[Component] | set[Component] | None = None,
30
+ variant: Literal["primary", "secondary", "stop", "huggingface"] = "secondary",
31
+ size: Literal["sm", "md", "lg"] = "lg",
32
+ icon: str | Path | None = None,
33
+ link: str | None = None,
34
+ visible: bool | Literal["hidden"] = True,
35
+ interactive: bool = True,
36
+ elem_id: str | None = None,
37
+ elem_classes: list[str] | str | None = None,
38
+ render: bool = True,
39
+ key: int | str | tuple[int | str, ...] | None = None,
40
+ preserved_by_key: list[str] | str | None = "value",
41
+ scale: int | None = None,
42
+ min_width: int | None = None,
43
+ help: str | I18nData | None = None,
44
+ ):
45
+ """
46
+ Parameters:
47
+ value: default text for the button to display. If a function is provided, the function will be called each time the app loads to set the initial value of this component.
48
+ every: continuously calls `value` to recalculate it if `value` is a function (has no effect otherwise). Can provide a Timer whose tick resets `value`, or a float that provides the regular interval for the reset Timer.
49
+ inputs: components that are used as inputs to calculate `value` if `value` is a function (has no effect otherwise). `value` is recalculated any time the inputs change.
50
+ variant: sets the background and text color of the button. Use 'primary' for main call-to-action buttons, 'secondary' for a more subdued style, 'stop' for a stop button, 'huggingface' for a black background with white text, consistent with Hugging Face's button styles.
51
+ size: size of the button. Can be "sm", "md", or "lg".
52
+ icon: URL or path to the icon file to display within the button. If None, no icon will be displayed.
53
+ link: URL to open when the button is clicked. If None, no link will be used.
54
+ visible: If False, component will be hidden. If "hidden", component will be visually hidden and not take up space in the layout but still exist in the DOM.
55
+ interactive: if False, the ButtonPlus will be in a disabled state.
56
+ elem_id: an optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
57
+ elem_classes: an optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
58
+ render: if False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
59
+ key: in a gr.render, Components with the same key across re-renders are treated as the same component, not a new component. Properties set in 'preserved_by_key' are not reset across a re-render.
60
+ preserved_by_key: A list of parameters from this component's constructor. Inside a gr.render() function, if a component is re-rendered with the same key, these (and only these) parameters will be preserved in the UI (if they have been changed by the user or an event listener) instead of re-rendered based on the values provided during constructor.
61
+ scale: relative size compared to adjacent Components. For example if Components A and B are in a Row, and A has scale=2, and B has scale=1, A will be twice as wide as B. Should be an integer. scale applies in Rows, and to top-level Components in Blocks where fill_height=True.
62
+ min_width: minimum pixel width, will wrap if not sufficient screen space to satisfy this value. If a certain scale value results in this Component being narrower than min_width, the min_width parameter will be respected first.
63
+ help: A string of help text to display in a tooltip when hovering over the button.
64
+ """
65
+ super().__init__(
66
+ every=every,
67
+ inputs=inputs,
68
+ visible=visible,
69
+ elem_id=elem_id,
70
+ elem_classes=elem_classes,
71
+ render=render,
72
+ key=key,
73
+ preserved_by_key=preserved_by_key,
74
+ value=value,
75
+ interactive=interactive,
76
+ scale=scale,
77
+ min_width=min_width,
78
+ )
79
+ self.icon = self.serve_static_file(icon)
80
+ self.variant = variant
81
+ self.size = size
82
+ self.link = link
83
+ self.help = help
84
+
85
+ @property
86
+ def skip_api(self):
87
+ return True
88
+
89
+ def preprocess(self, payload: str | None) -> str | None:
90
+ """
91
+ Parameters:
92
+ payload: string corresponding to the button label
93
+ Returns:
94
+ (Rarely used) the `str` corresponding to the button label when the button is clicked
95
+ """
96
+ return payload
97
+
98
+ def postprocess(self, value: str | None) -> str | None:
99
+ """
100
+ Parameters:
101
+ value: string corresponding to the button label
102
+ Returns:
103
+ Expects a `str` value that is set as the button label
104
+ """
105
+ return str(value)
106
+
107
+ def example_payload(self) -> Any:
108
+ return "Run"
109
+
110
+ def example_value(self) -> Any:
111
+ return "Run"
src/backend/gradio_buttonplus/templates/component/index.js ADDED
The diff for this file is too large to render. See raw diff
 
src/backend/gradio_buttonplus/templates/component/style.css ADDED
@@ -0,0 +1 @@
 
 
1
+ img.svelte-kxeri3{object-fit:cover}.block.svelte-239wnu{position:relative;margin:0;box-shadow:var(--block-shadow);border-width:var(--block-border-width);border-color:var(--block-border-color);border-radius:var(--block-radius);background:var(--block-background-fill);width:100%;line-height:var(--line-sm)}.block.fullscreen.svelte-239wnu{border-radius:0}.auto-margin.svelte-239wnu{margin-left:auto;margin-right:auto}.block.border_focus.svelte-239wnu{border-color:var(--color-accent)}.block.border_contrast.svelte-239wnu{border-color:var(--body-text-color)}.padded.svelte-239wnu{padding:var(--block-padding)}.hidden.svelte-239wnu{display:none}.flex.svelte-239wnu{display:flex;flex-direction:column}.hide-container.svelte-239wnu:not(.fullscreen){margin:0;box-shadow:none;--block-border-width:0;background:transparent;padding:0;overflow:visible}.resize-handle.svelte-239wnu{position:absolute;bottom:0;right:0;width:10px;height:10px;fill:var(--block-border-color);cursor:nwse-resize}.fullscreen.svelte-239wnu{position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:1000;overflow:auto}.animating.svelte-239wnu{animation:svelte-239wnu-pop-out .1s ease-out forwards}@keyframes svelte-239wnu-pop-out{0%{position:fixed;top:var(--start-top);left:var(--start-left);width:var(--start-width);height:var(--start-height);z-index:100}to{position:fixed;top:0vh;left:0vw;width:100vw;height:100vh;z-index:1000}}.placeholder.svelte-239wnu{border-radius:var(--block-radius);border-width:var(--block-border-width);border-color:var(--block-border-color);border-style:dashed}Tables */ table,tr,td,th{margin-top:var(--spacing-sm);margin-bottom:var(--spacing-sm);padding:var(--spacing-xl)}.md code,.md pre{background:none;font-family:var(--font-mono);font-size:var(--text-sm);text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:2;tab-size:2;-webkit-hyphens:none;hyphens:none}.md pre[class*=language-]::selection,.md pre[class*=language-] ::selection,.md code[class*=language-]::selection,.md code[class*=language-] ::selection{text-shadow:none;background:#b3d4fc}.md pre{padding:1em;margin:.5em 0;overflow:auto;position:relative;margin-top:var(--spacing-sm);margin-bottom:var(--spacing-sm);box-shadow:none;border:none;border-radius:var(--radius-md);background:var(--code-background-fill);padding:var(--spacing-xxl);font-family:var(--font-mono);text-shadow:none;border-radius:var(--radius-sm);white-space:nowrap;display:block;white-space:pre}.md :not(pre)>code{padding:.1em;border-radius:var(--radius-xs);white-space:normal;background:var(--code-background-fill);border:1px solid var(--panel-border-color);padding:var(--spacing-xxs) var(--spacing-xs)}.md .token.comment,.md .token.prolog,.md .token.doctype,.md .token.cdata{color:#708090}.md .token.punctuation{color:#999}.md .token.namespace{opacity:.7}.md .token.property,.md .token.tag,.md .token.boolean,.md .token.number,.md .token.constant,.md .token.symbol,.md .token.deleted{color:#905}.md .token.selector,.md .token.attr-name,.md .token.string,.md .token.char,.md .token.builtin,.md .token.inserted{color:#690}.md .token.atrule,.md .token.attr-value,.md .token.keyword{color:#07a}.md .token.function,.md .token.class-name{color:#dd4a68}.md .token.regex,.md .token.important,.md .token.variable{color:#e90}.md .token.important,.md .token.bold{font-weight:700}.md .token.italic{font-style:italic}.md .token.entity{cursor:help}.dark .md .token.comment,.dark .md .token.prolog,.dark .md .token.cdata{color:#5c6370}.dark .md .token.doctype,.dark .md .token.punctuation,.dark .md .token.entity{color:#abb2bf}.dark .md .token.attr-name,.dark .md .token.class-name,.dark .md .token.boolean,.dark .md .token.constant,.dark .md .token.number,.dark .md .token.atrule{color:#d19a66}.dark .md .token.keyword{color:#c678dd}.dark .md .token.property,.dark .md .token.tag,.dark .md .token.symbol,.dark .md .token.deleted,.dark .md .token.important{color:#e06c75}.dark .md .token.selector,.dark .md .token.string,.dark .md .token.char,.dark .md .token.builtin,.dark .md .token.inserted,.dark .md .token.regex,.dark .md .token.attr-value,.dark .md .token.attr-value>.token.punctuation{color:#98c379}.dark .md .token.variable,.dark .md .token.operator,.dark .md .token.function{color:#61afef}.dark .md .token.url{color:#56b6c2}span.svelte-1m32c2s div[class*=code_wrap]{position:relative}span.svelte-1m32c2s span.katex{font-size:var(--text-lg);direction:ltr}span.svelte-1m32c2s div[class*=code_wrap]>button{z-index:1;cursor:pointer;border-bottom-left-radius:var(--radius-sm);padding:var(--spacing-md);width:25px;height:25px;position:absolute;right:0}span.svelte-1m32c2s .check{opacity:0;z-index:var(--layer-top);transition:opacity .2s;background:var(--code-background-fill);color:var(--body-text-color);position:absolute;top:var(--size-1-5);left:var(--size-1-5)}span.svelte-1m32c2s p:not(:first-child){margin-top:var(--spacing-xxl)}span.svelte-1m32c2s .md-header-anchor{margin-left:-25px;padding-right:8px;line-height:1;color:var(--body-text-color-subdued);opacity:0}span.svelte-1m32c2s h1:hover .md-header-anchor,span.svelte-1m32c2s h2:hover .md-header-anchor,span.svelte-1m32c2s h3:hover .md-header-anchor,span.svelte-1m32c2s h4:hover .md-header-anchor,span.svelte-1m32c2s h5:hover .md-header-anchor,span.svelte-1m32c2s h6:hover .md-header-anchor{opacity:1}span.md.svelte-1m32c2s .md-header-anchor>svg{color:var(--body-text-color-subdued)}span.svelte-1m32c2s table{word-break:break-word}div.svelte-17qq50w>.md.prose{font-weight:var(--block-info-text-weight);font-size:var(--block-info-text-size);line-height:var(--line-sm)}div.svelte-17qq50w>.md.prose *{color:var(--block-info-text-color)}div.svelte-17qq50w{margin-bottom:var(--spacing-md)}span.has-info.svelte-zgrq3{margin-bottom:var(--spacing-xs)}span.svelte-zgrq3:not(.has-info){margin-bottom:var(--spacing-lg)}span.svelte-zgrq3{display:inline-block;position:relative;z-index:var(--layer-4);border:solid var(--block-title-border-width) var(--block-title-border-color);border-radius:var(--block-title-radius);background:var(--block-title-background-fill);padding:var(--block-title-padding);color:var(--block-title-text-color);font-weight:var(--block-title-text-weight);font-size:var(--block-title-text-size);line-height:var(--line-sm)}span[dir=rtl].svelte-zgrq3{display:block}.hide.svelte-zgrq3{margin:0;height:0}label.svelte-igqdol.svelte-igqdol{display:inline-flex;align-items:center;z-index:var(--layer-2);box-shadow:var(--block-label-shadow);border:var(--block-label-border-width) solid var(--block-label-border-color);border-top:none;border-left:none;border-radius:var(--block-label-radius);background:var(--block-label-background-fill);padding:var(--block-label-padding);pointer-events:none;color:var(--block-label-text-color);font-weight:var(--block-label-text-weight);font-size:var(--block-label-text-size);line-height:var(--line-sm)}.gr-group label.svelte-igqdol.svelte-igqdol{border-top-left-radius:0}label.float.svelte-igqdol.svelte-igqdol{position:absolute;top:var(--block-label-margin);left:var(--block-label-margin)}label.svelte-igqdol.svelte-igqdol:not(.float){position:static;margin-top:var(--block-label-margin);margin-left:var(--block-label-margin)}.hide.svelte-igqdol.svelte-igqdol{display:none}span.svelte-igqdol.svelte-igqdol{opacity:.8;margin-right:var(--size-2);width:calc(var(--block-label-text-size) - 1px);height:calc(var(--block-label-text-size) - 1px)}.hide-label.svelte-igqdol.svelte-igqdol{box-shadow:none;border-width:0;background:transparent;overflow:visible}label[dir=rtl].svelte-igqdol.svelte-igqdol{border:var(--block-label-border-width) solid var(--block-label-border-color);border-top:none;border-right:none;border-bottom-left-radius:var(--block-radius);border-bottom-right-radius:var(--block-label-radius);border-top-left-radius:var(--block-label-radius)}label[dir=rtl].svelte-igqdol span.svelte-igqdol{margin-left:var(--size-2);margin-right:0}.unstyled-link.svelte-151nsdd{all:unset;cursor:pointer}button.svelte-y0enk4{display:flex;justify-content:center;align-items:center;gap:1px;z-index:var(--layer-2);border-radius:var(--radius-xs);color:var(--block-label-text-color);border:1px solid var(--border-color);padding:var(--spacing-xxs)}button.svelte-y0enk4:hover{background-color:var(--background-fill-secondary)}button[disabled].svelte-y0enk4{opacity:.5;box-shadow:none}button[disabled].svelte-y0enk4:hover{cursor:not-allowed}.padded.svelte-y0enk4{background:var(--bg-color)}button.svelte-y0enk4:hover,button.highlight.svelte-y0enk4{cursor:pointer;color:var(--color-accent)}.padded.svelte-y0enk4:hover{color:var(--block-label-text-color)}span.svelte-y0enk4{padding:0 1px;font-size:10px}div.svelte-y0enk4{display:flex;align-items:center;justify-content:center;transition:filter .2s ease-in-out}.x-small.svelte-y0enk4{width:10px;height:10px}.small.svelte-y0enk4{width:14px;height:14px}.medium.svelte-y0enk4{width:20px;height:20px}.large.svelte-y0enk4{width:22px;height:22px}.pending.svelte-y0enk4{animation:svelte-y0enk4-flash .5s infinite}@keyframes svelte-y0enk4-flash{0%{opacity:.5}50%{opacity:1}to{opacity:.5}}.transparent.svelte-y0enk4{background:transparent;border:none;box-shadow:none}.empty.svelte-3w3rth{display:flex;justify-content:center;align-items:center;margin-top:calc(0px - var(--size-6));height:var(--size-full)}.icon.svelte-3w3rth{opacity:.5;height:var(--size-5);color:var(--body-text-color)}.small.svelte-3w3rth{min-height:calc(var(--size-32) - 20px)}.large.svelte-3w3rth{min-height:calc(var(--size-64) - 20px)}.unpadded_box.svelte-3w3rth{margin-top:0}.small_parent.svelte-3w3rth{min-height:100%!important}.dropdown-arrow.svelte-145leq6,.dropdown-arrow.svelte-ihhdbf{fill:currentColor}.circle.svelte-ihhdbf{fill:currentColor;opacity:.1}svg.svelte-pb9pol{animation:svelte-pb9pol-spin 1.5s linear infinite}@keyframes svelte-pb9pol-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}h2.svelte-1xg7h5n{font-size:var(--text-xl)!important}p.svelte-1xg7h5n,h2.svelte-1xg7h5n{white-space:pre-line}.wrap.svelte-1xg7h5n{display:flex;flex-direction:column;justify-content:center;align-items:center;min-height:var(--size-60);color:var(--block-label-text-color);line-height:var(--line-md);height:100%;padding-top:var(--size-3);text-align:center;margin:auto var(--spacing-lg)}.or.svelte-1xg7h5n{color:var(--body-text-color-subdued);display:flex}.icon-wrap.svelte-1xg7h5n{width:30px;margin-bottom:var(--spacing-lg)}@media (--screen-md){.wrap.svelte-1xg7h5n{font-size:var(--text-lg)}}.hovered.svelte-1xg7h5n{color:var(--color-accent)}div.svelte-q32hvf{border-top:1px solid transparent;display:flex;max-height:100%;justify-content:center;align-items:center;gap:var(--spacing-sm);height:auto;align-items:flex-end;color:var(--block-label-text-color);flex-shrink:0}.show_border.svelte-q32hvf{border-top:1px solid var(--block-border-color);margin-top:var(--spacing-xxl);box-shadow:var(--shadow-drop)}.source-selection.svelte-15ls1gu{display:flex;align-items:center;justify-content:center;border-top:1px solid var(--border-color-primary);width:100%;margin-left:auto;margin-right:auto;height:var(--size-10)}.icon.svelte-15ls1gu{width:22px;height:22px;margin:var(--spacing-lg) var(--spacing-xs);padding:var(--spacing-xs);color:var(--neutral-400);border-radius:var(--radius-md)}.selected.svelte-15ls1gu{color:var(--color-accent)}.icon.svelte-15ls1gu:hover,.icon.svelte-15ls1gu:focus{color:var(--color-accent)}.icon-button-wrapper.svelte-1h0hs6p{display:flex;flex-direction:row;align-items:center;justify-content:center;z-index:var(--layer-2);gap:var(--spacing-sm);box-shadow:var(--shadow-drop);border:1px solid var(--border-color-primary);background:var(--block-background-fill);padding:var(--spacing-xxs)}.icon-button-wrapper.hide-top-corner.svelte-1h0hs6p{border-top:none;border-right:none;border-radius:var(--block-label-right-radius)}.icon-button-wrapper.display-top-corner.svelte-1h0hs6p{border-radius:var(--radius-sm) 0 0 var(--radius-sm);top:var(--spacing-sm);right:-1px}.icon-button-wrapper.svelte-1h0hs6p:not(.top-panel){border:1px solid var(--border-color-primary);border-radius:var(--radius-sm)}.top-panel.svelte-1h0hs6p{position:absolute;top:var(--block-label-margin);right:var(--block-label-margin);margin:0}.icon-button-wrapper.svelte-1h0hs6p button{margin:var(--spacing-xxs);border-radius:var(--radius-xs);position:relative}.icon-button-wrapper.svelte-1h0hs6p a.download-link:not(:last-child),.icon-button-wrapper.svelte-1h0hs6p button:not(:last-child){margin-right:var(--spacing-xxs)}.icon-button-wrapper.svelte-1h0hs6p a.download-link:not(:last-child):not(.no-border *):after,.icon-button-wrapper.svelte-1h0hs6p button:not(:last-child):not(.no-border *):after{content:"";position:absolute;right:-4.5px;top:15%;height:70%;width:1px;background-color:var(--border-color-primary)}.icon-button-wrapper.svelte-1h0hs6p>*{height:100%}.image-container.svelte-x2tujq.svelte-x2tujq{height:100%;position:relative;min-width:var(--size-20)}.image-container.svelte-x2tujq button.svelte-x2tujq{width:var(--size-full);height:var(--size-full);border-radius:var(--radius-lg);display:flex;align-items:center;justify-content:center}.image-frame.svelte-x2tujq img{width:var(--size-full);height:var(--size-full);object-fit:scale-down}.selectable.svelte-x2tujq.svelte-x2tujq{cursor:crosshair}.fullscreen-controls svg{position:relative;top:0}.image-container:fullscreen{background-color:#000;display:flex;justify-content:center;align-items:center}.image-container:fullscreen img{max-width:90vw;max-height:90vh;object-fit:scale-down}.image-frame.svelte-x2tujq.svelte-x2tujq{width:auto;height:100%;display:flex;align-items:center;justify-content:center}button.svelte-u3k78w,a.svelte-u3k78w{display:inline-flex;justify-content:center;align-items:center;transition:var(--button-transition);padding:var(--size-0-5) var(--size-2);text-align:center;position:relative}button.svelte-u3k78w:hover{transform:var(--button-transform-hover)}button.svelte-u3k78w:active,a.svelte-u3k78w:active{transform:var(--button-transform-active)}button[disabled].svelte-u3k78w,a.disabled.svelte-u3k78w{opacity:.5;filter:grayscale(30%);cursor:not-allowed;transform:none}.hidden.svelte-u3k78w{display:none}.primary.svelte-u3k78w{border:var(--button-border-width) solid var(--button-primary-border-color);background:var(--button-primary-background-fill);color:var(--button-primary-text-color);box-shadow:var(--button-primary-shadow)}.primary.svelte-u3k78w:hover,.primary[disabled].svelte-u3k78w{background:var(--button-primary-background-fill-hover);color:var(--button-primary-text-color-hover)}.primary.svelte-u3k78w:hover{border-color:var(--button-primary-border-color-hover);box-shadow:var(--button-primary-shadow-hover)}.primary.svelte-u3k78w:active{box-shadow:var(--button-primary-shadow-active)}.primary[disabled].svelte-u3k78w{border-color:var(--button-primary-border-color)}.secondary.svelte-u3k78w{border:var(--button-border-width) solid var(--button-secondary-border-color);background:var(--button-secondary-background-fill);color:var(--button-secondary-text-color);box-shadow:var(--button-secondary-shadow)}.secondary.svelte-u3k78w:hover,.secondary[disabled].svelte-u3k78w{background:var(--button-secondary-background-fill-hover);color:var(--button-secondary-text-color-hover)}.secondary.svelte-u3k78w:hover{border-color:var(--button-secondary-border-color-hover);box-shadow:var(--button-secondary-shadow-hover)}.secondary.svelte-u3k78w:active{box-shadow:var(--button-secondary-shadow-active)}.secondary[disabled].svelte-u3k78w{border-color:var(--button-secondary-border-color)}.stop.svelte-u3k78w{background:var(--button-cancel-background-fill);color:var(--button-cancel-text-color);border:var(--button-border-width) solid var(--button-cancel-border-color);box-shadow:var(--button-cancel-shadow)}.stop.svelte-u3k78w:hover,.stop[disabled].svelte-u3k78w{background:var(--button-cancel-background-fill-hover)}.stop.svelte-u3k78w:hover{border-color:var(--button-cancel-border-color-hover);box-shadow:var(--button-cancel-shadow-hover)}.stop.svelte-u3k78w:active{box-shadow:var(--button-cancel-shadow-active)}.stop[disabled].svelte-u3k78w{border-color:var(--button-cancel-border-color)}.sm.svelte-u3k78w{border-radius:var(--button-small-radius);padding:var(--button-small-padding);font-weight:var(--button-small-text-weight);font-size:var(--button-small-text-size)}.md.svelte-u3k78w{border-radius:var(--button-medium-radius);padding:var(--button-medium-padding);font-weight:var(--button-medium-text-weight);font-size:var(--button-medium-text-size)}.lg.svelte-u3k78w{border-radius:var(--button-large-radius);padding:var(--button-large-padding);font-weight:var(--button-large-text-weight);font-size:var(--button-large-text-size)}.button-icon{width:var(--text-xl);height:var(--text-xl)}.button-icon.right-padded{margin-right:var(--spacing-md)}.huggingface.svelte-u3k78w{background:#141c2e;color:#fff}.huggingface.svelte-u3k78w:hover{background:#283042;color:#fff}.button-content.svelte-u3k78w{display:inline;visibility:visible;color:inherit}.tooltip-text.svelte-u3k78w{width:auto;max-width:500px;background-color:var(--body-text-color);color:var(--background-fill-primary);text-align:center;border-radius:var(--radius-md);padding:var(--spacing-md);z-index:var(--layer-top);opacity:1;transition:opacity .2s;pointer-events:none;font-weight:var(--body-text-weight);font-size:var(--body-text-size)}
src/demo/__init__.py ADDED
File without changes
src/demo/app.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import gradio as gr
3
+ from gradio_buttonplus import ButtonPlus
4
+
5
+
6
+ with gr.Blocks(theme=gr.themes.Ocean()) as demo:
7
+ gr.HTML("<h1><center>ButtonPlus Component Demo</center></h1>")
8
+ with gr.Row():
9
+ with gr.Column():
10
+ btn = ButtonPlus("⚙️", help="This button triggers an action.")
11
+ btn_2 = ButtonPlus("Another Test", help="This is a demo test")
12
+
13
+
14
+
15
+ if __name__ == "__main__":
16
+ 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_buttonplus
src/demo/space.py ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import gradio as gr
3
+ from app import demo as app
4
+ import os
5
+
6
+ _docs = {'ButtonPlus': {'description': 'Creates a button that can be assigned arbitrary .click() events. The value (label) of the button can be used as an input to the function (rarely used) or set via the output of a function.', 'members': {'__init__': {'value': {'type': 'str | I18nData | Callable', 'default': '"Run"', 'description': 'default text for the button to display. If a function is provided, the function will be called each time the app loads to set the initial value of this component.'}, 'every': {'type': 'Timer | float | None', 'default': 'None', 'description': 'continuously calls `value` to recalculate it if `value` is a function (has no effect otherwise). Can provide a Timer whose tick resets `value`, or a float that provides the regular interval for the reset Timer.'}, 'inputs': {'type': 'Component | Sequence[Component] | set[Component] | None', 'default': 'None', 'description': 'components that are used as inputs to calculate `value` if `value` is a function (has no effect otherwise). `value` is recalculated any time the inputs change.'}, 'variant': {'type': 'Literal["primary", "secondary", "stop", "huggingface"]', 'default': '"secondary"', 'description': "sets the background and text color of the button. Use 'primary' for main call-to-action buttons, 'secondary' for a more subdued style, 'stop' for a stop button, 'huggingface' for a black background with white text, consistent with Hugging Face's button styles."}, 'size': {'type': 'Literal["sm", "md", "lg"]', 'default': '"lg"', 'description': 'size of the button. Can be "sm", "md", or "lg".'}, 'icon': {'type': 'str | Path | None', 'default': 'None', 'description': 'URL or path to the icon file to display within the button. If None, no icon will be displayed.'}, 'link': {'type': 'str | None', 'default': 'None', 'description': 'URL to open when the button is clicked. If None, no link will be used.'}, 'visible': {'type': 'bool | Literal["hidden"]', 'default': 'True', 'description': 'If False, component will be hidden. If "hidden", component will be visually hidden and not take up space in the layout but still exist in the DOM.'}, 'interactive': {'type': 'bool', 'default': 'True', 'description': 'if False, the ButtonPlus will be in a disabled state.'}, 'elem_id': {'type': 'str | None', 'default': 'None', 'description': 'an optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.'}, 'elem_classes': {'type': 'list[str] | str | None', 'default': 'None', 'description': 'an optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.'}, 'render': {'type': 'bool', 'default': 'True', 'description': 'if False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.'}, 'key': {'type': 'int | str | tuple[int | str, ...] | None', 'default': 'None', 'description': "in a gr.render, Components with the same key across re-renders are treated as the same component, not a new component. Properties set in 'preserved_by_key' are not reset across a re-render."}, 'preserved_by_key': {'type': 'list[str] | str | None', 'default': '"value"', 'description': "A list of parameters from this component's constructor. Inside a gr.render() function, if a component is re-rendered with the same key, these (and only these) parameters will be preserved in the UI (if they have been changed by the user or an event listener) instead of re-rendered based on the values provided during constructor."}, 'scale': {'type': 'int | None', 'default': 'None', 'description': 'relative size compared to adjacent Components. For example if Components A and B are in a Row, and A has scale=2, and B has scale=1, A will be twice as wide as B. Should be an integer. scale applies in Rows, and to top-level Components in Blocks where fill_height=True.'}, 'min_width': {'type': 'int | None', 'default': 'None', 'description': 'minimum pixel width, will wrap if not sufficient screen space to satisfy this value. If a certain scale value results in this Component being narrower than min_width, the min_width parameter will be respected first.'}, 'help': {'type': 'str | I18nData | None', 'default': 'None', 'description': 'A string of help text to display in a tooltip when hovering over the button.'}}, 'postprocess': {'value': {'type': 'str | None', 'description': 'string corresponding to the button label'}}, 'preprocess': {'return': {'type': 'str | None', 'description': '(Rarely used) the `str` corresponding to the button label when the button is clicked'}, 'value': None}}, 'events': {'click': {'type': None, 'default': None, 'description': 'Triggered when the ButtonPlus is clicked.'}}}, '__meta__': {'additional_interfaces': {}, 'user_fn_refs': {'ButtonPlus': []}}}
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.Ocean(
13
+ font_mono=[
14
+ gr.themes.GoogleFont("Inconsolata"),
15
+ "monospace",
16
+ ],
17
+ ),
18
+ ) as demo:
19
+ gr.Markdown(
20
+ """
21
+ # `gradio_buttonplus`
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
+ Advanced Button Component for Gradio UI
28
+ """, elem_classes=["md-custom"], header_links=True)
29
+ app.render()
30
+ gr.Markdown(
31
+ """
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install gradio_buttonplus
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ ```python
41
+
42
+ import gradio as gr
43
+ from gradio_buttonplus import ButtonPlus
44
+
45
+
46
+ with gr.Blocks(theme=gr.themes.Ocean()) as demo:
47
+ gr.HTML("<h1><center>ButtonPlus Component Demo</center></h1>")
48
+ with gr.Row():
49
+ with gr.Column():
50
+ btn = ButtonPlus("⚙️", help="This button triggers an action.")
51
+ btn_2 = ButtonPlus("Another Test", help="This is a demo test")
52
+
53
+
54
+
55
+ if __name__ == "__main__":
56
+ demo.launch()
57
+
58
+ ```
59
+ """, elem_classes=["md-custom"], header_links=True)
60
+
61
+
62
+ gr.Markdown("""
63
+ ## `ButtonPlus`
64
+
65
+ ### Initialization
66
+ """, elem_classes=["md-custom"], header_links=True)
67
+
68
+ gr.ParamViewer(value=_docs["ButtonPlus"]["members"]["__init__"], linkify=[])
69
+
70
+
71
+ gr.Markdown("### Events")
72
+ gr.ParamViewer(value=_docs["ButtonPlus"]["events"], linkify=['Event'])
73
+
74
+
75
+
76
+
77
+ gr.Markdown("""
78
+
79
+ ### User function
80
+
81
+ 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).
82
+
83
+ - When used as an Input, the component only impacts the input signature of the user function.
84
+ - When used as an output, the component only impacts the return signature of the user function.
85
+
86
+ The code snippet below is accurate in cases where the component is used as both an input and an output.
87
+
88
+ - **As input:** Is passed, (Rarely used) the `str` corresponding to the button label when the button is clicked.
89
+ - **As output:** Should return, string corresponding to the button label.
90
+
91
+ ```python
92
+ def predict(
93
+ value: str | None
94
+ ) -> str | None:
95
+ return value
96
+ ```
97
+ """, elem_classes=["md-custom", "ButtonPlus-user-fn"], header_links=True)
98
+
99
+
100
+
101
+
102
+ demo.load(None, js=r"""function() {
103
+ const refs = {};
104
+ const user_fn_refs = {
105
+ ButtonPlus: [], };
106
+ requestAnimationFrame(() => {
107
+
108
+ Object.entries(user_fn_refs).forEach(([key, refs]) => {
109
+ if (refs.length > 0) {
110
+ const el = document.querySelector(`.${key}-user-fn`);
111
+ if (!el) return;
112
+ refs.forEach(ref => {
113
+ el.innerHTML = el.innerHTML.replace(
114
+ new RegExp("\\b"+ref+"\\b", "g"),
115
+ `<a href="#h-${ref.toLowerCase()}">${ref}</a>`
116
+ );
117
+ })
118
+ }
119
+ })
120
+
121
+ Object.entries(refs).forEach(([key, refs]) => {
122
+ if (refs.length > 0) {
123
+ const el = document.querySelector(`.${key}`);
124
+ if (!el) return;
125
+ refs.forEach(ref => {
126
+ el.innerHTML = el.innerHTML.replace(
127
+ new RegExp("\\b"+ref+"\\b", "g"),
128
+ `<a href="#h-${ref.toLowerCase()}">${ref}</a>`
129
+ );
130
+ })
131
+ }
132
+ })
133
+ })
134
+ }
135
+
136
+ """)
137
+
138
+ demo.launch()
src/frontend/Index.svelte ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script context="module" lang="ts">
2
+ export { default as BaseButton } from "./shared/Button.svelte";
3
+ </script>
4
+
5
+ <script lang="ts">
6
+ import type { Gradio } from "@gradio/utils";
7
+ import { type FileData } from "@gradio/client";
8
+
9
+ import Button from "./shared/Button.svelte";
10
+
11
+ export let elem_id = "";
12
+ export let elem_classes: string[] = [];
13
+ export let visible: boolean | "hidden" = true;
14
+ export let value: string | null;
15
+ export let variant: "primary" | "secondary" | "stop" = "secondary";
16
+ export let interactive: boolean;
17
+ export let size: "sm" | "lg" = "lg";
18
+ export let scale: number | null = null;
19
+ export let icon: FileData | null = null;
20
+ export let link: string | null = null;
21
+ export let min_width: number | undefined = undefined;
22
+ export let help: string | undefined = undefined;
23
+ export let gradio: Gradio<{
24
+ click: never;
25
+ }>;
26
+ </script>
27
+
28
+ <Button
29
+ {value}
30
+ {variant}
31
+ {elem_id}
32
+ {elem_classes}
33
+ {size}
34
+ {scale}
35
+ {link}
36
+ {icon}
37
+ {min_width}
38
+ {visible}
39
+ {help}
40
+ disabled={!interactive}
41
+ on:click={() => gradio.dispatch("click")}
42
+ />
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/main.ts ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ export { default as default } from "./Index.svelte";
2
+ export { default as BaseButton } from "./shared/Button.svelte";
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,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "gradio_buttonplus",
3
+ "version": "0.5.13",
4
+ "description": "Gradio UI packages",
5
+ "type": "module",
6
+ "author": "",
7
+ "license": "ISC",
8
+ "private": false,
9
+ "dependencies": {
10
+ "@gradio/client": "1.19.1",
11
+ "@gradio/image": "0.23.1",
12
+ "@gradio/upload": "0.17.1",
13
+ "@gradio/utils": "0.10.2"
14
+ },
15
+ "devDependencies": {
16
+ "@gradio/preview": "0.14.0"
17
+ },
18
+ "main": "./Index.svelte",
19
+ "main_changeset": true,
20
+ "exports": {
21
+ "./package.json": "./package.json",
22
+ ".": {
23
+ "gradio": "./Index.svelte",
24
+ "svelte": "./dist/Index.svelte",
25
+ "types": "./dist/Index.svelte.d.ts"
26
+ }
27
+ },
28
+ "peerDependencies": {
29
+ "svelte": "^4.0.0"
30
+ },
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "git+https://github.com/gradio-app/gradio.git",
34
+ "directory": "js/button"
35
+ }
36
+ }
src/frontend/shared/Button.svelte ADDED
@@ -0,0 +1,306 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { type FileData } from "@gradio/client";
3
+ import { Image } from "@gradio/image/shared";
4
+ import { onMount, tick } from "svelte";
5
+
6
+ export let elem_id = "";
7
+ export let elem_classes: string[] = [];
8
+ export let visible: boolean | "hidden" = true;
9
+ export let variant: "primary" | "secondary" | "stop" | "huggingface" = "secondary";
10
+ export let size: "sm" | "md" | "lg" = "lg";
11
+ export let value: string | null = null;
12
+ export let link: string | null = null;
13
+ export let icon: FileData | null = null;
14
+ export let disabled = false;
15
+ export let scale: number | null = null;
16
+ export let min_width: number | undefined = undefined;
17
+ export let help: string | undefined = undefined;
18
+
19
+ let show_tooltip = false;
20
+ let tooltip_element: HTMLSpanElement;
21
+ let button_element: HTMLButtonElement | HTMLAnchorElement;
22
+
23
+ function position_tooltip() {
24
+ if (!tooltip_element || !button_element) return;
25
+ const button_rect = button_element.getBoundingClientRect();
26
+ const tooltip_rect = tooltip_element.getBoundingClientRect();
27
+ tooltip_element.style.position = "fixed";
28
+ // Center horizontally below the button
29
+ tooltip_element.style.left = `${button_rect.left + (button_rect.width - tooltip_rect.width) / 2}px`;
30
+ // Position below the button with an 8px offset
31
+ tooltip_element.style.top = `${button_rect.bottom + 8}px`;
32
+ }
33
+
34
+ function portal(node: HTMLElement) {
35
+ document.body.appendChild(node);
36
+ return {
37
+ destroy() {
38
+ if (node.parentNode) {
39
+ node.parentNode.removeChild(node);
40
+ }
41
+ }
42
+ };
43
+ }
44
+
45
+ function handle_show_tooltip() {
46
+ show_tooltip = true;
47
+ // Wait for tooltip to render before positioning
48
+ tick().then(() => {
49
+ position_tooltip();
50
+ // Force reposition on next frame to ensure correct dimensions
51
+ requestAnimationFrame(position_tooltip);
52
+ });
53
+ }
54
+
55
+ // Update tooltip position on window resize
56
+ onMount(() => {
57
+ const handle_resize = () => {
58
+ if (show_tooltip) {
59
+ tick().then(position_tooltip);
60
+ }
61
+ };
62
+ window.addEventListener("resize", handle_resize);
63
+ return () => window.removeEventListener("resize", handle_resize);
64
+ });
65
+ </script>
66
+
67
+ {#if link && link.length > 0}
68
+ <a
69
+ href={link}
70
+ rel="noopener noreferrer"
71
+ class:hidden={visible === false || visible === "hidden"}
72
+ class:disabled
73
+ aria-disabled={disabled}
74
+ class="{size} {variant} {elem_classes.join(' ')}"
75
+ style:flex-grow={scale}
76
+ style:pointer-events={disabled ? "none" : null}
77
+ style:width={scale === 0 ? "fit-content" : null}
78
+ style:min-width={typeof min_width === "number" ? `calc(min(${min_width}px, 100%))` : null}
79
+ id={elem_id}
80
+ bind:this={button_element}
81
+ on:mouseenter={help ? handle_show_tooltip : null}
82
+ on:mouseleave={help ? () => show_tooltip = false : null}
83
+ on:focusin={help ? handle_show_tooltip : null}
84
+ on:focusout={help ? () => show_tooltip = false : null}
85
+ >
86
+ {#if icon}
87
+ <Image class="button-icon" src={icon.url} alt={`${value} icon`} />
88
+ {/if}
89
+ <span class="button-content">
90
+ {#if value}
91
+ {value}
92
+ {:else}
93
+ <slot />
94
+ {/if}
95
+ </span>
96
+ {#if show_tooltip && help}
97
+ <span class="tooltip-text" bind:this={tooltip_element} use:portal>
98
+ {help}
99
+ </span>
100
+ {/if}
101
+ </a>
102
+ {:else}
103
+ <button
104
+ on:click
105
+ class:hidden={visible === false || visible === "hidden"}
106
+ class="{size} {variant} {elem_classes.join(' ')}"
107
+ style:flex-grow={scale}
108
+ style:width={scale === 0 ? "fit-content" : null}
109
+ style:min-width={typeof min_width === "number" ? `calc(min(${min_width}px, 100%))` : null}
110
+ id={elem_id}
111
+ {disabled}
112
+ bind:this={button_element}
113
+ on:mouseenter={help ? handle_show_tooltip : null}
114
+ on:mouseleave={help ? () => show_tooltip = false : null}
115
+ on:focusin={help ? handle_show_tooltip : null}
116
+ on:focusout={help ? () => show_tooltip = false : null}
117
+ >
118
+ {#if icon}
119
+ <Image
120
+ class={`button-icon ${value ? "right-padded" : ""}`}
121
+ src={icon.url}
122
+ alt={`${value} icon`}
123
+ />
124
+ {/if}
125
+ <span class="button-content">
126
+ {#if value}
127
+ {value}
128
+ {:else}
129
+ <slot />
130
+ {/if}
131
+ </span>
132
+ {#if show_tooltip && help}
133
+ <span class="tooltip-text" bind:this={tooltip_element} use:portal>
134
+ {help}
135
+ </span>
136
+ {/if}
137
+ </button>
138
+ {/if}
139
+
140
+ <style>
141
+ button,
142
+ a {
143
+ display: inline-flex;
144
+ justify-content: center;
145
+ align-items: center;
146
+ transition: var(--button-transition);
147
+ padding: var(--size-0-5) var(--size-2);
148
+ text-align: center;
149
+ position: relative;
150
+ }
151
+
152
+ button:hover {
153
+ transform: var(--button-transform-hover);
154
+ }
155
+
156
+ button:active,
157
+ a:active {
158
+ transform: var(--button-transform-active);
159
+ }
160
+
161
+ button[disabled],
162
+ a.disabled {
163
+ opacity: 0.5;
164
+ filter: grayscale(30%);
165
+ cursor: not-allowed;
166
+ transform: none;
167
+ }
168
+
169
+ .hidden {
170
+ display: none;
171
+ }
172
+
173
+ .primary {
174
+ border: var(--button-border-width) solid var(--button-primary-border-color);
175
+ background: var(--button-primary-background-fill);
176
+ color: var(--button-primary-text-color);
177
+ box-shadow: var(--button-primary-shadow);
178
+ }
179
+ .primary:hover,
180
+ .primary[disabled] {
181
+ background: var(--button-primary-background-fill-hover);
182
+ color: var(--button-primary-text-color-hover);
183
+ }
184
+
185
+ .primary:hover {
186
+ border-color: var(--button-primary-border-color-hover);
187
+ box-shadow: var(--button-primary-shadow-hover);
188
+ }
189
+ .primary:active {
190
+ box-shadow: var(--button-primary-shadow-active);
191
+ }
192
+
193
+ .primary[disabled] {
194
+ border-color: var(--button-primary-border-color);
195
+ }
196
+
197
+ .secondary {
198
+ border: var(--button-border-width) solid var(--button-secondary-border-color);
199
+ background: var(--button-secondary-background-fill);
200
+ color: var(--button-secondary-text-color);
201
+ box-shadow: var(--button-secondary-shadow);
202
+ }
203
+
204
+ .secondary:hover,
205
+ .secondary[disabled] {
206
+ background: var(--button-secondary-background-fill-hover);
207
+ color: var(--button-secondary-text-color-hover);
208
+ }
209
+
210
+ .secondary:hover {
211
+ border-color: var(--button-secondary-border-color-hover);
212
+ box-shadow: var(--button-secondary-shadow-hover);
213
+ }
214
+ .secondary:active {
215
+ box-shadow: var(--button-secondary-shadow-active);
216
+ }
217
+
218
+ .secondary[disabled] {
219
+ border-color: var(--button-secondary-border-color);
220
+ }
221
+
222
+ .stop {
223
+ background: var(--button-cancel-background-fill);
224
+ color: var(--button-cancel-text-color);
225
+ border: var(--button-border-width) solid var(--button-cancel-border-color);
226
+ box-shadow: var(--button-cancel-shadow);
227
+ }
228
+
229
+ .stop:hover,
230
+ .stop[disabled] {
231
+ background: var(--button-cancel-background-fill-hover);
232
+ }
233
+
234
+ .stop:hover {
235
+ border-color: var(--button-cancel-border-color-hover);
236
+ box-shadow: var(--button-cancel-shadow-hover);
237
+ }
238
+ .stop:active {
239
+ box-shadow: var(--button-cancel-shadow-active);
240
+ }
241
+
242
+ .stop[disabled] {
243
+ border-color: var(--button-cancel-border-color);
244
+ }
245
+
246
+ .sm {
247
+ border-radius: var(--button-small-radius);
248
+ padding: var(--button-small-padding);
249
+ font-weight: var(--button-small-text-weight);
250
+ font-size: var(--button-small-text-size);
251
+ }
252
+
253
+ .md {
254
+ border-radius: var(--button-medium-radius);
255
+ padding: var(--button-medium-padding);
256
+ font-weight: var(--button-medium-text-weight);
257
+ font-size: var(--button-medium-text-size);
258
+ }
259
+
260
+ .lg {
261
+ border-radius: var(--button-large-radius);
262
+ padding: var(--button-large-padding);
263
+ font-weight: var(--button-large-text-weight);
264
+ font-size: var(--button-large-text-size);
265
+ }
266
+
267
+ :global(.button-icon) {
268
+ width: var(--text-xl);
269
+ height: var(--text-xl);
270
+ }
271
+ :global(.button-icon.right-padded) {
272
+ margin-right: var(--spacing-md);
273
+ }
274
+
275
+ .huggingface {
276
+ background: rgb(20, 28, 46);
277
+ color: white;
278
+ }
279
+
280
+ .huggingface:hover {
281
+ background: rgb(40, 48, 66);
282
+ color: white;
283
+ }
284
+
285
+ .button-content {
286
+ display: inline;
287
+ visibility: visible;
288
+ color: inherit;
289
+ }
290
+
291
+ .tooltip-text {
292
+ width: auto;
293
+ max-width: 500px;
294
+ background-color: var(--body-text-color);
295
+ color: var(--background-fill-primary);
296
+ text-align: center;
297
+ border-radius: var(--radius-md);
298
+ padding: var(--spacing-md);
299
+ z-index: var(--layer-top);
300
+ opacity: 1;
301
+ transition: opacity 0.2s;
302
+ pointer-events: none;
303
+ font-weight: var(--body-text-weight);
304
+ font-size: var(--body-text-size);
305
+ }
306
+ </style>
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_buttonplus"
11
+ version = "0.0.1"
12
+ description = "Advanced Button Component for Gradio UI"
13
+ readme = "README.md"
14
+ license = "apache-2.0"
15
+ requires-python = ">=3.10"
16
+ authors = [{ name = "Eliseu Silva", email = "[email protected]" }]
17
+ keywords = ["gradio-custom-component", "gradio-template-Button"]
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_buttonplus/templates", "*.pyi", "/\\backend\\gradio_buttonplus\\templates"]
49
+
50
+ [tool.hatch.build.targets.wheel]
51
+ packages = ["/backend/gradio_buttonplus"]