appkit-ui 0.7.3__tar.gz → 0.7.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- appkit_ui-0.7.5/PKG-INFO +530 -0
- appkit_ui-0.7.5/README.md +509 -0
- appkit_ui-0.7.5/pyproject.toml +45 -0
- appkit_ui-0.7.3/PKG-INFO +0 -8
- appkit_ui-0.7.3/README.md +0 -0
- appkit_ui-0.7.3/pyproject.toml +0 -24
- {appkit_ui-0.7.3 → appkit_ui-0.7.5}/.gitignore +0 -0
- {appkit_ui-0.7.3 → appkit_ui-0.7.5}/src/appkit_ui/__init__.py +0 -0
- {appkit_ui-0.7.3 → appkit_ui-0.7.5}/src/appkit_ui/components/__init__.py +0 -0
- {appkit_ui-0.7.3 → appkit_ui-0.7.5}/src/appkit_ui/components/collabsible.py +0 -0
- {appkit_ui-0.7.3 → appkit_ui-0.7.5}/src/appkit_ui/components/dialogs.py +0 -0
- {appkit_ui-0.7.3 → appkit_ui-0.7.5}/src/appkit_ui/components/editor.py +0 -0
- {appkit_ui-0.7.3 → appkit_ui-0.7.5}/src/appkit_ui/components/form_inputs.py +0 -0
- {appkit_ui-0.7.3 → appkit_ui-0.7.5}/src/appkit_ui/components/header.py +0 -0
- {appkit_ui-0.7.3 → appkit_ui-0.7.5}/src/appkit_ui/global_states.py +0 -0
- {appkit_ui-0.7.3 → appkit_ui-0.7.5}/src/appkit_ui/styles.py +0 -0
appkit_ui-0.7.5/PKG-INFO
ADDED
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: appkit-ui
|
|
3
|
+
Version: 0.7.5
|
|
4
|
+
Summary: Add your description here
|
|
5
|
+
Project-URL: Homepage, https://github.com/jenreh/appkit
|
|
6
|
+
Project-URL: Documentation, https://github.com/jenreh/appkit/tree/main/docs
|
|
7
|
+
Project-URL: Repository, https://github.com/jenreh/appkit
|
|
8
|
+
Project-URL: Issues, https://github.com/jenreh/appkit/issues
|
|
9
|
+
Author: Jens Rehpöhler
|
|
10
|
+
Keywords: components,mantine,reflex,ui,web
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
16
|
+
Classifier: Topic :: Software Development :: User Interfaces
|
|
17
|
+
Requires-Python: >=3.13
|
|
18
|
+
Requires-Dist: appkit-mantine
|
|
19
|
+
Requires-Dist: reflex>=0.8.20
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# appkit-ui
|
|
23
|
+
|
|
24
|
+
[](https://www.python.org/downloads/)
|
|
25
|
+
[](https://opensource.org/licenses/MIT)
|
|
26
|
+
|
|
27
|
+
**Shared UI components and layouts for AppKit applications.**
|
|
28
|
+
|
|
29
|
+
appkit-ui provides a collection of reusable UI components, layouts, and styling utilities designed to create consistent, professional interfaces across AppKit applications. It includes responsive page templates, navigation components, form helpers, and common UI patterns built on Reflex and Mantine.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## ✨ Features
|
|
34
|
+
|
|
35
|
+
- **Layout Components** - Responsive page templates and navigation headers
|
|
36
|
+
- **Form Helpers** - Pre-built form inputs with validation and styling
|
|
37
|
+
- **Dialog Components** - Confirmation dialogs and modal interfaces
|
|
38
|
+
- **Rich Text Editor** - Full-featured WYSIWYG editor based on SunEditor
|
|
39
|
+
- **Collapsible Sections** - Expandable/collapsible content areas
|
|
40
|
+
- **Global State Management** - Shared state for loading indicators and UI feedback
|
|
41
|
+
- **Styling Utilities** - Consistent themes, colors, and CSS utilities
|
|
42
|
+
- **Responsive Design** - Mobile-first components that work across all screen sizes
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 🚀 Installation
|
|
47
|
+
|
|
48
|
+
### As Part of AppKit Workspace
|
|
49
|
+
|
|
50
|
+
If you're using the full AppKit workspace:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
git clone https://github.com/jenreh/appkit.git
|
|
54
|
+
cd appkit
|
|
55
|
+
uv sync
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Standalone Installation
|
|
59
|
+
|
|
60
|
+
Install from PyPI:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install appkit-ui
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Or with uv:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
uv add appkit-ui
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Dependencies
|
|
73
|
+
|
|
74
|
+
- `appkit-commons` (shared utilities)
|
|
75
|
+
- `reflex>=0.8.12` (UI framework)
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 🏁 Quick Start
|
|
80
|
+
|
|
81
|
+
### Basic Layout
|
|
82
|
+
|
|
83
|
+
Create a responsive page layout with header:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
import reflex as rx
|
|
87
|
+
import appkit_ui as ui
|
|
88
|
+
|
|
89
|
+
def my_page():
|
|
90
|
+
return rx.vstack(
|
|
91
|
+
ui.header("My Application"),
|
|
92
|
+
rx.container(
|
|
93
|
+
rx.text("Welcome to my app!"),
|
|
94
|
+
max_width="800px",
|
|
95
|
+
padding="2em"
|
|
96
|
+
),
|
|
97
|
+
spacing="0",
|
|
98
|
+
min_height="100vh"
|
|
99
|
+
)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Using Form Components
|
|
103
|
+
|
|
104
|
+
Add styled form inputs:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from appkit_ui.components.form_inputs import inline_form_field
|
|
108
|
+
|
|
109
|
+
def contact_form():
|
|
110
|
+
return rx.form(
|
|
111
|
+
inline_form_field(
|
|
112
|
+
icon="user",
|
|
113
|
+
label="Name",
|
|
114
|
+
placeholder="Enter your name",
|
|
115
|
+
required=True
|
|
116
|
+
),
|
|
117
|
+
inline_form_field(
|
|
118
|
+
icon="mail",
|
|
119
|
+
label="Email",
|
|
120
|
+
type="email",
|
|
121
|
+
placeholder="Enter your email"
|
|
122
|
+
),
|
|
123
|
+
rx.button("Submit", type="submit")
|
|
124
|
+
)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Rich Text Editor
|
|
128
|
+
|
|
129
|
+
Add a WYSIWYG editor to your page:
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
from appkit_ui.components import editor
|
|
133
|
+
|
|
134
|
+
def blog_editor():
|
|
135
|
+
return editor(
|
|
136
|
+
placeholder="Write your blog post...",
|
|
137
|
+
button_list=editor.EditorButtonList.COMPLEX,
|
|
138
|
+
height="400px"
|
|
139
|
+
)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## 📖 Usage
|
|
145
|
+
|
|
146
|
+
### Layout Components
|
|
147
|
+
|
|
148
|
+
#### Header
|
|
149
|
+
|
|
150
|
+
Create a fixed header with responsive design:
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
from appkit_ui.components.header import header
|
|
154
|
+
|
|
155
|
+
# Basic header
|
|
156
|
+
header("Application Title")
|
|
157
|
+
|
|
158
|
+
# Indented header (for sidebar layouts)
|
|
159
|
+
header("Dashboard", indent=True)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
#### Styles and Themes
|
|
163
|
+
|
|
164
|
+
Apply consistent styling:
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
import appkit_ui.styles as styles
|
|
168
|
+
|
|
169
|
+
def styled_page():
|
|
170
|
+
return rx.box(
|
|
171
|
+
rx.text("Content"),
|
|
172
|
+
**styles.splash_container # Gradient background
|
|
173
|
+
)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Form Components
|
|
177
|
+
|
|
178
|
+
#### Inline Form Fields
|
|
179
|
+
|
|
180
|
+
Create labeled form inputs with icons:
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
from appkit_ui.components.form_inputs import inline_form_field
|
|
184
|
+
|
|
185
|
+
# Text input
|
|
186
|
+
inline_form_field(
|
|
187
|
+
icon="user",
|
|
188
|
+
label="Username",
|
|
189
|
+
placeholder="Enter username",
|
|
190
|
+
min_length=3,
|
|
191
|
+
max_length=50
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
# Email input
|
|
195
|
+
inline_form_field(
|
|
196
|
+
icon="mail",
|
|
197
|
+
label="Email",
|
|
198
|
+
type="email",
|
|
199
|
+
required=True
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
# Password input
|
|
203
|
+
inline_form_field(
|
|
204
|
+
icon="lock",
|
|
205
|
+
label="Password",
|
|
206
|
+
type="password",
|
|
207
|
+
hint="Must be at least 8 characters"
|
|
208
|
+
)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
#### Hidden Fields
|
|
212
|
+
|
|
213
|
+
Add hidden form data:
|
|
214
|
+
|
|
215
|
+
```python
|
|
216
|
+
from appkit_ui.components.form_inputs import hidden_field
|
|
217
|
+
|
|
218
|
+
hidden_field(name="csrf_token", value="abc123")
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Dialog Components
|
|
222
|
+
|
|
223
|
+
#### Delete Confirmation Dialog
|
|
224
|
+
|
|
225
|
+
Create a confirmation dialog for destructive actions:
|
|
226
|
+
|
|
227
|
+
```python
|
|
228
|
+
from appkit_ui.components.dialogs import delete_dialog
|
|
229
|
+
|
|
230
|
+
def user_management():
|
|
231
|
+
return rx.vstack(
|
|
232
|
+
delete_dialog(
|
|
233
|
+
title="Delete User",
|
|
234
|
+
content="user@example.com",
|
|
235
|
+
on_click=lambda: print("User deleted")
|
|
236
|
+
),
|
|
237
|
+
# Other user management UI
|
|
238
|
+
)
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Editor Component
|
|
242
|
+
|
|
243
|
+
#### Rich Text Editor
|
|
244
|
+
|
|
245
|
+
Configure the editor with different button sets:
|
|
246
|
+
|
|
247
|
+
```python
|
|
248
|
+
from appkit_ui.components import editor
|
|
249
|
+
|
|
250
|
+
# Basic editor
|
|
251
|
+
editor(placeholder="Enter text...")
|
|
252
|
+
|
|
253
|
+
# Full-featured editor
|
|
254
|
+
editor(
|
|
255
|
+
button_list=editor.EditorButtonList.COMPLEX,
|
|
256
|
+
height="500px",
|
|
257
|
+
placeholder="Write your content...",
|
|
258
|
+
on_change=lambda value: print(f"Content: {value}")
|
|
259
|
+
)
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
#### Editor Options
|
|
263
|
+
|
|
264
|
+
Customize editor behavior:
|
|
265
|
+
|
|
266
|
+
```python
|
|
267
|
+
from appkit_ui.components.editor import EditorOptions
|
|
268
|
+
|
|
269
|
+
custom_options = EditorOptions(
|
|
270
|
+
height="400px",
|
|
271
|
+
placeholder="Custom placeholder...",
|
|
272
|
+
button_list=[
|
|
273
|
+
["bold", "italic"],
|
|
274
|
+
["link", "image"],
|
|
275
|
+
["undo", "redo"]
|
|
276
|
+
]
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
editor(options=custom_options)
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Collapsible Components
|
|
283
|
+
|
|
284
|
+
#### Collapsible Sections
|
|
285
|
+
|
|
286
|
+
Create expandable content areas:
|
|
287
|
+
|
|
288
|
+
```python
|
|
289
|
+
from appkit_ui.components import collabsible
|
|
290
|
+
|
|
291
|
+
def settings_page():
|
|
292
|
+
return rx.vstack(
|
|
293
|
+
collabsible(
|
|
294
|
+
rx.text("Account settings content..."),
|
|
295
|
+
title="Account Settings",
|
|
296
|
+
info_text="Configure your account",
|
|
297
|
+
expanded=True
|
|
298
|
+
),
|
|
299
|
+
collabsible(
|
|
300
|
+
rx.text("Notification settings content..."),
|
|
301
|
+
title="Notifications",
|
|
302
|
+
info_text="Manage email preferences"
|
|
303
|
+
)
|
|
304
|
+
)
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Global State
|
|
308
|
+
|
|
309
|
+
#### Loading State
|
|
310
|
+
|
|
311
|
+
Manage loading indicators across your app:
|
|
312
|
+
|
|
313
|
+
```python
|
|
314
|
+
from appkit_ui.global_states import LoadingState
|
|
315
|
+
|
|
316
|
+
class MyState(LoadingState):
|
|
317
|
+
def load_data(self):
|
|
318
|
+
self.set_is_loading(True)
|
|
319
|
+
# Simulate async operation
|
|
320
|
+
await asyncio.sleep(2)
|
|
321
|
+
self.set_is_loading(False)
|
|
322
|
+
|
|
323
|
+
def loading_component():
|
|
324
|
+
return rx.cond(
|
|
325
|
+
LoadingState.is_loading,
|
|
326
|
+
rx.text(LoadingState.is_loading_message),
|
|
327
|
+
rx.text("Content loaded")
|
|
328
|
+
)
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
## 🔧 Configuration
|
|
334
|
+
|
|
335
|
+
### Editor Configuration
|
|
336
|
+
|
|
337
|
+
Customize the rich text editor:
|
|
338
|
+
|
|
339
|
+
```python
|
|
340
|
+
from appkit_ui.components.editor import EditorOptions
|
|
341
|
+
|
|
342
|
+
options = EditorOptions(
|
|
343
|
+
mode="classic", # or "inline", "balloon"
|
|
344
|
+
height="300px",
|
|
345
|
+
min_height="200px",
|
|
346
|
+
max_height="600px",
|
|
347
|
+
placeholder="Start writing...",
|
|
348
|
+
button_list=editor.EditorButtonList.FORMATTING,
|
|
349
|
+
font_size: ["8px", "10px", "12px", "14px", "16px", "18px", "20px"],
|
|
350
|
+
color_list: ["#ff0000", "#00ff00", "#0000ff"],
|
|
351
|
+
# Additional SunEditor options...
|
|
352
|
+
)
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### Styling Customization
|
|
356
|
+
|
|
357
|
+
Override default styles:
|
|
358
|
+
|
|
359
|
+
```python
|
|
360
|
+
import appkit_ui.styles as styles
|
|
361
|
+
|
|
362
|
+
# Custom dialog styles
|
|
363
|
+
custom_dialog_styles = {
|
|
364
|
+
**styles.dialog_styles,
|
|
365
|
+
"border_radius": "15px",
|
|
366
|
+
"box_shadow": "0 10px 25px rgba(0,0,0,0.1)"
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## 📋 API Reference
|
|
373
|
+
|
|
374
|
+
### Component API
|
|
375
|
+
|
|
376
|
+
#### Layout API
|
|
377
|
+
|
|
378
|
+
- `header()` - Fixed page header with responsive design
|
|
379
|
+
|
|
380
|
+
#### Form API
|
|
381
|
+
|
|
382
|
+
- `inline_form_field()` - Labeled form input with icon and validation
|
|
383
|
+
- `hidden_field()` - Hidden form input field
|
|
384
|
+
|
|
385
|
+
#### Dialog API
|
|
386
|
+
|
|
387
|
+
- `delete_dialog()` - Confirmation dialog for delete operations
|
|
388
|
+
|
|
389
|
+
#### Editor API
|
|
390
|
+
|
|
391
|
+
- `editor()` - Rich text WYSIWYG editor
|
|
392
|
+
- `EditorButtonList` - Predefined button configurations (BASIC, FORMATTING, COMPLEX)
|
|
393
|
+
- `EditorOptions` - Editor configuration options
|
|
394
|
+
|
|
395
|
+
#### Utility API
|
|
396
|
+
|
|
397
|
+
- `collabsible()` - Expandable/collapsible content sections
|
|
398
|
+
|
|
399
|
+
#### State API
|
|
400
|
+
|
|
401
|
+
- `LoadingState` - Global loading state with message support
|
|
402
|
+
|
|
403
|
+
#### Style API
|
|
404
|
+
|
|
405
|
+
- `splash_container` - Gradient background styles
|
|
406
|
+
- `dialog_styles` - Dialog component styling
|
|
407
|
+
- `label_styles` - Form label styling
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
## 🔒 Security
|
|
412
|
+
|
|
413
|
+
> [!IMPORTANT]
|
|
414
|
+
> Form components include basic client-side validation, but always implement server-side validation for security.
|
|
415
|
+
|
|
416
|
+
- Input sanitization for editor content
|
|
417
|
+
- CSRF protection support through hidden fields
|
|
418
|
+
- Secure handling of form data
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## 🤝 Integration Examples
|
|
423
|
+
|
|
424
|
+
### With AppKit Components
|
|
425
|
+
|
|
426
|
+
Combine with other AppKit packages:
|
|
427
|
+
|
|
428
|
+
```python
|
|
429
|
+
import reflex as rx
|
|
430
|
+
import appkit_ui as ui
|
|
431
|
+
import appkit_mantine as mn
|
|
432
|
+
import appkit_user as user
|
|
433
|
+
|
|
434
|
+
def dashboard():
|
|
435
|
+
return rx.vstack(
|
|
436
|
+
ui.header("Dashboard", indent=True),
|
|
437
|
+
rx.hstack(
|
|
438
|
+
# Sidebar navigation
|
|
439
|
+
mn.sidebar(),
|
|
440
|
+
# Main content
|
|
441
|
+
rx.container(
|
|
442
|
+
ui.collabsible(
|
|
443
|
+
mn.data_table(), # From appkit-mantine
|
|
444
|
+
title="User Data",
|
|
445
|
+
expanded=True
|
|
446
|
+
),
|
|
447
|
+
max_width="1200px"
|
|
448
|
+
),
|
|
449
|
+
flex_grow="1"
|
|
450
|
+
),
|
|
451
|
+
min_height="100vh"
|
|
452
|
+
)
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
### Custom Form with Validation
|
|
456
|
+
|
|
457
|
+
Create forms with integrated validation:
|
|
458
|
+
|
|
459
|
+
```python
|
|
460
|
+
from appkit_ui.components.form_inputs import inline_form_field
|
|
461
|
+
|
|
462
|
+
def registration_form():
|
|
463
|
+
return rx.form(
|
|
464
|
+
inline_form_field(
|
|
465
|
+
icon="user",
|
|
466
|
+
label="Username",
|
|
467
|
+
name="username",
|
|
468
|
+
min_length=3,
|
|
469
|
+
max_length=20,
|
|
470
|
+
pattern=r"^[a-zA-Z0-9_]+$",
|
|
471
|
+
required=True
|
|
472
|
+
),
|
|
473
|
+
inline_form_field(
|
|
474
|
+
icon="mail",
|
|
475
|
+
label="Email",
|
|
476
|
+
name="email",
|
|
477
|
+
type="email",
|
|
478
|
+
required=True
|
|
479
|
+
),
|
|
480
|
+
inline_form_field(
|
|
481
|
+
icon="lock",
|
|
482
|
+
label="Password",
|
|
483
|
+
name="password",
|
|
484
|
+
type="password",
|
|
485
|
+
min_length=8,
|
|
486
|
+
hint="At least 8 characters",
|
|
487
|
+
required=True
|
|
488
|
+
),
|
|
489
|
+
rx.button("Register", type="submit")
|
|
490
|
+
)
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
### Editor Integration
|
|
494
|
+
|
|
495
|
+
Use the editor in content management:
|
|
496
|
+
|
|
497
|
+
```python
|
|
498
|
+
from appkit_ui.components import editor
|
|
499
|
+
|
|
500
|
+
class BlogState(rx.State):
|
|
501
|
+
content: str = ""
|
|
502
|
+
|
|
503
|
+
def save_post(self):
|
|
504
|
+
# Save self.content to database
|
|
505
|
+
pass
|
|
506
|
+
|
|
507
|
+
def blog_editor_page():
|
|
508
|
+
return rx.vstack(
|
|
509
|
+
ui.header("New Blog Post"),
|
|
510
|
+
editor(
|
|
511
|
+
value=BlogState.content,
|
|
512
|
+
on_change=BlogState.set_content,
|
|
513
|
+
button_list=editor.EditorButtonList.COMPLEX,
|
|
514
|
+
height="600px",
|
|
515
|
+
placeholder="Write your blog post..."
|
|
516
|
+
),
|
|
517
|
+
rx.button("Save", on_click=BlogState.save_post),
|
|
518
|
+
spacing="4",
|
|
519
|
+
padding="2em"
|
|
520
|
+
)
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
---
|
|
524
|
+
|
|
525
|
+
## 📚 Related Components
|
|
526
|
+
|
|
527
|
+
- **[appkit-mantine](./../appkit-mantine)** - Mantine UI components used throughout appkit-ui
|
|
528
|
+
- **[appkit-user](./../appkit-user)** - User authentication components
|
|
529
|
+
- **[appkit-commons](./../appkit-commons)** - Shared utilities and configuration
|
|
530
|
+
- **[appkit-assistant](./../appkit-assistant)** - AI assistant with UI components
|
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
# appkit-ui
|
|
2
|
+
|
|
3
|
+
[](https://www.python.org/downloads/)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
**Shared UI components and layouts for AppKit applications.**
|
|
7
|
+
|
|
8
|
+
appkit-ui provides a collection of reusable UI components, layouts, and styling utilities designed to create consistent, professional interfaces across AppKit applications. It includes responsive page templates, navigation components, form helpers, and common UI patterns built on Reflex and Mantine.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## ✨ Features
|
|
13
|
+
|
|
14
|
+
- **Layout Components** - Responsive page templates and navigation headers
|
|
15
|
+
- **Form Helpers** - Pre-built form inputs with validation and styling
|
|
16
|
+
- **Dialog Components** - Confirmation dialogs and modal interfaces
|
|
17
|
+
- **Rich Text Editor** - Full-featured WYSIWYG editor based on SunEditor
|
|
18
|
+
- **Collapsible Sections** - Expandable/collapsible content areas
|
|
19
|
+
- **Global State Management** - Shared state for loading indicators and UI feedback
|
|
20
|
+
- **Styling Utilities** - Consistent themes, colors, and CSS utilities
|
|
21
|
+
- **Responsive Design** - Mobile-first components that work across all screen sizes
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 🚀 Installation
|
|
26
|
+
|
|
27
|
+
### As Part of AppKit Workspace
|
|
28
|
+
|
|
29
|
+
If you're using the full AppKit workspace:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
git clone https://github.com/jenreh/appkit.git
|
|
33
|
+
cd appkit
|
|
34
|
+
uv sync
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Standalone Installation
|
|
38
|
+
|
|
39
|
+
Install from PyPI:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install appkit-ui
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Or with uv:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
uv add appkit-ui
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Dependencies
|
|
52
|
+
|
|
53
|
+
- `appkit-commons` (shared utilities)
|
|
54
|
+
- `reflex>=0.8.12` (UI framework)
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 🏁 Quick Start
|
|
59
|
+
|
|
60
|
+
### Basic Layout
|
|
61
|
+
|
|
62
|
+
Create a responsive page layout with header:
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
import reflex as rx
|
|
66
|
+
import appkit_ui as ui
|
|
67
|
+
|
|
68
|
+
def my_page():
|
|
69
|
+
return rx.vstack(
|
|
70
|
+
ui.header("My Application"),
|
|
71
|
+
rx.container(
|
|
72
|
+
rx.text("Welcome to my app!"),
|
|
73
|
+
max_width="800px",
|
|
74
|
+
padding="2em"
|
|
75
|
+
),
|
|
76
|
+
spacing="0",
|
|
77
|
+
min_height="100vh"
|
|
78
|
+
)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Using Form Components
|
|
82
|
+
|
|
83
|
+
Add styled form inputs:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
from appkit_ui.components.form_inputs import inline_form_field
|
|
87
|
+
|
|
88
|
+
def contact_form():
|
|
89
|
+
return rx.form(
|
|
90
|
+
inline_form_field(
|
|
91
|
+
icon="user",
|
|
92
|
+
label="Name",
|
|
93
|
+
placeholder="Enter your name",
|
|
94
|
+
required=True
|
|
95
|
+
),
|
|
96
|
+
inline_form_field(
|
|
97
|
+
icon="mail",
|
|
98
|
+
label="Email",
|
|
99
|
+
type="email",
|
|
100
|
+
placeholder="Enter your email"
|
|
101
|
+
),
|
|
102
|
+
rx.button("Submit", type="submit")
|
|
103
|
+
)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Rich Text Editor
|
|
107
|
+
|
|
108
|
+
Add a WYSIWYG editor to your page:
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
from appkit_ui.components import editor
|
|
112
|
+
|
|
113
|
+
def blog_editor():
|
|
114
|
+
return editor(
|
|
115
|
+
placeholder="Write your blog post...",
|
|
116
|
+
button_list=editor.EditorButtonList.COMPLEX,
|
|
117
|
+
height="400px"
|
|
118
|
+
)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## 📖 Usage
|
|
124
|
+
|
|
125
|
+
### Layout Components
|
|
126
|
+
|
|
127
|
+
#### Header
|
|
128
|
+
|
|
129
|
+
Create a fixed header with responsive design:
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
from appkit_ui.components.header import header
|
|
133
|
+
|
|
134
|
+
# Basic header
|
|
135
|
+
header("Application Title")
|
|
136
|
+
|
|
137
|
+
# Indented header (for sidebar layouts)
|
|
138
|
+
header("Dashboard", indent=True)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
#### Styles and Themes
|
|
142
|
+
|
|
143
|
+
Apply consistent styling:
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
import appkit_ui.styles as styles
|
|
147
|
+
|
|
148
|
+
def styled_page():
|
|
149
|
+
return rx.box(
|
|
150
|
+
rx.text("Content"),
|
|
151
|
+
**styles.splash_container # Gradient background
|
|
152
|
+
)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Form Components
|
|
156
|
+
|
|
157
|
+
#### Inline Form Fields
|
|
158
|
+
|
|
159
|
+
Create labeled form inputs with icons:
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
from appkit_ui.components.form_inputs import inline_form_field
|
|
163
|
+
|
|
164
|
+
# Text input
|
|
165
|
+
inline_form_field(
|
|
166
|
+
icon="user",
|
|
167
|
+
label="Username",
|
|
168
|
+
placeholder="Enter username",
|
|
169
|
+
min_length=3,
|
|
170
|
+
max_length=50
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
# Email input
|
|
174
|
+
inline_form_field(
|
|
175
|
+
icon="mail",
|
|
176
|
+
label="Email",
|
|
177
|
+
type="email",
|
|
178
|
+
required=True
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
# Password input
|
|
182
|
+
inline_form_field(
|
|
183
|
+
icon="lock",
|
|
184
|
+
label="Password",
|
|
185
|
+
type="password",
|
|
186
|
+
hint="Must be at least 8 characters"
|
|
187
|
+
)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
#### Hidden Fields
|
|
191
|
+
|
|
192
|
+
Add hidden form data:
|
|
193
|
+
|
|
194
|
+
```python
|
|
195
|
+
from appkit_ui.components.form_inputs import hidden_field
|
|
196
|
+
|
|
197
|
+
hidden_field(name="csrf_token", value="abc123")
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Dialog Components
|
|
201
|
+
|
|
202
|
+
#### Delete Confirmation Dialog
|
|
203
|
+
|
|
204
|
+
Create a confirmation dialog for destructive actions:
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
from appkit_ui.components.dialogs import delete_dialog
|
|
208
|
+
|
|
209
|
+
def user_management():
|
|
210
|
+
return rx.vstack(
|
|
211
|
+
delete_dialog(
|
|
212
|
+
title="Delete User",
|
|
213
|
+
content="user@example.com",
|
|
214
|
+
on_click=lambda: print("User deleted")
|
|
215
|
+
),
|
|
216
|
+
# Other user management UI
|
|
217
|
+
)
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Editor Component
|
|
221
|
+
|
|
222
|
+
#### Rich Text Editor
|
|
223
|
+
|
|
224
|
+
Configure the editor with different button sets:
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
from appkit_ui.components import editor
|
|
228
|
+
|
|
229
|
+
# Basic editor
|
|
230
|
+
editor(placeholder="Enter text...")
|
|
231
|
+
|
|
232
|
+
# Full-featured editor
|
|
233
|
+
editor(
|
|
234
|
+
button_list=editor.EditorButtonList.COMPLEX,
|
|
235
|
+
height="500px",
|
|
236
|
+
placeholder="Write your content...",
|
|
237
|
+
on_change=lambda value: print(f"Content: {value}")
|
|
238
|
+
)
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
#### Editor Options
|
|
242
|
+
|
|
243
|
+
Customize editor behavior:
|
|
244
|
+
|
|
245
|
+
```python
|
|
246
|
+
from appkit_ui.components.editor import EditorOptions
|
|
247
|
+
|
|
248
|
+
custom_options = EditorOptions(
|
|
249
|
+
height="400px",
|
|
250
|
+
placeholder="Custom placeholder...",
|
|
251
|
+
button_list=[
|
|
252
|
+
["bold", "italic"],
|
|
253
|
+
["link", "image"],
|
|
254
|
+
["undo", "redo"]
|
|
255
|
+
]
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
editor(options=custom_options)
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Collapsible Components
|
|
262
|
+
|
|
263
|
+
#### Collapsible Sections
|
|
264
|
+
|
|
265
|
+
Create expandable content areas:
|
|
266
|
+
|
|
267
|
+
```python
|
|
268
|
+
from appkit_ui.components import collabsible
|
|
269
|
+
|
|
270
|
+
def settings_page():
|
|
271
|
+
return rx.vstack(
|
|
272
|
+
collabsible(
|
|
273
|
+
rx.text("Account settings content..."),
|
|
274
|
+
title="Account Settings",
|
|
275
|
+
info_text="Configure your account",
|
|
276
|
+
expanded=True
|
|
277
|
+
),
|
|
278
|
+
collabsible(
|
|
279
|
+
rx.text("Notification settings content..."),
|
|
280
|
+
title="Notifications",
|
|
281
|
+
info_text="Manage email preferences"
|
|
282
|
+
)
|
|
283
|
+
)
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Global State
|
|
287
|
+
|
|
288
|
+
#### Loading State
|
|
289
|
+
|
|
290
|
+
Manage loading indicators across your app:
|
|
291
|
+
|
|
292
|
+
```python
|
|
293
|
+
from appkit_ui.global_states import LoadingState
|
|
294
|
+
|
|
295
|
+
class MyState(LoadingState):
|
|
296
|
+
def load_data(self):
|
|
297
|
+
self.set_is_loading(True)
|
|
298
|
+
# Simulate async operation
|
|
299
|
+
await asyncio.sleep(2)
|
|
300
|
+
self.set_is_loading(False)
|
|
301
|
+
|
|
302
|
+
def loading_component():
|
|
303
|
+
return rx.cond(
|
|
304
|
+
LoadingState.is_loading,
|
|
305
|
+
rx.text(LoadingState.is_loading_message),
|
|
306
|
+
rx.text("Content loaded")
|
|
307
|
+
)
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## 🔧 Configuration
|
|
313
|
+
|
|
314
|
+
### Editor Configuration
|
|
315
|
+
|
|
316
|
+
Customize the rich text editor:
|
|
317
|
+
|
|
318
|
+
```python
|
|
319
|
+
from appkit_ui.components.editor import EditorOptions
|
|
320
|
+
|
|
321
|
+
options = EditorOptions(
|
|
322
|
+
mode="classic", # or "inline", "balloon"
|
|
323
|
+
height="300px",
|
|
324
|
+
min_height="200px",
|
|
325
|
+
max_height="600px",
|
|
326
|
+
placeholder="Start writing...",
|
|
327
|
+
button_list=editor.EditorButtonList.FORMATTING,
|
|
328
|
+
font_size: ["8px", "10px", "12px", "14px", "16px", "18px", "20px"],
|
|
329
|
+
color_list: ["#ff0000", "#00ff00", "#0000ff"],
|
|
330
|
+
# Additional SunEditor options...
|
|
331
|
+
)
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### Styling Customization
|
|
335
|
+
|
|
336
|
+
Override default styles:
|
|
337
|
+
|
|
338
|
+
```python
|
|
339
|
+
import appkit_ui.styles as styles
|
|
340
|
+
|
|
341
|
+
# Custom dialog styles
|
|
342
|
+
custom_dialog_styles = {
|
|
343
|
+
**styles.dialog_styles,
|
|
344
|
+
"border_radius": "15px",
|
|
345
|
+
"box_shadow": "0 10px 25px rgba(0,0,0,0.1)"
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## 📋 API Reference
|
|
352
|
+
|
|
353
|
+
### Component API
|
|
354
|
+
|
|
355
|
+
#### Layout API
|
|
356
|
+
|
|
357
|
+
- `header()` - Fixed page header with responsive design
|
|
358
|
+
|
|
359
|
+
#### Form API
|
|
360
|
+
|
|
361
|
+
- `inline_form_field()` - Labeled form input with icon and validation
|
|
362
|
+
- `hidden_field()` - Hidden form input field
|
|
363
|
+
|
|
364
|
+
#### Dialog API
|
|
365
|
+
|
|
366
|
+
- `delete_dialog()` - Confirmation dialog for delete operations
|
|
367
|
+
|
|
368
|
+
#### Editor API
|
|
369
|
+
|
|
370
|
+
- `editor()` - Rich text WYSIWYG editor
|
|
371
|
+
- `EditorButtonList` - Predefined button configurations (BASIC, FORMATTING, COMPLEX)
|
|
372
|
+
- `EditorOptions` - Editor configuration options
|
|
373
|
+
|
|
374
|
+
#### Utility API
|
|
375
|
+
|
|
376
|
+
- `collabsible()` - Expandable/collapsible content sections
|
|
377
|
+
|
|
378
|
+
#### State API
|
|
379
|
+
|
|
380
|
+
- `LoadingState` - Global loading state with message support
|
|
381
|
+
|
|
382
|
+
#### Style API
|
|
383
|
+
|
|
384
|
+
- `splash_container` - Gradient background styles
|
|
385
|
+
- `dialog_styles` - Dialog component styling
|
|
386
|
+
- `label_styles` - Form label styling
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
## 🔒 Security
|
|
391
|
+
|
|
392
|
+
> [!IMPORTANT]
|
|
393
|
+
> Form components include basic client-side validation, but always implement server-side validation for security.
|
|
394
|
+
|
|
395
|
+
- Input sanitization for editor content
|
|
396
|
+
- CSRF protection support through hidden fields
|
|
397
|
+
- Secure handling of form data
|
|
398
|
+
|
|
399
|
+
---
|
|
400
|
+
|
|
401
|
+
## 🤝 Integration Examples
|
|
402
|
+
|
|
403
|
+
### With AppKit Components
|
|
404
|
+
|
|
405
|
+
Combine with other AppKit packages:
|
|
406
|
+
|
|
407
|
+
```python
|
|
408
|
+
import reflex as rx
|
|
409
|
+
import appkit_ui as ui
|
|
410
|
+
import appkit_mantine as mn
|
|
411
|
+
import appkit_user as user
|
|
412
|
+
|
|
413
|
+
def dashboard():
|
|
414
|
+
return rx.vstack(
|
|
415
|
+
ui.header("Dashboard", indent=True),
|
|
416
|
+
rx.hstack(
|
|
417
|
+
# Sidebar navigation
|
|
418
|
+
mn.sidebar(),
|
|
419
|
+
# Main content
|
|
420
|
+
rx.container(
|
|
421
|
+
ui.collabsible(
|
|
422
|
+
mn.data_table(), # From appkit-mantine
|
|
423
|
+
title="User Data",
|
|
424
|
+
expanded=True
|
|
425
|
+
),
|
|
426
|
+
max_width="1200px"
|
|
427
|
+
),
|
|
428
|
+
flex_grow="1"
|
|
429
|
+
),
|
|
430
|
+
min_height="100vh"
|
|
431
|
+
)
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### Custom Form with Validation
|
|
435
|
+
|
|
436
|
+
Create forms with integrated validation:
|
|
437
|
+
|
|
438
|
+
```python
|
|
439
|
+
from appkit_ui.components.form_inputs import inline_form_field
|
|
440
|
+
|
|
441
|
+
def registration_form():
|
|
442
|
+
return rx.form(
|
|
443
|
+
inline_form_field(
|
|
444
|
+
icon="user",
|
|
445
|
+
label="Username",
|
|
446
|
+
name="username",
|
|
447
|
+
min_length=3,
|
|
448
|
+
max_length=20,
|
|
449
|
+
pattern=r"^[a-zA-Z0-9_]+$",
|
|
450
|
+
required=True
|
|
451
|
+
),
|
|
452
|
+
inline_form_field(
|
|
453
|
+
icon="mail",
|
|
454
|
+
label="Email",
|
|
455
|
+
name="email",
|
|
456
|
+
type="email",
|
|
457
|
+
required=True
|
|
458
|
+
),
|
|
459
|
+
inline_form_field(
|
|
460
|
+
icon="lock",
|
|
461
|
+
label="Password",
|
|
462
|
+
name="password",
|
|
463
|
+
type="password",
|
|
464
|
+
min_length=8,
|
|
465
|
+
hint="At least 8 characters",
|
|
466
|
+
required=True
|
|
467
|
+
),
|
|
468
|
+
rx.button("Register", type="submit")
|
|
469
|
+
)
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Editor Integration
|
|
473
|
+
|
|
474
|
+
Use the editor in content management:
|
|
475
|
+
|
|
476
|
+
```python
|
|
477
|
+
from appkit_ui.components import editor
|
|
478
|
+
|
|
479
|
+
class BlogState(rx.State):
|
|
480
|
+
content: str = ""
|
|
481
|
+
|
|
482
|
+
def save_post(self):
|
|
483
|
+
# Save self.content to database
|
|
484
|
+
pass
|
|
485
|
+
|
|
486
|
+
def blog_editor_page():
|
|
487
|
+
return rx.vstack(
|
|
488
|
+
ui.header("New Blog Post"),
|
|
489
|
+
editor(
|
|
490
|
+
value=BlogState.content,
|
|
491
|
+
on_change=BlogState.set_content,
|
|
492
|
+
button_list=editor.EditorButtonList.COMPLEX,
|
|
493
|
+
height="600px",
|
|
494
|
+
placeholder="Write your blog post..."
|
|
495
|
+
),
|
|
496
|
+
rx.button("Save", on_click=BlogState.save_post),
|
|
497
|
+
spacing="4",
|
|
498
|
+
padding="2em"
|
|
499
|
+
)
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
---
|
|
503
|
+
|
|
504
|
+
## 📚 Related Components
|
|
505
|
+
|
|
506
|
+
- **[appkit-mantine](./../appkit-mantine)** - Mantine UI components used throughout appkit-ui
|
|
507
|
+
- **[appkit-user](./../appkit-user)** - User authentication components
|
|
508
|
+
- **[appkit-commons](./../appkit-commons)** - Shared utilities and configuration
|
|
509
|
+
- **[appkit-assistant](./../appkit-assistant)** - AI assistant with UI components
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "appkit-ui"
|
|
3
|
+
version = "0.7.5"
|
|
4
|
+
description = "Add your description here"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [{ name = "Jens Rehpöhler" }]
|
|
7
|
+
requires-python = ">=3.13"
|
|
8
|
+
keywords = [
|
|
9
|
+
"reflex",
|
|
10
|
+
"mantine",
|
|
11
|
+
"ui",
|
|
12
|
+
"components",
|
|
13
|
+
"web",
|
|
14
|
+
]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.13",
|
|
20
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
21
|
+
"Topic :: Software Development :: User Interfaces",
|
|
22
|
+
]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"appkit-mantine",
|
|
25
|
+
"reflex>=0.8.20",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://github.com/jenreh/appkit"
|
|
30
|
+
Documentation = "https://github.com/jenreh/appkit/tree/main/docs"
|
|
31
|
+
Repository = "https://github.com/jenreh/appkit"
|
|
32
|
+
Issues = "https://github.com/jenreh/appkit/issues"
|
|
33
|
+
|
|
34
|
+
[tool.setuptools.packages.find]
|
|
35
|
+
where = ["src"]
|
|
36
|
+
|
|
37
|
+
[tool.uv.sources]
|
|
38
|
+
appkit-commons = { workspace = true }
|
|
39
|
+
|
|
40
|
+
[tool.hatch.build.targets.wheel]
|
|
41
|
+
packages = ["src/appkit_ui"]
|
|
42
|
+
|
|
43
|
+
[build-system]
|
|
44
|
+
requires = ["hatchling"]
|
|
45
|
+
build-backend = "hatchling.build"
|
appkit_ui-0.7.3/PKG-INFO
DELETED
appkit_ui-0.7.3/README.md
DELETED
|
File without changes
|
appkit_ui-0.7.3/pyproject.toml
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
[project]
|
|
2
|
-
name = "appkit-ui"
|
|
3
|
-
version = "0.7.3"
|
|
4
|
-
description = "Add your description here"
|
|
5
|
-
readme = "README.md"
|
|
6
|
-
authors = [{ name = "Jens Rehpöhler" }]
|
|
7
|
-
requires-python = ">=3.13"
|
|
8
|
-
dependencies = [
|
|
9
|
-
"appkit-commons",
|
|
10
|
-
"reflex>=0.8.12",
|
|
11
|
-
]
|
|
12
|
-
|
|
13
|
-
[tool.setuptools.packages.find]
|
|
14
|
-
where = ["src"]
|
|
15
|
-
|
|
16
|
-
[tool.uv.sources]
|
|
17
|
-
appkit-commons = { workspace = true }
|
|
18
|
-
|
|
19
|
-
[tool.hatch.build.targets.wheel]
|
|
20
|
-
packages = ["src/appkit_ui"]
|
|
21
|
-
|
|
22
|
-
[build-system]
|
|
23
|
-
requires = ["hatchling"]
|
|
24
|
-
build-backend = "hatchling.build"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|