Spaces:
Running
Running
Upload folder using huggingface_hub
Browse files- .gitignore +14 -0
- README.md +308 -12
- __init__.py +0 -0
- app.py +16 -0
- css.css +157 -0
- requirements.txt +1 -0
- space.py +138 -0
- src/.gitignore +14 -0
- src/.vscode/launch.json +29 -0
- src/README.md +308 -0
- src/backend/gradio_buttonplus/__init__.py +4 -0
- src/backend/gradio_buttonplus/buttonplus.py +111 -0
- src/backend/gradio_buttonplus/templates/component/index.js +0 -0
- src/backend/gradio_buttonplus/templates/component/style.css +1 -0
- src/demo/__init__.py +0 -0
- src/demo/app.py +16 -0
- src/demo/css.css +157 -0
- src/demo/requirements.txt +1 -0
- src/demo/space.py +138 -0
- src/frontend/Index.svelte +42 -0
- src/frontend/gradio.config.js +9 -0
- src/frontend/main.ts +2 -0
- src/frontend/package-lock.json +0 -0
- src/frontend/package.json +36 -0
- src/frontend/shared/Button.svelte +306 -0
- src/frontend/tsconfig.json +14 -0
- src/pyproject.toml +51 -0
.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 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
---
|
| 11 |
-
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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"]
|