Skip to content

Commit b699573

Browse files
committed
update mcp to use fastmcp and make docs have component preview
1 parent 87d541a commit b699573

82 files changed

Lines changed: 7840 additions & 2105 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

pywry/AGENTS.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -969,6 +969,24 @@ app.on("toolbar:state-response", on_state)
969969
# Set single component value
970970
app.emit("toolbar:set-value", {"componentId": "my-select", "value": "option2"}, label)
971971

972+
# Set value with attributes (label, disabled, etc.)
973+
app.emit("toolbar:set-value", {
974+
"componentId": "submit-btn",
975+
"label": "Saving...",
976+
"disabled": True
977+
}, label)
978+
979+
# Update dropdown options dynamically
980+
app.emit("toolbar:set-value", {
981+
"componentId": "type-select",
982+
"value": "bar",
983+
"options": [{"label": "Bar", "value": "bar"}, {"label": "Line", "value": "line"}]
984+
}, label)
985+
986+
# Or use widget method (recommended)
987+
widget.set_toolbar_value("submit-btn", label="Saving...", disabled=True)
988+
widget.set_toolbar_value("type-select", value="bar", options=[...])
989+
972990
# Set multiple values
973991
app.emit("toolbar:set-values", {"values": {"select-1": "A", "toggle-1": True}}, label)
974992
```

pywry/README.md

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2289,7 +2289,7 @@ These events are emitted automatically when users interact with toolbar chrome:
22892289
|-------|-----------|---------|-------------|
22902290
| `toolbar:state-response` | JS → Python | `{ toolbars, components, timestamp, context? }` | Response to state request |
22912291
| `toolbar:request-state` | Python → JS | `{ toolbarId?, componentId?, context? }` | Request current state |
2292-
| `toolbar:set-value` | Python → JS | `{ componentId, value, toolbarId? }` | Set single component value |
2292+
| `toolbar:set-value` | Python → JS | `{ componentId, value?, label?, disabled?, ...attrs }` | Set component value and/or attributes |
22932293
| `toolbar:set-values` | Python → JS | `{ values: { id: value, ... }, toolbarId? }` | Set multiple component values |
22942294

22952295
#### Marquee Events
@@ -4244,6 +4244,45 @@ handle = app.show(
42444244
)
42454245
```
42464246

4247+
**Setting Component Attributes** (labels, disabled state, etc.):
4248+
4249+
```python
4250+
def on_submit(data, event_type, label):
4251+
"""Show loading state then re-enable."""
4252+
# Update button label and disable
4253+
handle.set_toolbar_value("submit-btn", label="Saving...", disabled=True)
4254+
4255+
# ... do work ...
4256+
4257+
# Re-enable with original label
4258+
handle.set_toolbar_value("submit-btn", label="Submit", disabled=False)
4259+
4260+
def on_category_change(data, event_type, label):
4261+
"""Update dropdown options dynamically."""
4262+
category = data.get("value")
4263+
if category == "fruits":
4264+
options = [{"label": "Apple", "value": "apple"}, {"label": "Banana", "value": "banana"}]
4265+
else:
4266+
options = [{"label": "Carrot", "value": "carrot"}, {"label": "Broccoli", "value": "broccoli"}]
4267+
4268+
handle.set_toolbar_value("item-select", value=options[0]["value"], options=options)
4269+
```
4270+
4271+
Supported attributes for `set_toolbar_value()`:
4272+
4273+
| Attribute | Description | Example |
4274+
|-----------|-------------|---------|
4275+
| `value` | Component value | `value="dark"` |
4276+
| `label`/`text` | Text content | `label="Loading..."` |
4277+
| `disabled` | Enable/disable | `disabled=True` |
4278+
| `variant` | Button style | `variant="danger"` |
4279+
| `tooltip`/`description` | Hover text | `tooltip="Click to save"` |
4280+
| `options` | Dropdown options | `options=[{"label": "A", "value": "a"}]` |
4281+
| `style` | Inline CSS | `style={"color": "red"}` |
4282+
| `className` | CSS classes | `className={"add": ["active"]}` |
4283+
| `placeholder` | Input hint | `placeholder="Search..."` |
4284+
| `min`/`max`/`step` | Input constraints | `min=0, max=100` |
4285+
42474286
</details>
42484287

