caspian-utils 0.1.13 → 0.1.14
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.
package/dist/docs/components.md
CHANGED
|
@@ -16,7 +16,7 @@ related:
|
|
|
16
16
|
|
|
17
17
|
Components in Caspian are implemented as Python functions decorated with `@component`.
|
|
18
18
|
|
|
19
|
-
In authored HTML, import them with
|
|
19
|
+
In authored route, layout, or component HTML files, import them with a top-of-file `@import` comment and render them with HTML-first kebab-cased `x-*` tags such as `<x-my-component />` or `<x-my-component>...</x-my-component>`.
|
|
20
20
|
|
|
21
21
|
Treat that `x-*` form as the current Caspian component contract for authored templates.
|
|
22
22
|
|
|
@@ -26,12 +26,13 @@ As the app grows, treat `src/components/` as the default home for reusable appli
|
|
|
26
26
|
|
|
27
27
|
## Mental Model
|
|
28
28
|
|
|
29
|
-
- Use a Python component when you want a reusable server-rendered UI building block.
|
|
30
|
-
- Return an HTML string directly for small presentational components.
|
|
31
|
-
- Use `html(...)` to keep markup, server interpolation, and a PulsePoint `<script>` inline in one Python file (single-file component) for small
|
|
32
|
-
- Use `render_html(...)` with a same-name `.html` file when the component has large markup, a long script, or you want clearer separation between Python logic and UI.
|
|
33
|
-
-
|
|
34
|
-
-
|
|
29
|
+
- Use a Python component when you want a reusable server-rendered UI building block.
|
|
30
|
+
- Return an HTML string directly for small presentational components.
|
|
31
|
+
- Use `html(...)` to keep markup, server interpolation, and a PulsePoint `<script>` inline in one Python file (single-file component) for a small or medium UI responsibility. It renders through Caspian's Jinja env, so `{{ ... }}` is server-side and `{ ... }` stays for PulsePoint.
|
|
32
|
+
- Use `render_html(...)` with a same-name `.html` file when the component has large markup, a long script, or you want clearer separation between Python logic and UI.
|
|
33
|
+
- Split UI by responsibility the way you would split React components. Single-file component authoring is a file shape, not permission to put a full page, dashboard, or all tab panels into one Python file.
|
|
34
|
+
- When a component needs first-party interactivity, bind events in the component template with PulsePoint-handled `on*` attributes and keep state in `pp.state(...)`; do not build id-driven `querySelector(...)` or `addEventListener(...)` wiring for normal component behavior.
|
|
35
|
+
- Keep page-level workflows in `src/app/`, move reusable UI into `src/components/`, and keep helpers, services, validators, and adapters in `src/lib/`.
|
|
35
36
|
|
|
36
37
|
## Framework Internals Note
|
|
37
38
|
|
|
@@ -107,7 +108,7 @@ Authored PulsePoint examples:
|
|
|
107
108
|
|
|
108
109
|
## Import And Use Components
|
|
109
110
|
|
|
110
|
-
Place component imports at the top of the HTML template, above the authored root element.
|
|
111
|
+
Place component imports at the top of the HTML template, above the authored root element.
|
|
111
112
|
|
|
112
113
|
```html
|
|
113
114
|
<!-- @import Container from "../components" -->
|
|
@@ -121,7 +122,7 @@ The import comment is the bridge between the Python component export and the `x-
|
|
|
121
122
|
|
|
122
123
|
In section-based apps, follow the same mental model as the Next.js App Router: import shared shell components such as sidebars, topbars, breadcrumbs, and section frames in the parent folder's `layout.html`, then import page-specific components in each child route's `index.html`.
|
|
123
124
|
|
|
124
|
-
Treat `<!-- @import ... -->` as a file-level directive, not as rendered markup. It does not count as the template root, and it
|
|
125
|
+
Treat `<!-- @import ... -->` as a file-level directive, not as rendered markup. It does not count as the template root, and it must not be nested inside the root wrapper element. In route and layout files, this means the import comments come before the first authored tag in `index.html` or `layout.html`.
|
|
125
126
|
|
|
126
127
|
- `<!-- @import Container from "../components" -->` resolves `Container.py` from that folder.
|
|
127
128
|
- The exported component name maps to the tag you render by kebab-casing it and prefixing `x-`, such as `Container` for `<x-container />` or `CommandDialog` for `<x-command-dialog />`.
|
|
@@ -141,14 +142,14 @@ Good:
|
|
|
141
142
|
</section>
|
|
142
143
|
```
|
|
143
144
|
|
|
144
|
-
Bad:
|
|
145
|
-
|
|
146
|
-
```html
|
|
147
|
-
<section class="auth-panel auth-panel-compact fade-up">
|
|
148
|
-
<!-- @import { Button, Input, Label } from "../../../lib/maddex" -->
|
|
149
|
-
<
|
|
150
|
-
</section>
|
|
151
|
-
```
|
|
145
|
+
Bad:
|
|
146
|
+
|
|
147
|
+
```html
|
|
148
|
+
<section class="auth-panel auth-panel-compact fade-up">
|
|
149
|
+
<!-- @import { Button, Input, Label } from "../../../lib/maddex" -->
|
|
150
|
+
<x-label>Email</x-label>
|
|
151
|
+
</section>
|
|
152
|
+
```
|
|
152
153
|
|
|
153
154
|
### Same-File Component Exports
|
|
154
155
|
|
|
@@ -221,11 +222,13 @@ Use this split when:
|
|
|
221
222
|
|
|
222
223
|
This keeps the component easy to read: Python owns the server-side logic and template context, while the HTML file owns the rendered UI and browser behavior.
|
|
223
224
|
|
|
224
|
-
## Single-File Components With `html(...)`
|
|
225
|
-
|
|
226
|
-
When a component is small or medium, keep the markup, server-side interpolation, and the PulsePoint `<script>` inline in the Python file instead of a sibling `.html`. Import `html` from `casp.component_decorator` and return `html("""...""", **context)`.
|
|
227
|
-
|
|
228
|
-
`
|
|
225
|
+
## Single-File Components With `html(...)`
|
|
226
|
+
|
|
227
|
+
When a component is small or medium, keep the markup, server-side interpolation, and the PulsePoint `<script>` inline in the Python file instead of a sibling `.html`. Import `html` from `casp.component_decorator` and return `html("""...""", **context)`.
|
|
228
|
+
|
|
229
|
+
Single-file does not mean one file per page. Treat each single-file component like a React component with one clear responsibility. If a screen has an overview tab, an activity tab, and a settings tab, those substantial panels should normally be separate components such as `OverviewTab.py`, `ActivityTab.py`, and `SettingsTab.py`, assembled by a small tab shell or the route template. If one component is growing because it owns unrelated forms, tables, charts, and action bars, split those responsibilities and pass the needed data as props.
|
|
230
|
+
|
|
231
|
+
`html(...)` renders the string through the same Jinja environment Caspian uses for template files, so three brace dialects coexist without colliding:
|
|
229
232
|
|
|
230
233
|
- `{{ value }}` is server render (Python to HTML).
|
|
231
234
|
- `{{ value | json }}` safely serializes a server value into a `<script>`.
|
|
@@ -256,11 +259,13 @@ def UserCard(user, **props):
|
|
|
256
259
|
|
|
257
260
|
The returned value is `Markup`, so the normal pipeline still injects `pp-component` on the single root and `transform_scripts(...)` rewrites the plain `<script>` to `type="text/pp"`. A single-file component renders identically to the two-file `render_html(...)` form; the choice is purely about readability.
|
|
258
261
|
|
|
259
|
-
Rules for inline `html(...)`:
|
|
260
|
-
|
|
261
|
-
- The single-root rule still applies: exactly one top-level element with any `<script>` nested inside it.
|
|
262
|
-
-
|
|
263
|
-
-
|
|
262
|
+
Rules for inline `html(...)`:
|
|
263
|
+
|
|
264
|
+
- The single-root rule still applies: exactly one top-level element with any `<script>` nested inside it.
|
|
265
|
+
- Keep the component focused on one UI responsibility. Prefer composing several single-file components over one long Python file that contains multiple sections, tab panels, or workflows.
|
|
266
|
+
- Pass data, labels, variants, current selection, counts, permissions, or callbacks as props instead of making child components reach back into route markup or duplicate parent state.
|
|
267
|
+
- Autoescaping is ON (Jinja default), so `{{ value }}` escapes HTML automatically and user text is safe without `| e`. The flip side: trusted HTML you want rendered as-is must be `Markup(...)` or piped through `| safe`.
|
|
268
|
+
- A `children` value is auto-marked safe (parity with `render_html(...)`), so `{{ children }}` renders nested component markup correctly without `| safe`.
|
|
264
269
|
- Do not use a Python f-string for the markup. PulsePoint single braces `{ ... }` would collide with f-string interpolation. Use a plain triple-quoted string passed to `html(...)`.
|
|
265
270
|
- Prefer `render_html(...)` with a same-name `.html` file when the markup is large or the `<script>` carries real logic. A long client script is a smell regardless of file shape; move heavy work into `@rpc()` actions or smaller composed components.
|
|
266
271
|
|
|
@@ -314,14 +319,14 @@ def Counter(label: str = "Clicks", **props):
|
|
|
314
319
|
|
|
315
320
|
The fix is always the same: move the `<script>` above the root's closing tag so the whole return value is one element. Caspian has no fragment syntax — the single root must be a real native element — so if a component genuinely needs sibling-looking sections, wrap them all in one outer element (a `<div>` or `<section>`) and keep the script inside that wrapper. This rule is identical for the two-file `render_html(...)` form, so the same `.html` file must also end with `</script></root>` rather than `</root>` followed by a trailing `<script>`.
|
|
316
321
|
|
|
317
|
-
## Component Imports: Python Imports Or `@import`
|
|
318
|
-
|
|
319
|
-
A component can render other components with `x-*` tags in either the two-file `.html` or the inline `html(...)` form. There are two ways to tell Caspian which component a tag refers to.
|
|
320
|
-
|
|
321
|
-
1. The `<!-- @import Name from "path" -->` HTML comment, resolved by path string.
|
|
322
|
-
2. A real Python import at the top of the component module. A component's own `x-*` tags resolve from the components imported into that module, with no `@import` comment needed.
|
|
323
|
-
|
|
324
|
-
|
|
322
|
+
## Component Imports: Python Imports Or `@import`
|
|
323
|
+
|
|
324
|
+
A component can render other components with `x-*` tags in either the two-file `.html` or the inline `html(...)` form. There are two ways to tell Caspian which component a tag refers to.
|
|
325
|
+
|
|
326
|
+
1. The `<!-- @import Name from "path" -->` HTML comment, resolved by path string. Use this as a top-of-file directive in authored `.html` templates, above the single root element.
|
|
327
|
+
2. A real Python import at the top of the component module. A component's own `x-*` tags resolve from the components imported into that module, with no `@import` comment needed.
|
|
328
|
+
|
|
329
|
+
For single-file Python components that return `html("""...""")`, use real Python imports for child components. Do not put `<!-- @import ... -->` inside the returned HTML string. The compiler can parse local import comments, but that is a permissive fallback, not the authoring pattern for single-file components. Python imports are the unambiguous source of truth for which component a tag refers to, they give normal editor navigation, and they prevent same-name collisions across directories. If `variantA/Tag.py` and `variantB/Tag.py` both export `Tag`, the Python import in each consumer file decides which `Tag` its `<x-tag>` resolves to.
|
|
325
330
|
|
|
326
331
|
```python
|
|
327
332
|
from casp.component_decorator import component, html
|
|
@@ -340,15 +345,15 @@ def Panel(children="", **props):
|
|
|
340
345
|
""", children=children)
|
|
341
346
|
```
|
|
342
347
|
|
|
343
|
-
|
|
348
|
+
Runtime resolution precedence for an `x-*` tag inside a component's own output, lowest to highest:
|
|
349
|
+
|
|
350
|
+
- inherited components from an ancestor template
|
|
351
|
+
- the component's own Python module imports
|
|
352
|
+
- a local `<!-- @import ... -->` in that same template
|
|
353
|
+
|
|
354
|
+
So a component's Python import wins over an inherited same-name component, and an explicit local `@import` wins over both. Authoring guidance is stricter than the runtime fallback: put `@import` comments only at the top of `.html` templates, and use Python imports inside single-file `html(...)` components.
|
|
344
355
|
|
|
345
|
-
-
|
|
346
|
-
- the component's own Python module imports
|
|
347
|
-
- a local `<!-- @import ... -->` in that same template
|
|
348
|
-
|
|
349
|
-
So a component's Python import wins over an inherited same-name component, and an explicit local `@import` wins over both.
|
|
350
|
-
|
|
351
|
-
### Direct-Call Composition (Calling A Component As A Function)
|
|
356
|
+
### Direct-Call Composition (Calling A Component As A Function)
|
|
352
357
|
|
|
353
358
|
A component can compose another component two ways: by writing its `<x-*>` tag, or by calling it as a plain Python function and interpolating the result with `{{ }}` (React-style). Both work, and both resolve nested `<x-*>` tags from the callee's own Python module imports.
|
|
354
359
|
|
|
@@ -377,7 +382,36 @@ Notes:
|
|
|
377
382
|
|
|
378
383
|
### Slot Content Resolves In The Parent Scope
|
|
379
384
|
|
|
380
|
-
Component tags written as slot content (children passed between a component's opening and closing tags) resolve in the scope where they were authored, not in the child component's scope. This matches slot semantics in other component systems: a `<x-tag>` written by the parent stays bound to the parent's `Tag` even when it is slotted into a child that has its own `Tag`. The component that authors a tag in markup must import that component, the same way it would for any tag it renders directly.
|
|
385
|
+
Component tags written as slot content (children passed between a component's opening and closing tags) resolve in the scope where they were authored, not in the child component's scope. This matches slot semantics in other component systems: a `<x-tag>` written by the parent stays bound to the parent's `Tag` even when it is slotted into a child that has its own `Tag`. The component that authors a tag in markup must import that component, the same way it would for any tag it renders directly.
|
|
386
|
+
|
|
387
|
+
## Component Granularity And Responsibility
|
|
388
|
+
|
|
389
|
+
Prefer small, named components that match the responsibility a developer would expect from a React-style component tree.
|
|
390
|
+
|
|
391
|
+
Use this split before writing markup:
|
|
392
|
+
|
|
393
|
+
- Page route: owns page assembly, first-render context, and route-level workflows.
|
|
394
|
+
- Shell component: owns shared layout around a page area, such as a tab list, sidebar, toolbar frame, or dashboard section wrapper.
|
|
395
|
+
- Section component: owns one visible content area, such as an overview panel, analytics section, settings form, activity list, billing table, or user card grid.
|
|
396
|
+
- Leaf component: owns repeated or reusable details, such as cards, rows, badges, buttons with behavior, empty states, and field groups.
|
|
397
|
+
|
|
398
|
+
For example, a tabbed account page should be assembled from focused parts:
|
|
399
|
+
|
|
400
|
+
```text
|
|
401
|
+
src/components/account/
|
|
402
|
+
AccountTabs.py
|
|
403
|
+
AccountOverviewTab.py
|
|
404
|
+
AccountSecurityTab.py
|
|
405
|
+
AccountBillingTab.py
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
`AccountTabs.py` can own the selected tab state and render the tab controls, while each tab panel owns its own markup and receives props such as `user`, `plan`, `sessions`, or `can_edit`. This keeps PulsePoint state close to the interaction that owns it and keeps each file readable.
|
|
409
|
+
|
|
410
|
+
Do not create a single `AccountPage.py` or `DashboardTabs.py` that contains every tab, form, table, metric card, and modal just because `html(...)` makes it possible. When the file starts needing headings in comments to separate unrelated areas, those headings are usually component boundaries.
|
|
411
|
+
|
|
412
|
+
Related subcomponents may live in one Python file only when they are tiny and tightly coupled, such as `Tabs`, `TabsList`, `TabsTrigger`, and `TabsContent` primitives, or a component plus two very small private helpers. For app-specific page chunks, prefer one exported component per file with a name that explains its role.
|
|
413
|
+
|
|
414
|
+
Props are the boundary between components. Pass parent-owned data and configuration down through attributes or direct Python calls, keep local interactive state inside the component that owns the behavior, and use slot content when the parent needs to provide authored child markup. If two sibling chunks need the same server data, load it in the route's `page()` or a shared helper and pass the relevant pieces into each component.
|
|
381
415
|
|
|
382
416
|
## Auto-Injected `pp-component` And PulsePoint Script Type
|
|
383
417
|
|
|
@@ -396,7 +430,7 @@ Every component HTML template must render exactly one authored top-level parent
|
|
|
396
430
|
|
|
397
431
|
The same rule applies to route and layout templates such as `src/app/**/index.html` and `src/app/**/layout.html`. See [routing.md](./routing.md) and [pulsepoint.md](./pulsepoint.md) for the non-component versions of the same authoring contract.
|
|
398
432
|
|
|
399
|
-
Top-of-file `<!-- @import ... -->` directives are allowed before that root element and do not violate the single-root rule.
|
|
433
|
+
Top-of-file `<!-- @import ... -->` directives are allowed before that root element and do not violate the single-root rule. They belong before the root, not inside it.
|
|
400
434
|
|
|
401
435
|
In source, that parent may be a native HTML element or a single imported `x-*` component tag. After component expansion, the template must still resolve to one final native HTML root so Caspian has exactly one place to inject `pp-component`.
|
|
402
436
|
|
|
@@ -508,11 +542,13 @@ async def ProfileCard(user_id: str) -> str:
|
|
|
508
542
|
|
|
509
543
|
Keep synchronous components as the default. Switch to `async def` only when the component itself needs awaited I/O.
|
|
510
544
|
|
|
511
|
-
## Best Practices
|
|
512
|
-
|
|
513
|
-
- Put reusable components in `src/components/` and keep route files in `src/app/`.
|
|
514
|
-
- For dashboards, admin areas, account sections, and route groups with child routes, put the shared shell in the parent folder's `layout.html` and compose it from reusable components there instead of repeating the same shell in every child `index.html`.
|
|
515
|
-
- Default to a single Python file with inline `html(...)` for most components, including ones with PulsePoint behavior. Move to a thin Python wrapper plus a same-name `.html` template only when
|
|
545
|
+
## Best Practices
|
|
546
|
+
|
|
547
|
+
- Put reusable components in `src/components/` and keep route files in `src/app/`.
|
|
548
|
+
- For dashboards, admin areas, account sections, and route groups with child routes, put the shared shell in the parent folder's `layout.html` and compose it from reusable components there instead of repeating the same shell in every child `index.html`.
|
|
549
|
+
- Default to a single Python file with inline `html(...)` for most focused components, including ones with PulsePoint behavior. Move to a thin Python wrapper plus a same-name `.html` template only when that focused component's markup is large or the `<script>` carries real logic. Both forms render identically, so this is a readability choice, not a capability one.
|
|
550
|
+
- Split by responsibility before switching file shapes. If a component is large because it contains several independent sections, tabs, tables, forms, or workflows, create smaller components first instead of turning it into one huge `.py` plus `.html` pair.
|
|
551
|
+
- In single-file `html(...)` components, resolve child `x-*` tags with real Python imports at the top of the `.py` module. Reserve `<!-- @import ... -->` comments for authored `.html` templates and keep those comments above the root.
|
|
516
552
|
- For component clicks, inputs, menus, toggles, filters, and list updates, use PulsePoint events and directives inside the component template (inline `html(...)` or the `.html` file). Avoid manual DOM selection, manual listener setup, and manual `innerHTML` rendering unless integrating a third-party imperative widget.
|
|
517
553
|
- Keep the component file name, exported function name, and authored tag aligned, such as `Button.py`, `def Button(...)`, and `<x-button />`.
|
|
518
554
|
- Accept `children` or `**props` when the component should support nested content.
|
|
@@ -40,9 +40,9 @@ Treat `caspian.config.json` and the actual project tree as the source of truth f
|
|
|
40
40
|
|
|
41
41
|
## Authored HTML Rule
|
|
42
42
|
|
|
43
|
-
For authored route, layout, loading, not-found, and error HTML files, keep exactly one top-level parent HTML element or one imported `x-*` component root.
|
|
44
|
-
|
|
45
|
-
- Keep any `<!-- @import ... -->` directives above that root.
|
|
43
|
+
For authored route, layout, loading, not-found, and error HTML files, keep exactly one top-level parent HTML element or one imported `x-*` component root.
|
|
44
|
+
|
|
45
|
+
- Keep any `<!-- @import ... -->` directives above that root. They are header directives for the file, not children of the root element.
|
|
46
46
|
- Keep any owned plain `<script>` inside that root, not after it.
|
|
47
47
|
- Do not handwrite `pp-component` or `type="text/pp"`.
|
|
48
48
|
|
|
@@ -125,9 +125,11 @@ See `routing.md` for the full App Router-style rules for dynamic segments, route
|
|
|
125
125
|
|
|
126
126
|
Use this folder for reusable UI components that should be imported into route templates or other component templates.
|
|
127
127
|
|
|
128
|
-
As the app grows, default to `src/components/` for application-level UI that will be shared across routes or features. Keep page-only markup close to the route in `src/app/`, but move shared cards, forms, shells, navigation, and other reusable visual building blocks into `src/components/`.
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
As the app grows, default to `src/components/` for application-level UI that will be shared across routes or features. Keep page-only markup close to the route in `src/app/`, but move shared cards, forms, shells, navigation, and other reusable visual building blocks into `src/components/`.
|
|
129
|
+
|
|
130
|
+
For page-specific chunks that are still substantial, a route-local component folder is also acceptable. Use this when a component is owned by one route but deserves its own focused file, such as one tab panel, one settings form, one analytics section, or one table toolbar. The route should still read as a short assembly of named `x-*` tags.
|
|
131
|
+
|
|
132
|
+
The common Caspian pattern is a Python file such as `Button.py` with `@component`, optionally paired with a same-name HTML file such as `Button.html` when the component has richer markup or PulsePoint behavior. In authored HTML, that component is consumed as `<x-button />`.
|
|
131
133
|
|
|
132
134
|
One Python file can also export multiple related `@component` functions. When that happens, import those tags from that exact file path in HTML, for example `<!-- @import { Breadcrumb, BreadcrumbItem, BreadcrumbList } from "../components/Breadcrumb.py" -->`, and render them as `<x-breadcrumb />`, `<x-breadcrumb-item />`, and `<x-breadcrumb-list />` instead of assuming each tag has its own sibling `.py` file.
|
|
133
135
|
|
|
@@ -334,10 +336,11 @@ If an AI agent is deciding where to make changes, use these rules first.
|
|
|
334
336
|
- When the user asks for a dashboard, admin area, account area, or any grouped set of child routes, create a parent folder in `src/app/` with `layout.html` and place the child routes beneath it. Use `(group)/layout.html` only when that parent should not appear in the URL.
|
|
335
337
|
- Read [file-uploads.md](./file-uploads.md) when the task involves upload widgets, media libraries, or file-manager flows.
|
|
336
338
|
- Check [routing.md](./routing.md) when you need URL segment rules, layout nesting behavior, or dynamic route conventions.
|
|
337
|
-
- Put reusable component files in `src/components/` and check [components.md](./components.md) for `@component`, `render_html(__file__)`, `x-*` component tags, import comments, and single-root template rules.
|
|
338
|
-
-
|
|
339
|
+
- Put reusable component files in `src/components/` and check [components.md](./components.md) for `@component`, `render_html(__file__)`, `x-*` component tags, import comments, and single-root template rules.
|
|
340
|
+
- Split UI by component responsibility before files become large. A tab panel, settings form, table section, toolbar, or repeated card/list item can be its own component even when it is only used by one route.
|
|
341
|
+
- When deciding between `src/components/` and `src/lib/`, use `src/components/` for anything rendered as reusable UI and `src/lib/` for helpers, services, validators, adapters, and shared business logic.
|
|
339
342
|
- Use [mcp.md](./mcp.md) only when `caspian.config.json` enables MCP and the task involves FastMCP tool definitions, nested config discovery, or local MCP commands.
|
|
340
|
-
- Keep `<!-- @import ... -->` comments above the single authored root element in route, layout, and component HTML files.
|
|
343
|
+
- Keep `<!-- @import ... -->` comments above the single authored root element in route, layout, and component HTML files. Do not nest them inside `<html>`, `<body>`, `<section>`, or any other parent wrapper.
|
|
341
344
|
- Follow the single-root authoring contract in [routing.md](./routing.md), [components.md](./components.md), and [pulsepoint.md](./pulsepoint.md): one authored root, any owned `<script>` inside that root, and no handwritten `pp-component` or `type="text/pp"` in source templates.
|
|
342
345
|
- Put shared helpers and reusable libraries in `src/lib/`.
|
|
343
346
|
- Use `settings/bs-config.ts` when uploaded public assets should not trigger BrowserSync reloads during the local stack.
|
package/dist/docs/routing.md
CHANGED
|
@@ -177,11 +177,13 @@ Examples:
|
|
|
177
177
|
|
|
178
178
|
Use `index.html` for the route template. This is the route's view layer.
|
|
179
179
|
|
|
180
|
-
If a route renders visible page content, that content belongs here even when the route also has an `index.py` companion.
|
|
181
|
-
|
|
182
|
-
Route templates can import reusable Python components with `<!-- @import ... -->` comments and render them with HTML-first `x-*` tags such as `<x-button />`. Use [components.md](./components.md) for the component authoring rules.
|
|
183
|
-
|
|
184
|
-
Place those import comments at the top of the file, above the authored root element. They are file-level directives, not children of the route root.
|
|
180
|
+
If a route renders visible page content, that content belongs here even when the route also has an `index.py` companion.
|
|
181
|
+
|
|
182
|
+
Route templates can import reusable Python components with `<!-- @import ... -->` comments and render them with HTML-first `x-*` tags such as `<x-button />`. Use [components.md](./components.md) for the component authoring rules.
|
|
183
|
+
|
|
184
|
+
Place those import comments at the top of the file, above the authored root element. They are file-level directives, not children of the route root.
|
|
185
|
+
|
|
186
|
+
Keep route templates as composition, not as the place where all section markup accumulates. A route with tabs, dashboard panels, forms, tables, or repeated cards should import focused components for those responsibilities and assemble them with `x-*` tags. For example, a dashboard route can import `<x-dashboard-header />`, `<x-metric-strip />`, `<x-activity-tab />`, and `<x-settings-tab />` rather than placing every tab panel's full markup in `index.html` or one giant Python component.
|
|
185
187
|
|
|
186
188
|
Route templates follow the same authored-vs-runtime contract documented in [pulsepoint.md](./pulsepoint.md) and the same single-root discipline documented in [components.md](./components.md): keep one authored parent node, keep any `<!-- @import ... -->` directives above that root, use a plain `<script>` inside that root when needed, and do not handwrite `pp-component` or `type="text/pp"`. That root may be a native HTML element or a single imported `x-*` component tag, but after expansion it must resolve to one final HTML root.
|
|
187
189
|
|
|
@@ -223,14 +225,24 @@ Also bad:
|
|
|
223
225
|
<aside class="dashboard-help">Tips</aside>
|
|
224
226
|
```
|
|
225
227
|
|
|
226
|
-
Also bad:
|
|
227
|
-
|
|
228
|
-
```html
|
|
229
|
-
<section class="dashboard-shell">
|
|
230
|
-
<!-- @import StatsCard from "../components" -->
|
|
231
|
-
<x-stats-card title="Users" value="42" />
|
|
232
|
-
</section>
|
|
233
|
-
```
|
|
228
|
+
Also bad:
|
|
229
|
+
|
|
230
|
+
```html
|
|
231
|
+
<section class="dashboard-shell">
|
|
232
|
+
<!-- @import StatsCard from "../components" -->
|
|
233
|
+
<x-stats-card title="Users" value="42" />
|
|
234
|
+
</section>
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Correct:
|
|
238
|
+
|
|
239
|
+
```html
|
|
240
|
+
<!-- @import StatsCard from "../components" -->
|
|
241
|
+
|
|
242
|
+
<section class="dashboard-shell">
|
|
243
|
+
<x-stats-card title="Users" value="42" />
|
|
244
|
+
</section>
|
|
245
|
+
```
|
|
234
246
|
|
|
235
247
|
Use [pulsepoint.md](./pulsepoint.md) when you need the full authored-vs-rendered example instead of this routing-focused reminder. Use [pulsepoint-runtime-map.md](./pulsepoint-runtime-map.md) when a route task names a specific PulsePoint directive or SPA behavior and you need the owning runtime file quickly.
|
|
236
248
|
|
|
@@ -510,8 +522,9 @@ If an AI agent is choosing where to add or update route code, apply these rules
|
|
|
510
522
|
- If a route renders UI, create or update `index.html` for the markup.
|
|
511
523
|
- Add `index.py` only when the same route needs metadata or server behavior; do not place route HTML in `index.py`.
|
|
512
524
|
- Keep route-specific backend logic in the route's own `index.py`; extract to `src/lib/**` only for genuinely shared logic.
|
|
513
|
-
- Keep visible page markup in `index.html` and shared subtree shells in `layout.html`; do not place route HTML in `index.py` or layout HTML in `layout.py`.
|
|
514
|
-
-
|
|
525
|
+
- Keep visible page markup in `index.html` and shared subtree shells in `layout.html`; do not place route HTML in `index.py` or layout HTML in `layout.py`.
|
|
526
|
+
- Keep `index.html` as a short assembly of focused `x-*` components. When a route area has its own responsibility, such as a tab panel, settings form, data table, toolbar, or metric section, create a component for that area and pass route data into it as props.
|
|
527
|
+
- Use PulsePoint as the first-party interaction model for route and layout HTML. Avoid custom DOM wiring for normal events and reactivity.
|
|
515
528
|
- When the user asks for a dashboard, admin area, account section, or any grouped subtree of child routes, create a parent folder with `layout.html` and place the child routes beneath it. Follow the same mental model as the Next.js App Router.
|
|
516
529
|
- Use a normal folder such as `dashboard/` when the segment should appear in the URL. Use `(group)/` only when the folder should organize or wrap child routes without adding a path segment.
|
|
517
530
|
- Use [cache.md](./cache.md) when an `index.py` route should opt into page-level HTML caching.
|