### Running PuePy Examples Locally
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/00-using-this-tutorial.md
Clone the PuePy git repository and use a local web server to run the tutorial examples. Changes made to the example files will be reflected live in the browser upon reloading.
```bash
git clone https://github.com/kkinder/puepy
cd puepy
python -m http.server 8000
```
--------------------------------
### Install Puepy Router
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/advanced-routing.md
Install the router by calling `app.install_router`. Choose a `link_mode` to define how URLs are created and parsed.
```Python
from puepy import Application
from puepy.router import Router
app = Application()
app.install_router(Router, link_mode=Router.LINK_MODE_HASH)
```
--------------------------------
### Install PuePy Router with History Mode
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/07-routing.md
Demonstrates how to install the PuePy router using HTML5 history mode instead of hash-based routing. This is an alternative configuration for routing.
```python
app.install_router(Router, link_mode=Router.LINK_MODE_HISTORY)
```
--------------------------------
### Install PuePy Router with Hash Mode
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/07-routing.md
Installs the PuePy router using hash-based navigation. This is the default and recommended mode for most SPAs.
```python
app.install_router(Router, link_mode=Router.LINK_MODE_HASH)
```
--------------------------------
### Full Example: Parsing HTML with BeautifulSoup
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/08-pypi-libraries.md
This is a complete example demonstrating how to use BeautifulSoup to parse HTML and generate a PuePy component. It requires the CPython/Pyodide runtime and the 'beautifulsoup4' package.
```python
# This file is generated from examples/tutorial/08_libraries/libraries.py
# It is not intended to be run directly.
# The actual code is embedded in the documentation.
# For the full example, please refer to the source file.
# Example content:
# from bs4 import BeautifulSoup, Comment
#
# html_doc = """
#
The Dormouse's story
#
The Dormouse's story
#
#
Once upon a time there were three little sisters; and their names were
# Elsie,
# Lacie and
# Tillie;
# and they lived at the bottom of a well.
#
#
...
#
#
#
#
# """
#
# soup = BeautifulSoup(html_doc, 'html.parser')
#
# # Extract title
# title = soup.title.string
#
# # Extract first paragraph
# first_paragraph = soup.find('p', class_='story').get_text()
#
# # Extract all links
# links = [a['href'] for a in soup.find_all('a')]
#
# # Extract comments
# comments = [str(c) for c in soup.find_all(Comment)]
#
# # Construct PuePy component
# puepy_component = f"""
#
#
HTML Parsing Example
#
Title: {title}
#
First Paragraph: {first_paragraph}
#
Links:
#
# {''.join([f'
{link}
' for link in links])}
#
#
Comments:
#
# {''.join([f'
{comment}
' for comment in comments])}
#
#
# """
#
# # In a real PuePy application, you would typically render this component
# # For demonstration purposes, we'll just print it.
# print(puepy_component)
```
--------------------------------
### Python: In-place State Modification Example (Will Not Work)
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/02-hello-name.md
Illustrates incorrect methods for modifying complex state objects like lists and dictionaries in Puepy, which do not trigger re-renders.
```python
# THESE WILL NOT WORK:
self.state["my_list"].append("spam")
self.state["my_dict"]["spam"] = "eggs"
```
--------------------------------
### Shoelace Spinner Loading Indicator
Source: https://github.com/kkinder/puepy/blob/main/docs/cookbook/loading-indicators.md
Integrate a Shoelace web component spinner for a visual loading indicator. This example shows how to set up the necessary links and scripts, and embed the spinner within the target element.
```html
Example
```
--------------------------------
### Create a Basic PuePy Application
Source: https://github.com/kkinder/puepy/blob/main/README.md
This snippet demonstrates the fundamental structure of a PuePy application. It includes setting up the Application, defining a Page with initial state, populating the UI with elements, and handling user interactions like button clicks. Mount the application to a specific DOM element.
```python
from puepy import Page, Application, t
app = Application()
@app.page()
class Hello(Page):
def initial(self):
return dict(name="")
def populate(self):
with t.div(classes=["container", "mx-auto", "p-4"]):
t.h1("Welcome to PyScript", classes=["text-xl", "pb-4"])
if self.state["name"]:
t.p(f"Hello there, {self.state['name']}")
else:
t.p("Why don't you tell me your name?")
t.input(placeholder="Enter your name", bind="name")
t.button("Continue", classes="btn btn-lg", on_click=self.on_button_click)
def on_button_click(self, event):
print("Button clicked") # This logs to console
app.mount("#app")
```
--------------------------------
### Download PuePy Client Runtime
Source: https://github.com/kkinder/puepy/blob/main/docs/installation.md
Use this command to download the PuePy wheel file for client-side integration. Ensure you replace {{project_version}} with the correct version number.
```Bash
curl -O https://download.puepy.dev/puepy-{{project_version}}-py3-none-any.whl
```
--------------------------------
### Load Pyodide Runtime
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/runtimes.md
Use this configuration to load the Pyodide runtime. Ensure your `pyscript.json` configuration is set up correctly.
```html
```
--------------------------------
### PuePy Hello World Python Code
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/01-hello-world.md
This Python script defines a simple PuePy application. It imports necessary components, creates an application instance, defines a page with content, and mounts the application to a specific DOM element.
```python
from puepy import Application, Page, t
```
```python
app = Application()
```
```python
class HelloWorldPage(Page):
def populate(self):
self.add(t.h1(t.text("Hello, World!")))
```
```python
app.mount("#app", HelloWorldPage)
```
--------------------------------
### Python: Hello Name Page with State
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/02-hello-name.md
Defines a Puepy page that initializes state with a 'name' variable, conditionally displays a greeting based on the name, and binds an input field to the 'name' state.
```python
from puepy import Application, Page, t
app = Application()
@app.page()
class HelloNamePage(Page):
def initial(self):
return {"name": ""} # (1)
def populate(self):
if self.state["name"]: # (2)
t.h1(f"Hello, {self.state['name']}!")
else:
t.h1(f"Why don't you tell me your name?")
with t.div(style="margin: 1em"):
t.input(bind="name", placeholder="name", autocomplete="off") # (3)
app.mount("#app")
```
--------------------------------
### Compare HTML Template to Puepy Python Code
Source: https://github.com/kkinder/puepy/blob/main/docs/faq.md
Illustrates how a simple HTML structure with a loop and a button can be represented more concisely in Puepy's Python syntax.
```html
{{ name }}'s grocery shopping list
{% for item in items %}
{{ item }}
{% endfor %}
```
```python
with t.h1():
t(f"{name}'s grocery shopping list")
with t.ul():
for item in items:
t.li(item)
t.button("Buy Items", on_click=self.buy)
```
--------------------------------
### Define Initial Component State
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/reactivity.md
Components define their initial state using the `initial()` method, returning a dictionary of state properties.
```Python
class MyComponent(Component):
def initial(self):
return {
"name": "Monty ... Something?",
"movies": ["Monty Python and the Holy Grail"]
}
```
--------------------------------
### Python: Correct In-place State Modification with Mutate
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/02-hello-name.md
Demonstrates the correct way to modify complex state objects in Puepy using the `with self.state.mutate()` context manager to ensure re-renders.
```python
# This will work
with self.state.mutate("my_list", "my_dict"):
self.state["my_list"].append("spam")
self.state["my_dict"]["spam"] = "eggs"
```
--------------------------------
### HTML Structure for PuePy Application
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/01-hello-world.md
This HTML file sets up the basic structure for a PuePy application. It includes PyScript from a CDN and specifies the configuration file and the main Python script to execute.
```html
```
```html
```
--------------------------------
### Define Page with Route Parameters
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/advanced-routing.md
Pages can accept parameters from the router. Define placeholders in the route path and list them in the `props` attribute of the Page class.
```Python
@app.page("/post///view")
class PostPage(Page):
props = ["author_id", "post_id"]
def populate(self):
t.p(f"This is a post from {self.author_id}->{self.user_id}")
```
--------------------------------
### Mount the PuePy Application
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/07-routing.md
Mounts the PuePy application to the specified DOM element, typically an element with the ID 'app'. This makes the application interactive.
```python
app.mount("#app")
```
--------------------------------
### Define the Default Page with Pet Links
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/07-routing.md
Defines the default page for the root URL. It displays a list of pets, with each pet name linking to its respective detail page using the custom `Link` component and passing the `pet_id` as an argument.
```python
@app.page()
class DefaultPage(Page):
def populate(self):
t.h1("PuePy Routing Demo: Pet Listing")
with t.ul():
for pet_id, pet_details in pets.items():
with t.li():
t.link(pet_details["name"],
href=PetPage,
args={"pet_id": pet_id}) # (5)
```
--------------------------------
### Using Shoelace Dialog and Button Components in PuePy
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/09-using-web-components.md
This Python code demonstrates how to use Shoelace's `sl-dialog` and `sl-button` Web Components within a PuePy page. It shows how to define the components and attach event handlers for opening and closing the dialog.
```Python
@app.page()
class DefaultPage(Page):
def populate(self):
with t.sl_dialog(label="Dialog", classes="dialog-overview", tag="sl-dialog", ref="dialog"): # (1)!
t("Web Components are just delightful.")
t.sl_button("Close", slot="footer", variant="primary", on_click=self.on_close_click) # (2)!
t.sl_button("Open Dialog", tag="sl-button", on_click=self.on_open_click)
```
```Python
def on_open_click(self, event):
self.refs["dialog"].element.show()
def on_close_click(self, event):
self.refs["dialog"].element.hide()
```
--------------------------------
### Use the Card Component with Slots and Events
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/06-components.md
This snippet demonstrates how to use the previously defined `Card` component within a Puepy page. It shows how to pass props, populate named and default slots, and handle custom events emitted by the component.
```python
@app.page()
class ComponentPage(Page):
def initial(self):
return {"message": ""}
def populate(self):
t.h1("Components are useful")
with t.card(type="success",
on_my_custom_event=self.handle_custom_event) as card:
with card.slot("card-header"):
t("Success!")
with card.slot():
t("Your operation worked")
with t.card(type="warning", on_my_custom_event=self.handle_custom_event) as card:
with card.slot("card-header"):
t("Warning!")
with card.slot():
t("Your operation may not work")
with t.card(type="error", on_my_custom_event=self.handle_custom_event) as card:
with card.slot("card-header"):
t("Failure!")
with card.slot():
t("Your operation failed")
if self.state["message"]:
t.p(self.state["message"])
def handle_custom_event(self, event):
self.state["message"] = f"Custom event from card with type {event.detail.get('type')}"
```
--------------------------------
### Consuming Slots Correctly
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/06-components.md
Illustrates the correct way to consume slots by calling `.slot` directly on the component instance, not `t.slot` or `self.slot`.
```py
with t.card() as card:
with card.slot("card-header"): # (1)
t("Success!")
```
--------------------------------
### Redirect to Login Page
Source: https://github.com/kkinder/puepy/blob/main/docs/cookbook/navigation-guards.md
Implement a precheck to redirect users to a different page (e.g., a login page) if they do not meet the required conditions for accessing the current page.
```python
from puepy import exceptions, Page
class LoginPage(Page):
...
class MyPage(Page):
...
def precheck(self):
if not self.application.state["authenticated_user"]:
raise exceptions.Redirect(LoginPage)
```
--------------------------------
### Configure PuePy Runtime in PyScript
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/pyscript-config.md
Use this JSON configuration to set up the PuePy runtime within a PyScript project. It specifies the project name, enables debug mode, includes the PuePy wheel file, and loads the Morphdom JavaScript module.
```JSON
{
"name": "PuePy Tutorial",
"debug": true,
"packages": [
"./puepy-{{project_version}}-py3-none-any.whl"
],
"js_modules": {
"main": {
"https://cdn.jsdelivr.net/npm/morphdom@2.7.4/+esm": "morphdom"
}
}
}
```
--------------------------------
### Configure PyScript to use CPython/Pyodide runtime
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/08-pypi-libraries.md
Specify the CPython/Pyodide runtime for PyScript by setting the script type to 'py'. This enables the use of a wider range of Python packages.
```html
```
--------------------------------
### Configure PyScript for Multiple Files
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/10-full-app.md
Specify additional Python source files and JavaScript modules in the PyScript configuration to make them available to your application. Ensure correct paths and module names for successful integration.
```json
{
"name": "PuePy Tutorial",
"debug": true,
"files": {
"./common.py": "common.py",
"./components.py": "components.py",
"./main.py": "main.py",
"./pages.py": "pages.py"
},
"js_modules": {
"main": {
"https://cdn.jsdelivr.net/npm/chart.js": "chart",
"https://cdn.jsdelivr.net/npm/morphdom@2.7.4/+esm": "morphdom"
}
},
"packages": [
"../../puepy-{{project_version}}-py3-none-any.whl"
]
}
```
--------------------------------
### Loading Shoelace Web Components from CDN
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/09-using-web-components.md
Include these HTML tags in your index.html file to load the Shoelace library and its theme from a CDN. This makes Shoelace components available for use in your application.
```html
```
--------------------------------
### Render Content Based on Application State
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/reactivity.md
Display a personalized greeting using the `authenticated_user` from the application state.
```python
def populate(self):
...
t.h1(f"Hello, you are authenticated as {self.application.state['authenticated_user']}")
```
--------------------------------
### Define a Default Page Component
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/07-routing.md
Shows the basic structure for defining a default page component in PuePy. This page is rendered when no specific route matches or when the URL is the root.
```python
@app.page()
class DefaultPage(Page):
...
```
--------------------------------
### Counter Component Styles
Source: https://github.com/kkinder/puepy/blob/main/examples/tutorial/03_counter/index.html
Basic CSS for styling the counter buttons and display.
```css
body { display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; }
.button-box { display: flex; gap: 10px; }
.button { padding: 10px 20px; font-size: 16px; }
.count { font-size: 16px; padding: 10px 20px; }
.decrement-button { background-color: darkred; color: white; }
.increment-button { background-color: darkgreen; color: white; }
```
--------------------------------
### Watch for Specific State Changes
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/reactivity.md
Define an `on__change` method to execute custom logic when a specific state key's value is updated.
```Python
class MyComponent(Component):
def initial():
return {"spam": "eggs"}
def on_spam_change(self, new_value):
print("New value for spam", new_value)
```
--------------------------------
### Simple HTML Loading Indicator
Source: https://github.com/kkinder/puepy/blob/main/docs/cookbook/loading-indicators.md
Include a simple HTML indicator within the target element. This text will be replaced by PuePy once it loads.
```html
Loading...
```
--------------------------------
### Set Default Component Classes, Attributes, and Role
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/in-depth-components.md
Define `default_classes`, `default_attributes`, and `default_role` to apply consistent styling and behavior to component instances.
```python
class MyInputComponent(Component):
enclosing_tag = "input"
default_classes = ["my-input"]
default_attributes = {"type": "text"}
default_role = "textbox"
```
--------------------------------
### Component Parent/Child Relationships
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/in-depth-components.md
Demonstrates how to access parent and page instances from within a component. The `on_event_handle` method shows accessing `self.parent`.
```python
from puepy import Application, Page, Component, t
app = Application()
@t.component()
class CustomInput(Component):
enclosing_tag = "input"
def on_event_handle(self, event):
print(self.parent)
class MyPage(Page):
def populate(self):
with t.div():
t.custom_input()
```
--------------------------------
### PyScript Configuration for PuePy
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/01-hello-world.md
This JSON file configures PyScript for a PuePy application. It specifies the application name, enables debug mode, and lists necessary JavaScript modules and Python packages, including PuePy itself and its dependency, Morphdom.
```json
{
"name": "PuePy Tutorial",
"debug": true,
"files": {},
"js_modules": {
"main": {
"https://cdn.jsdelivr.net/npm/morphdom@2.7.4/+esm": "morphdom"
}
},
"packages": [
"./puepy-{{project_version}}-py3-none-any.whl"
]
}
```
--------------------------------
### Configure Redraw on App State Changes (Default)
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/reactivity.md
Sets `redraw_on_app_state_changes` to `True`, meaning all changes to application state will trigger a redraw by default.
```python
class Page1(Page):
redraw_on_app_state_changes = True # (1)!
```
--------------------------------
### Fill Slots in Calling Code
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/06-components.md
This snippet demonstrates how to fill defined slots in a component from the calling code using the context manager and the `.slot()` method.
```py
with t.card() as card:
with card.slot("card-header"):
t("Success!")
with card.slot():
t("Your operation worked")
```
--------------------------------
### Loading Indicator HTML
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/10-full-app.md
Displays a loading spinner within the target div while the application is initializing. This provides visual feedback to the user on slower connections.
```html
```
--------------------------------
### Python App Layout Component
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/10-full-app.md
Defines a reusable application layout component with a sidebar, header, and footer. Includes pre-authentication checks and navigation logic.
```Python
class SidebarItem:
def __init__(self, label, icon, route):
self.label = label
self.icon = icon
self.route = route
@t.component()
class AppLayout(Component):
sidebar_items = [
SidebarItem("Dashboard", "emoji-sunglasses", "dashboard_page"),
SidebarItem("Charts", "graph-up", "charts_page"),
SidebarItem("Forms", "input-cursor-text", "forms_page"),
]
def precheck(self):
if not self.application.state["authenticated_user"]:
raise exceptions.Unauthorized()
def populate(self):
with t.sl_drawer(label="Menu", placement="start", classes="drawer-placement-start", ref="drawer"):
self.populate_sidebar()
with t.div(classes="container"):
with t.div(classes="header"):
with t.div():
with t.sl_button(classes="menu-btn", on_click=self.show_drawer):
t.sl_icon(name="list")
t.div("The Dapper App")
self.populate_topright()
with t.div(classes="sidebar", id="sidebar"):
self.populate_sidebar()
with t.div(classes="main"):
self.insert_slot()
with t.div(classes="footer"):
t("Business Time!")
def populate_topright(self):
with t.div(classes="dropdown-hoist"):
with t.sl_dropdown(hoist=""):
t.sl_icon_button(slot="trigger", label="User Settings", name="person-gear")
with t.sl_menu(on_sl_select=self.on_menu_select):
t.sl_menu_item(
"Profile",
t.sl_icon(slot="suffix", name="person-badge"),
value="profile",
)
t.sl_menu_item("Settings", t.sl_icon(slot="suffix", name="gear"), value="settings")
t.sl_divider()
t.sl_menu_item("Logout", t.sl_icon(slot="suffix", name="box-arrow-right"), value="logout")
def on_menu_select(self, event):
if event.detail.item.value == "logout":
self.application.state["authenticated_user"] = ""
def populate_sidebar(self):
for item in self.sidebar_items:
with t.div():
with t.sl_button(
item.label,
variant="text",
classes="sidebar-button",
href=self.page.router.reverse(item.route),
):
if item.icon:
t.sl_icon(name=item.icon, slot="prefix")
def show_drawer(self, event):
self.refs["drawer"].element.show()
```
--------------------------------
### Watch for Any State Change
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/reactivity.md
Implement the `on_state_change` method to be notified of any key-value pair changes in the component's state.
```Python
class MyComponent(Component):
def on_state_change(self, key, value):
print(key, "was set to", value)
```
--------------------------------
### Configure Redraw on Specific App State Changes
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/reactivity.md
Sets `redraw_on_app_state_changes` to a list of keys, triggering a redraw only when those specific keys in the application state change.
```python
class Page3(Page):
redraw_on_app_state_changes = ["authenticated_user"] # (3)!
```
--------------------------------
### Counter Application with Event Handlers
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/03-events.md
This Python code defines a Puepy application with a counter that can be incremented or decremented using buttons. It demonstrates binding click events to methods that modify the page's state.
```python
from puepy import Application, Page, t
app = Application()
@app.page()
class CounterPage(Page):
def initial(self):
return {"current_value": 0}
def populate(self):
with t.div(classes="button-box"):
t.button("-",
classes=["button", "decrement-button"],
on_click=self.on_decrement_click) # (1)
t.span(str(self.state["current_value"]), classes="count")
t.button("+",
classes="button increment-button",
on_click=self.on_increment_click) # (2)
def on_decrement_click(self, event):
self.state["current_value"] -= 1 # (3)
def on_increment_click(self, event):
self.state["current_value"] += 1 # (4)
app.mount("#app")
```
--------------------------------
### Define a Reusable Card Component
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/06-components.md
This snippet shows how to define a custom Puepy component named `Card`. It includes defining properties (`props`), CSS classes, and using slots for dynamic content insertion. The component also triggers a custom event upon button click.
```python
@t.component()
class Card(Component):
props = ["type", "button_text"]
card = CssClass(
margin="1em",
padding="1em",
background_color="#efefef",
border="solid 2px #333",
)
default_classes = [card]
type_styles = {
"success": success,
"warning": warning,
"error": error,
}
def populate(self):
with t.h2(classes=[self.type_styles[self.type]]):
self.insert_slot("card-header")
with t.p():
self.insert_slot()
t.button(self.button_text, on_click=self.on_button_click)
def on_button_click(self, event):
self.trigger_event("my-custom-event",
detail={"type": self.type})
```
--------------------------------
### Define a Dynamic Route for Pet Details
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/07-routing.md
Defines a page component that displays information about a specific pet, identified by `pet_id` in the URL. It uses a dictionary to fetch pet details and includes a link back to the homepage.
```python
@app.page("/pet/") # (3)
class PetPage(Page):
props = ["pet_id"]
def populate(self):
pet = pets.get(self.pet_id)
t.h1("Pet Information")
with t.dl():
for k, v in pet.items():
t.dt(k)
t.dd(v)
t.link("Back to Homepage", href=DefaultPage) # (4)
```
--------------------------------
### Define Component Props
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/in-depth-components.md
Define props for a component using a list of strings for names or Prop instances for additional metadata. The expanded props are available on `self.props_expanded`.
```python
class MyComponent(Component):
props = [
"title", # (1)!
Prop("author_name", "Name of Author", str, "Unknown") # (2)!
]
```
--------------------------------
### Define a Default Route
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/advanced-routing.md
Define a default route by omitting the path argument in the `@app.page` decorator. This route will be matched if no other routes are specified.
```Python
@app.page()
class MyPage(Page):
...
```
--------------------------------
### Custom Link Component for Navigation
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/07-routing.md
A custom component for creating navigation links. It handles click events to prevent default navigation and uses the router to navigate to the specified page, resolving the correct href.
```python
from puepy import Application, Page, Component, t
from puepy.router import Router
app = Application()
app.install_router(Router, link_mode=Router.LINK_MODE_HASH) # (1)
pets = {
"scooby": {"name": "Scooby-Doo", "type": "dog", "character": "fearful"},
"garfield": {"name": "Garfield", "type": "cat", "character": "lazy"},
"snoopy": {"name": "Snoopy", "type": "dog", "character": "playful"},
}
@t.component()
class Link(Component): # (2)
props = ["args"]
enclosing_tag = "a"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.add_event_listener("click", self.on_click)
def set_href(self, href):
if issubclass(href, Page):
args = self.args or {}
self._resolved_href = self.page.router.reverse(href, **args)
else:
self._resolved_href = href
self.attrs["href"] = self._resolved_href
def on_click(self, event):
if (
isinstance(self._resolved_href, str)
and self._resolved_href[0] in "#/"
and self.page.router.navigate_to_path(self._resolved_href)
):
# A page was found; prevent navigation and navigate to page
event.preventDefault()
```
--------------------------------
### Insert Raw HTML in Puepy Component
Source: https://github.com/kkinder/puepy/blob/main/docs/faq.md
Shows how to embed raw HTML strings directly into a Puepy component's rendering using the `html()` helper function. Ensure the `html` function is imported from `puepy.core`.
```python
from puepy.core import html
class MyPage(Page):
def populate(self):
t(html("Hello!"))
```
--------------------------------
### Define a Page Route with Decorator
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/advanced-routing.md
Use the `@app.page` decorator to associate a URL path with a Page class. This is the preferred method for defining routes.
```Python
from puepy import Page
@app.page("/my-page")
class MyPage(Page):
...
```
--------------------------------
### Reverse Route by Page Object
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/advanced-routing.md
Generate a URL path for a specific page by calling `self.page.router.reverse` with the Page object and any necessary arguments.
```Python
path = self.page.router.reverse(PostPage, author_id="5", post_id="7")
```
--------------------------------
### Assigning and Accessing Component Refs
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/in-depth-components.md
Use the `ref=` argument when building tags to assign a unique identifier. Access these refs later via `self.refs["ref_name"]` to interact with the component, such as triggering a click event.
```Python
class MyPage(Page):
def populate(self):
t.button("My Button", ref="my_button")
def auto_click_button(self, ...):
self.refs["my_button"].element.click()
```
--------------------------------
### Import BeautifulSoup from bs4
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/08-pypi-libraries.md
Import the BeautifulSoup library and any specific components like 'Comment' from the 'bs4' package in your Python source file. This makes the library's functionality available for use.
```python
from bs4 import BeautifulSoup, Comment
```
--------------------------------
### Raise Unauthorized Exception
Source: https://github.com/kkinder/puepy/blob/main/docs/cookbook/navigation-guards.md
Use this precheck to prevent page rendering and raise an Unauthorized exception if a condition (e.g., user not authenticated) is not met. Puepy will then display the unauthorized page.
```python
from puepy import exceptions, Page
class MyPage(Page):
...
def precheck(self):
if not self.application.state["authenticated_user"]:
raise exceptions.Unauthorized()
```
--------------------------------
### Listen for Custom Events
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/in-depth-components.md
Consume custom events emitted by child components by defining an `on_` method in the parent component or page. The event object contains the detail dictionary passed during the trigger.
```python
class MyPage(Page):
def populate(self):
t.my_component(on_greeting=self.on_greeting_sent)
def on_greeting_sent(self, event):
print("Incoming message from component", event.detail.get('message'))
```
--------------------------------
### Create a Chart Component with Chart.js
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/10-full-app.md
Define a reusable Chart component in Python that integrates with the Chart.js JavaScript library. This component handles chart creation, updates, and destruction using PyScript's lifecycle methods.
```python
@t.component()
class Chart(Component):
props = ["type", "data", "options"]
enclosing_tag = "canvas"
def on_redraw(self):
self.call_chartjs()
def on_ready(self):
self.call_chartjs()
def call_chartjs(self):
if hasattr(self, "_chart_js"):
self._chart_js.destroy()
self._chart_js = js.Chart.new(
self.element,
jsobj(type=self.type, data=self.data, options=self.options),
)
```
--------------------------------
### Bind Form Element to State
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/reactivity.md
Use the `bind` parameter on input elements to create a two-way connection between the element's value and a state key. Changes in the input update the state, and state updates reflect in the input.
```Python
class MyComponent(Component):
def initial(self):
return {"name": ""}
def populate(self):
# bind specifies what key on self.state should be tied to this input's value
t.input(placeholder="Type your name", bind="name")
```
--------------------------------
### Set Authenticated User in Application State
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/reactivity.md
Assign the username from local state to the `authenticated_user` key in the application state.
```python
self.application.state["authenticated_user"] = self.state["username"]
```
--------------------------------
### Add or Remove Component CSS Classes
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/css-classes.md
When using a component, you can add new classes or remove default classes. To remove a class, prefix its name with a '/'.
```Python
t.card(classes="card-blue")
t.card(classes="/card")
```
--------------------------------
### PuePy Fixed Code: Using `ref=` for Element Preservation
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/04-refs.md
This code shows the solution using the `ref=` parameter to preserve DOM elements between refreshes. This prevents elements from being discarded and recreated, maintaining their state and focus.
```python
@app.page()
class RefsSolutionPage(Page):
def initial(self):
return {"word": ""}
def populate(self):
t.h1("Solution: Use ref=")
if self.state["word"]:
for char in self.state["word"]:
t.span(char, classes="char-box")
with t.div(style="margin-top: 1em"):
t.input(bind="word", placeholder="Type a word", ref="enter_word")
```
--------------------------------
### Reverse Route by Route Name
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/advanced-routing.md
Alternatively, reverse a route by its name using `self.page.router.reverse`, providing the route name string and any required arguments.
```Python
path = self.page.router.reverse("post_page", author_id="5", post_id="7")
```
--------------------------------
### Add Chart.js JavaScript Library
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/10-full-app.md
Include the Chart.js library in your PyScript project by specifying its CDN URL and a module name in the `js_modules` configuration. This allows direct usage from Python.
```json
"https://cdn.jsdelivr.net/npm/chart.js": "chart"
```
--------------------------------
### Specify PyPi packages in PyScript config
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/08-pypi-libraries.md
Declare necessary PyPi packages, such as 'beautifulsoup4', in the 'packages' array within the PyScript JSON configuration file. This ensures the packages are available to your application.
```json
{
"name": "PuePy Tutorial",
"debug": true,
"packages": [
"./puepy-0.5.0-py3-none-any.whl",
"beautifulsoup4"
],
"js_modules": {
"main": {
"https://cdn.jsdelivr.net/npm/morphdom@2.7.4/+esm": "morphdom"
}
}
}
```
--------------------------------
### Check Authenticated User in Navigation Guard
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/reactivity.md
Use `application.state` to check for an authenticated user before allowing navigation. Raises `Unauthorized` if the user is not authenticated.
```python
def precheck(self):
if not self.application.state["authenticated_user"]:
raise exceptions.Unauthorized()
```
--------------------------------
### PuePy Problem Code: Re-creating DOM Elements
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/04-refs.md
This code demonstrates the issue where DOM elements are re-created on each page redraw, leading to loss of focus. It's used when elements need to be dynamically generated without preservation.
```python
@app.page()
class RefsProblemPage(Page):
def initial(self):
return {"word": ""}
def populate(self):
t.h1("Problem: DOM elements are re-created")
if self.state["word"]:
for char in self.state["word"]:
t.span(char, classes="char-box")
with t.div(style="margin-top: 1em"):
t.input(bind="word", placeholder="Type a word")
```
--------------------------------
### Add Route Directly
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/advanced-routing.md
Routes can also be added directly to the router instance using `app.router.add_route`. This method is less preferred than using the decorator.
```Python
app.router.add_route(path_match="/foobar", page_class=Foobar)
```
--------------------------------
### Use SVG with xmlns in Puepy
Source: https://github.com/kkinder/puepy/blob/main/docs/faq.md
Demonstrates how to correctly include SVG elements within Puepy components by specifying the xmlns attribute.
```python
with t.svg(xmlns="http://www.w3.org/2000/svg"):
...
```
--------------------------------
### Configure Redraw on App State Changes (Disabled)
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/reactivity.md
Sets `redraw_on_app_state_changes` to `False`, preventing changes to application state from triggering a redraw.
```python
class Page2(Page):
redraw_on_app_state_changes = False # (2)!
```
--------------------------------
### Modify Mutable State In-Place with Mutate Context Manager
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/reactivity.md
When modifying mutable objects within the state (like lists or dictionaries) in-place, use the `mutate()` context manager to ensure reactivity. Direct in-place modifications without `mutate()` will not trigger UI updates.
```Python
class MyComponent(Component):
def update_movies(self):
# THIS WILL NOT CAUSE A UI REFRESH!
self.state["movies"].append("Monty Python’s Life of Brian")
```
```Python
class MyComponent(Component):
def update_movies(self):
# THIS WILL NOT CAUSE A UI REFRESH!
with self.state.mutate("movies"):
self.state["movies"].append("Monty Python’s Life of Brian")
```
--------------------------------
### Define Slots in a Component
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/06-components.md
This snippet shows how to define slots within a Puepy component using `self.insert_slot()`. The default slot is used when no name is provided.
```py
with t.h2():
self.insert_slot("card-header")
with t.p():
self.insert_slot() # (1)
```
--------------------------------
### Limit Automatic UI Refresh
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/reactivity.md
Specify a list of state keys to `redraw_on_changes` to only refresh the UI when those specific items change.
```Python
class MyComponent(Component):
# When items in this this change, the UI will be redrawn
redraw_on_changes = ["items"]
```
--------------------------------
### Guessing Game with Number Watcher
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/05-watchers.md
This snippet demonstrates a PuePy component that watches for changes in the 'number' input field. When the input changes, the `on_number_change` method is triggered to validate the user's guess against a predefined winning number and update a message accordingly. The function name `on_number_change` is automatically registered based on the pattern `on__change`.
```python
from puepy import app, Page, t
@app.page()
class WatcherPage(Page):
def initial(self):
self.winner = 4
return {"number": "", "message": ""}
def populate(self):
t.h1("Can you guess a number between 1 and 10?")
with t.div(style="margin: 1em"):
t.input(bind="number", placeholder="Enter a guess", autocomplete="off", type="number", maxlength=1)
if self.state["message"]:
t.p(self.state["message"])
def on_number_change(self, event): # (1)
try:
if int(self.state["number"]) == self.winner:
self.state["message"] = "You guessed the number!"
else:
self.state["message"] = "Keep trying..."
except (ValueError, TypeError):
self.state["message"] = ""
```
--------------------------------
### Define Custom Route Name
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/advanced-routing.md
Assign a custom name to a route using the `name` parameter in either the `@app.page` decorator or the `add_route` method. This name can be used for reversing routes.
```Python
@app.page("/my-page", name="another_name")
class MyPage(Page):
...
class AnotherPage(Page):
...
app.add_route("/foobar", AnotherPage, name="foobar")
```
--------------------------------
### Component Default CSS Classes
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/css-classes.md
Components can specify default CSS classes using the `default_classes` attribute. These classes are applied automatically when the component is rendered.
```Python
@t.component()
class Card(Component):
...
default_classes = ["card"]
...
```
--------------------------------
### Trigger Custom Events
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/in-depth-components.md
Emit custom events from a component using `self.trigger_event`, optionally including a detail dictionary. This allows child components to communicate with parent components.
```python
class MyComponent(Component):
def some_method(self):
self.trigger_event("greeting", detail={"message": "Hello There"})
```
--------------------------------
### Pass Attributes to Components
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/in-depth-components.md
Arbitrary keyword arguments not matching defined props are treated as attributes and rendered as HTML attributes on the component's tag. This allows passing HTML attributes without explicit prop definition.
```python
from puepy import Component, Page, t
class NameInput(Component):
enclosing_tag = "input"
class MyPage(Page):
def populate(self):
t.name_input(id="name_input", placeholder="Enter your name")
```
--------------------------------
### Accessing Web Component DOM Elements in PuePy
Source: https://github.com/kkinder/puepy/blob/main/docs/tutorial/09-using-web-components.md
This Python snippet shows how to access the underlying DOM element of a Web Component instance in PuePy. Use the `.element` attribute on the referenced component to call its native JavaScript methods, such as `show()`.
```Python
self.refs["dialog"].element.show()
```
--------------------------------
### Define CSS Classes for Tags
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/css-classes.md
Use `class_name` or `classes` attributes to assign CSS classes to tags. Classes can be provided as a single string, a list of strings, or a dictionary where keys are class names and values determine inclusion.
```Python
t.button("Primary Large Button", class_name="primary large")
t.button("Primary Small Button", classes=["primary", "small"])
t.button("Primary Medium Button", classes={
"primary": True,
"medium": True,
"small": False,
"large": False})
```
--------------------------------
### Override Component Enclosing Tag
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/in-depth-components.md
Set the `enclosing_tag` attribute to change the default HTML tag used for rendering a component. The default is 'div'.
```python
class MyInputComponent(Component):
enclosing_tag = "input"
```
--------------------------------
### Update Component State to Trigger Refresh
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/reactivity.md
Modifying the state dictionary directly, such as updating the 'name' property, automatically triggers a UI refresh.
```Python
class MyComponent(Component):
def update_name(self):
# This triggers a refresh
self.state["name"] = "Monty Python"
```
--------------------------------
### Disable Automatic UI Refresh
Source: https://github.com/kkinder/puepy/blob/main/docs/guide/reactivity.md
Set `redraw_on_changes` to `False` to completely disable automatic UI refreshes. Use `trigger_redraw()` to manually refresh the component or the entire page.
```Python
class MyComponent(Component):
# The UI will no longer refresh on state changes
redraw_on_changes = False
def something_happened(self):
# This can be called to manually refresh this component and its children
self.trigger_redraw()
# Or, you can redraw the whole page
self.page.trigger_redraw()
```
=== COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.