42494288
<details>

pywry/docs/docs/components/button.md

Lines changed: 60 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,30 @@ Buttons support typical styles via the `variant` parameter:
2020
["primary", "secondary", "neutral", "outline", "ghost", "danger", "warning", "icon"]
2121
```
2222

23-
<img width="500" height="40" alt="Button Variants - Dark" src="https://github.com/user-attachments/assets/ded61da3-e06a-40fd-b07a-55a7671bae4b" />
24-
<img width="500" height="40" alt="Button Variants - Light" src="https://github.com/user-attachments/assets/d746890b-ffc7-486d-85c5-a34b29960c98" />
23+
<div class="component-preview center">
24+
<button class="pywry-btn pywry-toolbar-button" data-event="demo:primary">Primary</button>
25+
<button class="pywry-btn pywry-toolbar-button pywry-btn-secondary" data-event="demo:secondary">Secondary</button>
26+
<button class="pywry-btn pywry-toolbar-button pywry-btn-neutral" data-event="demo:neutral">Neutral</button>
27+
<button class="pywry-btn pywry-toolbar-button pywry-btn-ghost" data-event="demo:ghost">Ghost</button>
28+
<button class="pywry-btn pywry-toolbar-button pywry-btn-outline" data-event="demo:outline">Outline</button>
29+
<button class="pywry-btn pywry-toolbar-button pywry-btn-danger" data-event="demo:danger">Danger</button>
30+
<button class="pywry-btn pywry-toolbar-button pywry-btn-warning" data-event="demo:warning">Warning</button>
31+
<button class="pywry-btn pywry-toolbar-button pywry-btn-icon"
32+
style="font-size: 32px;"
33+
data-event="demo:icon">⚙\ufe0e</button>
34+
</div>
2535

2636
## Sizes
2737

2838
Button sizes can be defined by presets, or can be overriden by supplying the `style` initialization parameter.
2939

30-
<img width="300" height="60" alt="Button Sizes" src="https://github.com/user-attachments/assets/e2f8ce04-c38e-4655-8ba5-5ff846094f60" />
40+
<div class="component-preview center">
41+
<button class="pywry-btn pywry-toolbar-button pywry-btn-neutral pywry-btn-xs" data-event="demo:xs">XS</button>
42+
<button class="pywry-btn pywry-toolbar-button pywry-btn-neutral pywry-btn-sm" data-event="demo:sm">SM</button>
43+
<button class="pywry-btn pywry-toolbar-button pywry-btn-neutral" data-event="demo:default">Default</button>
44+
<button class="pywry-btn pywry-toolbar-button pywry-btn-neutral pywry-btn-lg" data-event="demo:lg">LG</button>
45+
<button class="pywry-btn pywry-toolbar-button pywry-btn-neutral pywry-btn-xl" data-event="demo:xl">XL</button>
46+
</div>
3147

3248
## Icons
3349

@@ -70,6 +86,16 @@ data : dict
7086
Additional data payload to include with the event.
7187
```
7288

89+
## Events
90+
91+
Emits the `event` name with payload:
92+
93+
```json
94+
{"componentId": "button-abc123"}
95+
```
96+
97+
Any additional key/value pairs from the `data` parameter are merged into the payload.
98+
7399
## Handling Clicks
74100

75101
Connect button clicks to Python callbacks:
@@ -79,7 +105,7 @@ from pywry import PyWry, Toolbar, Button
79105

80106
def on_save(data, event_type, label):
81107
"""Handle save button click."""
82-
# data contains {"clicked": True} for buttons
108+
# data contains {"componentId": "..."} plus any custom data keys
83109
# Perform your save operation here
84110
app.emit("pywry:alert", {"message": "Saved!", "type": "success"}, label)
85111

