caspian-utils 0.0.18 → 0.0.20
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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Components
|
|
3
|
-
description: Use this page when the task mentions `@component`, reusable UI, component imports, same-name `.html` templates, or where shared components belong in a Caspian project.
|
|
3
|
+
description: Use this page when the task mentions `@component`, reusable UI, HTML-first `x-*` component tags, component imports, same-name `.html` templates, `merge_classes(...)`, `twMerge(...)`, or where shared components belong in a Caspian project.
|
|
4
4
|
related:
|
|
5
5
|
title: Related docs
|
|
6
6
|
description: Use the structure guide for file placement, the routing guide for route templates, the PulsePoint guide for browser-side scripts, and the data guide for component-owned RPC flows.
|
|
@@ -12,9 +12,11 @@ related:
|
|
|
12
12
|
- /docs/index
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
-
Components in Caspian are Python functions decorated with `@component`.
|
|
15
|
+
Components in Caspian are implemented as Python functions decorated with `@component`.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
In authored HTML, import them with an `@import` comment and render them with HTML-first kebab-cased `x-*` tags such as `<x-my-component />` or `<x-my-component>...</x-my-component>`.
|
|
18
|
+
|
|
19
|
+
Treat that `x-*` form as the current Caspian component contract for authored templates.
|
|
18
20
|
|
|
19
21
|
Component tooling scans Python files under the paths listed in `caspian.config.json`. When `componentScanDirs` includes `src/`, `src/components/` is the clean default location for reusable UI, even though any scanned path can work.
|
|
20
22
|
|
|
@@ -29,7 +31,7 @@ As the app grows, treat `src/components/` as the default home for reusable appli
|
|
|
29
31
|
|
|
30
32
|
## Basic Component
|
|
31
33
|
|
|
32
|
-
This is the simplest pattern: accept props,
|
|
34
|
+
This is the simplest pattern: accept props, assemble the final class value, and return HTML.
|
|
33
35
|
|
|
34
36
|
```python
|
|
35
37
|
from casp.component_decorator import component
|
|
@@ -51,7 +53,44 @@ Notes:
|
|
|
51
53
|
|
|
52
54
|
- `children` receives the inner content passed between opening and closing tags.
|
|
53
55
|
- `**props` lets the component accept additional HTML attributes such as `id`, `data-*`, and `aria-*`.
|
|
54
|
-
- The runtime normalizes `class`, `className`, and `class_name` into
|
|
56
|
+
- The runtime normalizes `class`, `className`, and `class_name` into one `class` value before the component is called.
|
|
57
|
+
- Pass the `merge_classes(...)` result straight into `get_attributes(...)` or the rendered `class` attribute; do not wrap it in another helper.
|
|
58
|
+
|
|
59
|
+
## Tailwind Merge Contract
|
|
60
|
+
|
|
61
|
+
When `caspian.config.json` has `tailwindcss: true`, Caspian uses a frontend-first Tailwind merge contract.
|
|
62
|
+
|
|
63
|
+
- In Python components, use `merge_classes(...)` to assemble class defaults plus incoming class props.
|
|
64
|
+
- `merge_classes(...)` emits a frontend-ready `{twMerge(...)}` expression instead of doing Python-side Tailwind conflict resolution.
|
|
65
|
+
- In authored PulsePoint markup and scripts, use global `twMerge(...)` directly for attribute expressions and script-local derived values.
|
|
66
|
+
|
|
67
|
+
Python example:
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from casp.component_decorator import component
|
|
71
|
+
from casp.html_attrs import get_attributes, merge_classes
|
|
72
|
+
|
|
73
|
+
@component
|
|
74
|
+
def IconButton(**props) -> str:
|
|
75
|
+
incoming_class = props.pop("class", "")
|
|
76
|
+
final_class = merge_classes("size-4 rounded-md", incoming_class)
|
|
77
|
+
|
|
78
|
+
attributes = get_attributes({
|
|
79
|
+
"class": final_class,
|
|
80
|
+
}, props)
|
|
81
|
+
|
|
82
|
+
return f'<button {attributes}></button>'
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Authored PulsePoint examples:
|
|
86
|
+
|
|
87
|
+
```html
|
|
88
|
+
<p class="{twMerge(baseClass, inputClass)}">Merged badge preview</p>
|
|
89
|
+
|
|
90
|
+
<script>
|
|
91
|
+
const merged = twMerge(baseClass, inputClass);
|
|
92
|
+
</script>
|
|
93
|
+
```
|
|
55
94
|
|
|
56
95
|
## Import And Use Components
|
|
57
96
|
|
|
@@ -60,17 +99,17 @@ Place component imports at the top of the HTML template, above the authored root
|
|
|
60
99
|
```html
|
|
61
100
|
<!-- @import Container from "../components" -->
|
|
62
101
|
|
|
63
|
-
<
|
|
102
|
+
<x-container class="py-10">
|
|
64
103
|
<h1>Dashboard</h1>
|
|
65
|
-
</
|
|
104
|
+
</x-container>
|
|
66
105
|
```
|
|
67
106
|
|
|
68
|
-
The import comment is the bridge between the Python component
|
|
107
|
+
The import comment is the bridge between the Python component export and the `x-*` tag you author in HTML.
|
|
69
108
|
|
|
70
109
|
Treat `<!-- @import ... -->` as a file-level directive, not as rendered markup. It does not count as the template root, and it should not be nested inside the root wrapper element.
|
|
71
110
|
|
|
72
111
|
- `<!-- @import Container from "../components" -->` resolves `Container.py` from that folder.
|
|
73
|
-
- The component
|
|
112
|
+
- 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 />`.
|
|
74
113
|
- Grouped imports and aliases are also supported, for example `<!-- @import { Button, Card as UserCard } from "../components/ui" -->`.
|
|
75
114
|
- If one Python file exports several `@component` functions, point `from` at that exact file instead of assuming one file per tag.
|
|
76
115
|
- In that case, prefer one grouped import so every rendered tag resolves back to the same Python module.
|
|
@@ -81,9 +120,9 @@ Good:
|
|
|
81
120
|
<!-- @import { Button, Input, Label } from "../../../lib/maddex" -->
|
|
82
121
|
|
|
83
122
|
<section class="auth-panel auth-panel-compact fade-up">
|
|
84
|
-
<
|
|
85
|
-
<
|
|
86
|
-
<
|
|
123
|
+
<x-label>Email</x-label>
|
|
124
|
+
<x-input type="email" />
|
|
125
|
+
<x-button>Continue</x-button>
|
|
87
126
|
</section>
|
|
88
127
|
```
|
|
89
128
|
|
|
@@ -106,17 +145,17 @@ If `Breadcrumb.py` defines `Breadcrumb`, `BreadcrumbList`, `BreadcrumbItem`, `Br
|
|
|
106
145
|
<!-- @import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from "../maddex/Breadcrumb.py" -->
|
|
107
146
|
|
|
108
147
|
<div class="dashboard-topbar">
|
|
109
|
-
<
|
|
110
|
-
<
|
|
111
|
-
<
|
|
112
|
-
<
|
|
113
|
-
</
|
|
114
|
-
<
|
|
115
|
-
<
|
|
116
|
-
<
|
|
117
|
-
</
|
|
118
|
-
</
|
|
119
|
-
</
|
|
148
|
+
<x-breadcrumb class="dashboard-breadcrumbs" aria-label="Dashboard breadcrumbs">
|
|
149
|
+
<x-breadcrumb-list class="dashboard-breadcrumbs__list">
|
|
150
|
+
<x-breadcrumb-item class="dashboard-breadcrumbs__item">
|
|
151
|
+
<x-breadcrumb-link href="/dashboard">Dashboard</x-breadcrumb-link>
|
|
152
|
+
</x-breadcrumb-item>
|
|
153
|
+
<x-breadcrumb-separator class="dashboard-breadcrumbs__separator" />
|
|
154
|
+
<x-breadcrumb-item class="dashboard-breadcrumbs__item">
|
|
155
|
+
<x-breadcrumb-page class="dashboard-breadcrumbs__page">Reports</x-breadcrumb-page>
|
|
156
|
+
</x-breadcrumb-item>
|
|
157
|
+
</x-breadcrumb-list>
|
|
158
|
+
</x-breadcrumb>
|
|
120
159
|
</div>
|
|
121
160
|
```
|
|
122
161
|
|
|
@@ -317,7 +356,7 @@ Keep synchronous components as the default. Switch to `async def` only when the
|
|
|
317
356
|
|
|
318
357
|
- Put reusable components in `src/components/` and keep route files in `src/app/`.
|
|
319
358
|
- If the component includes PulsePoint behavior, prefer a thin Python wrapper plus a same-name `.html` template.
|
|
320
|
-
- Keep the component file name, exported function name, and tag
|
|
359
|
+
- Keep the component file name, exported function name, and authored tag aligned, such as `Button.py`, `def Button(...)`, and `<x-button />`.
|
|
321
360
|
- Accept `children` or `**props` when the component should support nested content.
|
|
322
361
|
- Keep page-level data loading in `page()` when the data is not intrinsic to the component itself.
|
|
323
362
|
- If you add `@rpc()` functions inside a component file, keep their names globally unique because component RPCs are not route-scoped.
|
package/dist/docs/index.md
CHANGED
|
@@ -26,6 +26,7 @@ Before making feature, tooling, or file-placement decisions in a Caspian project
|
|
|
26
26
|
When generating or editing a Caspian app, treat these as the default choices unless the task explicitly requires something else:
|
|
27
27
|
|
|
28
28
|
- Use PulsePoint for reactive frontend behavior.
|
|
29
|
+
- When `caspian.config.json` has `tailwindcss: true`, use Python `merge_classes(...)` plus browser `twMerge(...)` as the only supported Tailwind class-merging path.
|
|
29
30
|
- Use `@rpc()` plus `pp.rpc()` for browser-triggered reads, writes, streaming, and uploads.
|
|
30
31
|
- Use `Validate` and `Rule` from `casp.validate` for server-side input validation and sanitization.
|
|
31
32
|
|
|
@@ -42,8 +43,8 @@ The packaged Caspian docs referenced by this index live here:
|
|
|
42
43
|
- `mcp.md` - MCP-specific layout, launch flow, and AI routing rules for projects where `caspian.config.json` enables MCP
|
|
43
44
|
- `database.md` - Prisma schema, migration, seed, and client-generation workflow for projects where `caspian.config.json` enables Prisma, plus Python-side helper caveats
|
|
44
45
|
- `auth.md` - Session-backed authentication with `casp.auth`, centralized `auth_config.py`, public-vs-private route mode guidance, RPC-first signout guidance, RBAC, and OAuth provider helpers
|
|
45
|
-
- `components.md` - Create reusable Python components, template-backed UI,
|
|
46
|
-
- `pulsepoint.md` - Default reactive frontend runtime contract for component scripts, state, effects, directives,
|
|
46
|
+
- `components.md` - Create reusable Python components, template-backed UI, HTML-first `x-*` component tags, the single-parent root rule for component HTML files, and the Python-side `merge_classes(...)` contract when Tailwind CSS is enabled
|
|
47
|
+
- `pulsepoint.md` - Default reactive frontend runtime contract for component scripts, state, effects, directives, client-side behaviors, and direct browser `twMerge(...)` usage when Tailwind CSS is enabled
|
|
47
48
|
- `fetch-data.md` - Initial server-side data loading and browser-triggered RPC flows with `pp.rpc()`, streaming, uploads, and auth-aware actions
|
|
48
49
|
- `file-uploads.md` - Route-local file uploads and file-manager flows with `@rpc()`, `pp.rpc()`, Prisma metadata, public asset storage, and BrowserSync ignore rules
|
|
49
50
|
- `state.md` - Request-scoped server state with `StateManager`, session-backed JSON persistence, and listener callbacks for transient flows
|
|
@@ -119,9 +119,9 @@ Use this folder for reusable UI components that should be imported into route te
|
|
|
119
119
|
|
|
120
120
|
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/`.
|
|
121
121
|
|
|
122
|
-
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.
|
|
122
|
+
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 />`.
|
|
123
123
|
|
|
124
|
-
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" -->`, instead of assuming each tag has its own sibling `.py` file.
|
|
124
|
+
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.
|
|
125
125
|
|
|
126
126
|
For component HTML files, follow the same one-parent rule as route HTML files: one top-level lowercase HTML element only, with no sibling roots and no top-level script sitting outside that root.
|
|
127
127
|
|
|
@@ -243,7 +243,7 @@ If a route renders UI and needs no backend behavior, this file alone is sufficie
|
|
|
243
243
|
|
|
244
244
|
Treat import comments as top-of-file directives that belong above the route's single authored root element.
|
|
245
245
|
|
|
246
|
-
Use `components.md` when the task involves authoring reusable `<
|
|
246
|
+
Use `components.md` when the task involves authoring reusable `<x-my-component />` tags backed by Python files.
|
|
247
247
|
|
|
248
248
|
### `src/app/globals.css`
|
|
249
249
|
|
|
@@ -278,7 +278,7 @@ If an AI agent is deciding where to make changes, use these rules first.
|
|
|
278
278
|
- As the app grows, keep route-owned code in `src/app/`, reusable rendered UI in `src/components/`, and reusable non-UI support code in `src/lib/`.
|
|
279
279
|
- Read [file-uploads.md](./file-uploads.md) when the task involves upload widgets, media libraries, or file-manager flows.
|
|
280
280
|
- Check [routing.md](./routing.md) when you need URL segment rules, layout nesting behavior, or dynamic route conventions.
|
|
281
|
-
- Put reusable component files in `src/components/` and check [components.md](./components.md) for `@component`, `render_html(__file__)`, import comments, and single-root template rules.
|
|
281
|
+
- 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.
|
|
282
282
|
- 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.
|
|
283
283
|
- 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.
|
|
284
284
|
- Keep `<!-- @import ... -->` comments above the single authored root element in route, layout, and component HTML files.
|
package/dist/docs/pulsepoint.md
CHANGED
|
@@ -16,9 +16,9 @@ related:
|
|
|
16
16
|
|
|
17
17
|
This file documents the PulsePoint contract for the shipped Caspian browser runtime. Treat it as the AI-facing source of truth when generating or reviewing interactive Caspian UI.
|
|
18
18
|
|
|
19
|
-
If a task involves `pp.state`, `pp.effect`, `pp.layoutEffect`, `pp-ref`, `pp-style`, `pp-spread`, `pp-for`, context, portals, SPA navigation, or component boundary behavior, read this page first and keep generated code aligned with the
|
|
19
|
+
If a task involves `pp.state`, `pp.effect`, `pp.layoutEffect`, `pp-ref`, `pp-style`, `pp-spread`, `pp-for`, context, portals, SPA navigation, or component boundary behavior, read this page first and keep generated code aligned with the current Caspian runtime.
|
|
20
20
|
|
|
21
|
-
Use `components.md` for authoring Python `@component` files
|
|
21
|
+
Use `components.md` for authoring Python `@component` files, same-name HTML templates, and HTML-first `x-*` component tags. Use this page for the browser-side PulsePoint contract, the authoring rules that feed it, and the React-style mental model used by the shipped runtime.
|
|
22
22
|
|
|
23
23
|
PulsePoint is the default reactive frontend layer for Caspian. In the current runtime it follows a React-like component pattern, but it is HTML-first rather than JSX-first.
|
|
24
24
|
|
|
@@ -36,6 +36,7 @@ Important current facts:
|
|
|
36
36
|
|
|
37
37
|
- `public/js/pp-reactive-v2.js` exposes the global `pp` runtime and auto-mounts on DOM ready.
|
|
38
38
|
- `main.py` renders the final HTML, runs `transform_components(...)`, then runs `transform_scripts(...)` before returning the response.
|
|
39
|
+
- Authored route and component templates compose reusable server components as HTML-first `x-*` tags before the browser runtime mounts.
|
|
39
40
|
|
|
40
41
|
If docs, generated examples, or older notes disagree with `public/js/pp-reactive-v2.js` plus `main.py`, follow the code that actually runs.
|
|
41
42
|
|
|
@@ -51,7 +52,7 @@ When a Caspian page needs reactive browser behavior, use PulsePoint.
|
|
|
51
52
|
|
|
52
53
|
## Authoring Model
|
|
53
54
|
|
|
54
|
-
PulsePoint authoring
|
|
55
|
+
PulsePoint authoring is split into two layers:
|
|
55
56
|
|
|
56
57
|
- The authored layer: route, layout, and component templates under `src/` with plain HTML plus a plain `<script>`.
|
|
57
58
|
- The runtime layer: the browser sees `pp-component` roots and `script[type="text/pp"]` after Caspian transforms the HTML.
|
package/dist/docs/routing.md
CHANGED
|
@@ -89,7 +89,7 @@ Use `index.html` for the route template. This is the route's view layer.
|
|
|
89
89
|
|
|
90
90
|
If a route renders visible page content, that content belongs here even when the route also has an `index.py` companion.
|
|
91
91
|
|
|
92
|
-
Route templates can import reusable Python components with `<!-- @import ... -->` comments and render them with
|
|
92
|
+
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.
|
|
93
93
|
|
|
94
94
|
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.
|
|
95
95
|
|
|
@@ -130,7 +130,7 @@ Also bad:
|
|
|
130
130
|
```html
|
|
131
131
|
<section class="dashboard-shell">
|
|
132
132
|
<!-- @import StatsCard from "../components" -->
|
|
133
|
-
<
|
|
133
|
+
<x-stats-card title="Users" value="42" />
|
|
134
134
|
</section>
|
|
135
135
|
```
|
|
136
136
|
|
|
@@ -140,7 +140,7 @@ Example authored route template:
|
|
|
140
140
|
<!-- @import StatsCard from "../components" -->
|
|
141
141
|
|
|
142
142
|
<section class="dashboard-shell">
|
|
143
|
-
<
|
|
143
|
+
<x-stats-card title="Users" value="42" />
|
|
144
144
|
|
|
145
145
|
<script>
|
|
146
146
|
const [filter, setFilter] = pp.state("all");
|