Skip to content

Commit 32397f6

Browse files
author
deeleeramone
committed
more docs pages updates
1 parent b3aff37 commit 32397f6

5 files changed

Lines changed: 603 additions & 243 deletions

File tree

pywry/docs/docs/guides/index.md

Lines changed: 0 additions & 24 deletions
This file was deleted.

pywry/docs/docs/guides/modals.md

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
# Modals
2+
3+
Modals are popup dialogs that overlay the content area. They reuse the same component system as toolbars — any `ToolbarItem` works inside a modal — but add overlay behavior, sizing, keyboard handling, and open/close control.
4+
5+
## Creating a Modal
6+
7+
A `Modal` takes a list of toolbar items and is passed alongside your content:
8+
9+
```python
10+
from pywry import PyWry, Modal, Button, TextInput, Select, Option
11+
12+
app = PyWry()
13+
14+
modal = Modal(
15+
component_id="settings-modal",
16+
title="Settings",
17+
items=[
18+
Select(
19+
label="Language",
20+
event="settings:language",
21+
options=[Option(label="Python"), Option(label="JavaScript"), Option(label="Rust")],
22+
selected="Python",
23+
),
24+
TextInput(label="API Key", event="settings:api-key", placeholder="Enter key..."),
25+
Button(label="Save", event="settings:save", variant="primary"),
26+
Button(label="Cancel", event="settings:cancel", variant="ghost"),
27+
],
28+
)
29+
30+
app.show(
31+
"<h1>Dashboard</h1>",
32+
modals=[modal],
33+
callbacks={
34+
"settings:save": on_save,
35+
"settings:cancel": lambda d, e, l: app.emit("modal:close:settings-modal", {}, l),
36+
},
37+
)
38+
```
39+
40+
The modal is hidden by default. It renders as an overlay div with a backdrop, and its HTML is injected after the main content.
41+
42+
## Modal Properties
43+
44+
| Property | Type | Default | Description |
45+
|:---|:---|:---|:---|
46+
| `component_id` | `str` | auto | Unique identifier — used in open/close commands |
47+
| `title` | `str` | `"Modal"` | Header text |
48+
| `items` | `list[ToolbarItem]` | `[]` | Components inside the modal body |
49+
| `size` | `"sm"` \| `"md"` \| `"lg"` \| `"xl"` \| `"full"` | `"md"` | Preset width |
50+
| `width` | `str \| None` | `None` | Custom width (overrides `size`) |
51+
| `max_height` | `str` | `"80vh"` | Maximum height before scrolling |
52+
| `overlay_opacity` | `float` | `0.5` | Backdrop darkness (0.0–1.0) |
53+
| `close_on_escape` | `bool` | `True` | ESC key closes the modal |
54+
| `close_on_overlay_click` | `bool` | `True` | Clicking outside closes the modal |
55+
| `reset_on_close` | `bool` | `True` | Reset all inputs when closed |
56+
| `on_close_event` | `str \| None` | `None` | Event emitted when modal closes |
57+
| `open_on_load` | `bool` | `False` | Open immediately on page load |
58+
| `style` | `str` | `""` | Inline CSS on the modal container |
59+
| `script` | `str \| Path \| None` | `None` | JavaScript to inject with the modal |
60+
| `class_name` | `str` | `""` | Extra CSS class on the modal container |
61+
62+
### Size Presets
63+
64+
| Size | Width |
65+
|:---|:---|
66+
| `sm` | Small — compact dialogs, confirmations |
67+
| `md` | Medium — forms, settings panels |
68+
| `lg` | Large — data views, multi-column layouts |
69+
| `xl` | Extra large — dashboards, wide content |
70+
| `full` | Full viewport width |
71+
72+
## Opening and Closing
73+
74+
### From Python
75+
76+
```python
77+
# Open
78+
handle.emit("modal:open:settings-modal", {})
79+
80+
# Close
81+
handle.emit("modal:close:settings-modal", {})
82+
83+
# Toggle
84+
handle.emit("modal:toggle:settings-modal", {})
85+
```
86+
87+
The event name format is `modal:{action}:{component_id}`. These events are intercepted client-side by the modal handler — they don't round-trip to the server.
88+
89+
### From JavaScript
90+
91+
```javascript
92+
// Direct API
93+
pywry.modal.open("settings-modal");
94+
pywry.modal.close("settings-modal");
95+
pywry.modal.toggle("settings-modal");
96+
97+
// Or via events (equivalent)
98+
window.pywry.emit("modal:open:settings-modal", {});
99+
```
100+
101+
### From a Toolbar Button
102+
103+
A common pattern is a toolbar button that opens a modal:
104+
105+
```python
106+
toolbar = Toolbar(
107+
position="header",
108+
items=[Button(label="⚙ Settings", event="modal:open:settings-modal")],
109+
)
110+
111+
modal = Modal(component_id="settings-modal", title="Settings", items=[...])
112+
113+
app.show(content, toolbars=[toolbar], modals=[modal])
114+
```
115+
116+
Because the event matches `modal:open:*`, it's handled directly by the frontend — no Python callback needed.
117+
118+
## Close Events
119+
120+
When `on_close_event` is set, PyWry emits that event every time the modal closes (via ESC, overlay click, or programmatic close):
121+
122+
```python
123+
modal = Modal(
124+
component_id="confirm-modal",
125+
title="Confirm Action",
126+
on_close_event="app:confirm-dismissed",
127+
items=[
128+
Button(label="Confirm", event="app:confirm-yes", variant="primary"),
129+
Button(label="Cancel", event="modal:close:confirm-modal", variant="ghost"),
130+
],
131+
)
132+
133+
def on_dismissed(data, event_type, label):
134+
print("User dismissed the confirmation dialog")
135+
136+
app.show(content, modals=[modal], callbacks={"app:confirm-dismissed": on_dismissed})
137+
```
138+
139+
## Reset on Close
140+
141+
When `reset_on_close=True` (the default), all input components inside the modal are reset to their initial values when the modal is closed. This prevents stale form state when reopening.
142+
143+
Set `reset_on_close=False` if you want inputs to preserve their values between open/close cycles:
144+
145+
```python
146+
modal = Modal(
147+
component_id="filter-modal",
148+
title="Filters",
149+
reset_on_close=False, # Keep selections when reopened
150+
items=[
151+
Select(event="filter:status", options=["Active", "Archived", "All"], selected="Active"),
152+
Toggle(label="Include drafts", event="filter:drafts", value=False),
153+
],
154+
)
155+
```
156+
157+
## Open on Load
158+
159+
Set `open_on_load=True` for modals that should appear immediately — useful for welcome screens, terms acceptance, or first-run configuration:
160+
161+
```python
162+
modal = Modal(
163+
component_id="welcome",
164+
title="Welcome to the Dashboard",
165+
open_on_load=True,
166+
close_on_escape=False,
167+
close_on_overlay_click=False,
168+
items=[
169+
Button(label="Get Started", event="modal:close:welcome", variant="primary"),
170+
],
171+
)
172+
```
173+
174+
## Custom Scripts
175+
176+
The `script` parameter lets you inject JavaScript that runs when the modal is loaded. This is useful for custom form validation, dynamic behavior, or third-party integrations:
177+
178+
```python
179+
modal = Modal(
180+
component_id="my-modal",
181+
title="Custom Form",
182+
items=[
183+
TextInput(component_id="email", event="form:email", placeholder="Email"),
184+
Button(label="Submit", event="form:submit", variant="primary"),
185+
],
186+
script="""
187+
document.getElementById('email').addEventListener('input', function(e) {
188+
const btn = document.querySelector('[data-event="form:submit"]');
189+
btn.disabled = !e.target.value.includes('@');
190+
});
191+
""",
192+
)
193+
```
194+
195+
## Multiple Modals
196+
197+
You can define multiple modals and open them independently:
198+
199+
```python
200+
app.show(
201+
content,
202+
modals=[
203+
Modal(component_id="settings", title="Settings", items=[...]),
204+
Modal(component_id="export", title="Export Data", items=[...]),
205+
Modal(component_id="help", title="Help", size="lg", items=[...]),
206+
],
207+
toolbars=[
208+
Toolbar(position="header", items=[
209+
Button(label="", event="modal:open:settings", variant="icon"),
210+
Button(label="", event="modal:open:export", variant="icon"),
211+
Button(label="?", event="modal:open:help", variant="icon"),
212+
]),
213+
],
214+
)
215+
```
216+
217+
Only one modal can be visible at a time — opening a new one implicitly closes any currently open modal.
218+
219+
## Styling
220+
221+
Target modals with CSS using the component ID or the `.pywry-modal` class:
222+
223+
```css
224+
/* All modals */
225+
.pywry-modal {
226+
border-radius: 12px;
227+
}
228+
229+
/* Specific modal */
230+
#settings-modal .pywry-modal-body {
231+
padding: 24px;
232+
}
233+
234+
/* Modal overlay */
235+
.pywry-modal-overlay {
236+
backdrop-filter: blur(4px);
237+
}
238+
```
239+
240+
## Next Steps
241+
242+
- **[Toolbar System](toolbars.md)** — Components available inside modals
243+
- **[Toasts & Alerts](toasts.md)** — Non-blocking notifications
244+
- **[Theming & CSS](theming.md)** — Customize modal appearance
245+
- **[Components](../components/index.md)** — Full component API reference

0 commit comments

Comments
 (0)