@@ -96,7 +122,9 @@ app.show(
96122
### Confirmation Dialog
97123

98124
```python
99-
from pywry import Button
125+
from pywry import PyWry, Toolbar, Button
126+
127+
app = PyWry()
100128

101129
def show_confirm(data, event_type, label):
102130
"""Show a confirmation dialog before destructive action."""
@@ -112,39 +140,49 @@ def on_delete_confirmed(data, event_type, label):
112140
# Perform delete and show success
113141
app.emit("pywry:alert", {"message": "Deleted!", "type": "success"}, label)
114142

115-
delete_btn = Button(
116-
label="🗑️ Delete",
117-
event="action:delete",
118-
variant="danger",
143+
app.show(
144+
"<h1>My Document</h1><p>Click delete to remove.</p>",
145+
toolbars=[
146+
Toolbar(position="top", items=[
147+
Button(label="🗑️ Delete", event="action:delete", variant="danger")
148+
])
149+
],
150+
callbacks={
151+
"action:delete": show_confirm,
152+
"delete:confirmed": on_delete_confirmed,
153+
},
119154
)
120-
121-
# Register callbacks
122-
callbacks = {
123-
"action:delete": show_confirm,
124-
"delete:confirmed": on_delete_confirmed,
125-
}
126155
```
127156

128157
### Toggle State Buttons
129158

130159
```python
131-
from pywry import Button
160+
from pywry import PyWry, Toolbar, Button
132161

162+
app = PyWry()
133163
current_state = {"playing": False}
134164

135165
def on_toggle(data, event_type, label):
136166
is_playing = not current_state["playing"]
137167
current_state["playing"] = is_playing
138168
# Update button label dynamically
139-
widget.emit("toolbar:set-value", {
169+
app.emit("toolbar:set-value", {
140170
"componentId": "play-btn",
141171
"label": "⏸️ Pause" if is_playing else "▶️ Play"
142-
})
172+
}, label)
143173

144-
play_btn = Button(
145-
component_id="play-btn", # Required for dynamic updates
146-
label="▶️ Play",
147-
event="media:toggle",
174+
app.show(
175+
"<h1>Media Player</h1>",
176+
toolbars=[
177+
Toolbar(position="top", items=[
178+
Button(
179+
component_id="play-btn", # Required for dynamic updates
180+
label="▶️ Play",
181+
event="media:toggle",
182+
)
183+
])
184+
],
185+
callbacks={"media:toggle": on_toggle},
148186
)
149187
```
150188

pywry/docs/docs/components/checkbox.md

Lines changed: 96 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,20 @@
22

33
A checkable box for boolean selections, typically used in forms.
44

5+
<div class="component-preview">
6+
<label class="pywry-checkbox">
7+
<input type="checkbox" class="pywry-checkbox-input" checked>
8+
<span class="pywry-checkbox-box"></span>
9+
<span class="pywry-checkbox-label">Checked</span>
10+
</label>
11+
<span class="preview-sep"></span>
12+
<label class="pywry-checkbox">
13+
<input type="checkbox" class="pywry-checkbox-input">
14+
<span class="pywry-checkbox-box"></span>
15+
<span class="pywry-checkbox-label">Unchecked</span>
16+
</label>
17+
</div>
18+
519
## Basic Usage
620

721
```python
@@ -19,32 +33,39 @@ agree = Checkbox(
1933
### Form Agreement
2034

2135
```python
22-
from pywry import Toolbar, Checkbox, Button
36+
from pywry import PyWry, Toolbar, Checkbox, Button
37+
38+
app = PyWry()
2339

2440
def on_agree_change(data, event_type, label):
2541
agreed = data["value"]
26-
2742
# Enable/disable submit button based on agreement
28-
widget.emit("toolbar:set-value", {
43+
app.emit("toolbar:set-value", {
2944
"componentId": "submit-btn",
3045
"disabled": not agreed
31-
})
32-
33-
form_toolbar = Toolbar(
34-
position="bottom",
35-
items=[
36-
Checkbox(
37-
label="I agree to the terms and conditions",
38-
event="form:agree",
39-
),
40-
Button(
41-
component_id="submit-btn",
42-
label="Submit",
43-
event="form:submit",
44-
variant="primary",
45-
disabled=True, # Initially disabled
46-
),
46+
}, label)
47+
48+
def on_submit(data, event_type, label):
49+
app.emit("pywry:alert", {"message": "Form submitted!", "type": "success"}, label)
50+
51+
app.show(
52+
"<h1>Sign Up</h1><p>Please agree to continue.</p>",
53+
toolbars=[
54+
Toolbar(position="bottom", items=[
55+
Checkbox(label="I agree to the terms and conditions", event="form:agree"),
56+
Button(
57+
component_id="submit-btn",
58+
label="Submit",
59+
event="form:submit",
60+
variant="primary",
61+
disabled=True, # Initially disabled
62+
),
63+
])
4764
],
65+
callbacks={
66+
"form:agree": on_agree_change,
67+
"form:submit": on_submit,
68+
},
4869
)
4970
```
5071

@@ -67,33 +88,74 @@ features_toolbar = Toolbar(
6788
### Select All Pattern
6889

6990
```python
70-
from pywry import Toolbar, Checkbox
91+
from pywry import PyWry, Toolbar, Checkbox
7192

72-
items = [{"id": 1, "name": "Item A"}, {"id": 2, "name": "Item B"}]
93+
app = PyWry()
94+
items = [{"id": 1, "name": "Item A"}, {"id": 2, "name": "Item B"}, {"id": 3, "name": "Item C"}]
7395

7496
def on_select_all(data, event_type, label):
7597
select_all = data["value"]
76-
7798
# Update all child checkboxes
7899
for item in items:
79-
widget.emit("toolbar:set-value", {
100+
app.emit("toolbar:set-value", {
80101
"componentId": f"item-{item['id']}",
81102
"value": select_all
82-
})
83-
84-
toolbar = Toolbar(
85-
position="top",
86-
items=[
87-
Checkbox(label="Select All", event="items:select_all"),
88-
*[Checkbox(
89-
component_id=f"item-{item['id']}",
90-
label=item['name'],
91-
event=f"item:select:{item['id']}"
92-
) for item in items],
103+
}, label)
104+
105+
def on_item_select(data, event_type, label):
106+
app.emit("pywry:alert", {
107+
"message": f"Item selected: {data.get('value')}",
108+
"type": "info"
109+
}, label)
110+
111+
app.show(
112+
"<h1>Select Items</h1>",
113+
toolbars=[
114+
Toolbar(position="top", items=[
115+
Checkbox(label="Select All", event="items:select_all"),
116+
*[Checkbox(
117+
component_id=f"item-{item['id']}",
118+
label=item['name'],
119+
event="item:select"
120+
) for item in items],
121+
])
93122
],
123+
callbacks={
124+
"items:select_all": on_select_all,
125+
"item:select": on_item_select,
126+
},
94127
)
95128
```
96129

130+
## Attributes
131+
132+
```
133+
component_id : str | None
134+
Unique identifier for state tracking (auto-generated if not provided)
135+
label : str | None
136+
Display label shown next to the checkbox
137+
description : str | None
138+
Tooltip/hover text for accessibility and user guidance
139+
event : str
140+
Event name emitted on interaction (format: namespace:event-name)
141+
style : str | None
142+
Optional inline CSS
143+
disabled : bool
144+
Whether the checkbox is disabled (default: False)
145+
value : bool
146+
Current checked state (default: False)
147+
```
148+
149+
## Events
150+
151+
Emits the `event` name with payload:
152+
153+
```json
154+
{"value": true, "componentId": "checkbox-abc123"}
155+
```
156+
157+
- `value``true` when checked, `false` when unchecked
158+
97159
## Checkbox vs Toggle
98160

99161
| Component | Visual | Use Case |

0 commit comments

Comments
 (0)