caspian-utils 0.1.15 → 0.1.17
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
|
@@ -264,6 +264,7 @@ Rules for inline `html(...)`:
|
|
|
264
264
|
- The single-root rule still applies: exactly one top-level element with any `<script>` nested inside it.
|
|
265
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
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
|
+
- Component attributes are props regardless of the value type. Kebab-case names become camel-cased in `pp.props`, so callbacks may be authored as `on-open-change="{setOpen}"`, `open-change="{setOpen}"`, or `select-first="{selectFirst}"` according to the component API. The `on-` prefix is conventional, not required. Lowercase native DOM event attributes such as `onclick` and `oninput` remain events on the boundary element; use `on-click` only when the component API intentionally exposes an `onClick` prop.
|
|
267
268
|
- 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
269
|
- A `children` value is auto-marked safe (parity with `render_html(...)`), so `{{ children }}` renders nested component markup correctly without `| safe`.
|
|
269
270
|
- 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(...)`.
|
|
@@ -412,8 +413,27 @@ Do not create a single `AccountPage.py` or `DashboardTabs.py` that contains ever
|
|
|
412
413
|
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
|
|
|
414
415
|
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.
|
|
415
|
-
|
|
416
|
-
##
|
|
416
|
+
|
|
417
|
+
## Component Root Refs
|
|
418
|
+
|
|
419
|
+
`pp-ref` on an `x-*` tag is a parent-owned component ref. It resolves in the scope that authored the component tag and binds to the component's rendered root DOM element. Generated component kits that accept `**props` and spread unknown attributes need no `forwardRef` wrapper and should not special-case `pp-ref`.
|
|
420
|
+
|
|
421
|
+
```html
|
|
422
|
+
<div>
|
|
423
|
+
<x-input pp-ref="{codeInput}" />
|
|
424
|
+
<button onclick="codeInput.current?.focus()">Focus code</button>
|
|
425
|
+
|
|
426
|
+
<script>
|
|
427
|
+
const codeInput = pp.ref(null);
|
|
428
|
+
</script>
|
|
429
|
+
</div>
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
For ref purposes, a component's root is the single native element that receives its injected `pp-component` boundary. If a composition component renders another `x-*` component as its root, Caspian forwards the ref through its layout-neutral boundary host to the eventual concrete DOM root.
|
|
433
|
+
|
|
434
|
+
The default takes precedence over catch-all `**props`: `pp-ref` is reserved for root ref forwarding and is not delivered in that dictionary. A component that intentionally wants `pp-ref` as ordinary data can opt out by declaring an explicit camel-case `ppRef` parameter, for example `def Inspector(ppRef="", **props)`. That explicit declaration consumes the prop, disables automatic root forwarding for that component invocation, and makes the component responsible for how the value is used. Use this escape hatch sparingly; ordinary UI primitives should keep the standard root-ref contract.
|
|
435
|
+
|
|
436
|
+
## Auto-Injected `pp-component` And PulsePoint Script Type
|
|
417
437
|
|
|
418
438
|
Treat `pp-component="componentName"` and `type="text/pp"` as framework output, not authored source. The canonical authored-vs-runtime explanation lives in [pulsepoint.md](./pulsepoint.md).
|
|
419
439
|
|
|
@@ -36,7 +36,7 @@ If an inspected browser DOM disagrees with authored template source, remember th
|
|
|
36
36
|
| Template expressions | text and attributes with `{...}` | `pp-reactive-v2.js` | top-level script bindings are exported, nested bindings are not assumed |
|
|
37
37
|
| State | `pp.state(initial)` | `pp-reactive-v2.js` | setters accept values or updater functions, state belongs to the component instance |
|
|
38
38
|
| Effects | `pp.effect(...)`, `pp.layoutEffect(...)` | `pp-reactive-v2.js` | callbacks may return cleanup functions, promises are not awaited |
|
|
39
|
-
| Refs | `pp.ref(...)`, `pp-ref` | `pp-reactive-v2.js` |
|
|
39
|
+
| Refs | `pp.ref(...)`, `pp-ref` on native or `x-*` tags | `components_compiler.py`, `TemplateCompiler.ts`, `Component.ts`, `RefBindingManager.ts`, shipped in `pp-reactive-v2.js` | component-tag refs are reserved by the Python compiler, stamped with runtime-owned `pp-ref-owner`, captured in the parent's scope, and bound to the child's concrete root; do not author `data-pp-ref`, `pp-ref-owner`, or `pp-ref-forward`; callback refs may return synchronous cleanup functions that run on replacement or detach |
|
|
40
40
|
| Context | `pp.createContext(...)`, lowercase `<themecontext.provider>`, `pp.context(token)` | `TemplateCompiler.ts`, `NestedBoundaryManager.ts`, `pp-reactive-v2.js` | authored provider tags are HTML-first and lowercase; `TemplateCompiler.transformContextProviderTags(...)` rewrites `*.provider` to runtime-owned `pp-context-provider`; ancestry is logical component ancestry; do not invent `pp-context` or `pp.provideContext` |
|
|
41
41
|
| Portals | `pp.portal(ref, target?)` | `pp-reactive-v2.js` | context should preserve logical ancestry through the registry |
|
|
42
42
|
| Lists | `<template pp-for="item in items">` | `pp-reactive-v2.js` | `pp-for` belongs on `<template>`, accepts arrays and synchronous iterables, captures rendered row values for events/props, and uses plain `key`, not `pp-key` |
|
package/dist/docs/pulsepoint.md
CHANGED
|
@@ -419,7 +419,8 @@ Notes:
|
|
|
419
419
|
|
|
420
420
|
- The global `pp` singleton auto-mounts once the runtime is loaded and the DOM is ready. Manual `pp.mount()` is still safe because it short-circuits after the first mount.
|
|
421
421
|
- `pp.state` setters accept either a value or an updater function.
|
|
422
|
-
- `pp.effect` and `pp.layoutEffect` are cleanup-style hooks. They may return only a synchronous cleanup function; returning a promise warns and is ignored, so start async work inside the effect instead.
|
|
422
|
+
- `pp.effect` and `pp.layoutEffect` are cleanup-style hooks. They may return only a synchronous cleanup function; returning a promise warns and is ignored, so start async work inside the effect instead.
|
|
423
|
+
- A function used through `pp-ref` may return a synchronous cleanup function. PulsePoint runs it when that callback ref is replaced or detached; callbacks that do not return cleanup retain the legacy `callback(null)` detach behavior.
|
|
423
424
|
- `pp.portal(ref)` defaults to `document.body` when no target is provided.
|
|
424
425
|
- Older docs may call the RPC helper `pp.fetchFunction()`. In the current bundled runtime the implemented global API is `pp.rpc()`.
|
|
425
426
|
- Keep template-facing bindings at the top level so the AST-based exporter can see them.
|
|
@@ -588,18 +589,20 @@ Nested components:
|
|
|
588
589
|
## Template expressions and attributes
|
|
589
590
|
|
|
590
591
|
- Use `{expression}` in text nodes and attribute values.
|
|
592
|
+
- Follow HTML-first attribute naming. Native event attributes are lowercase DOM event attributes (`onclick`, `oninput`, `onsubmit`). Every other attribute on a component boundary is a prop: kebab-case names become camel-cased only inside `pp.props` (`selected-value` becomes `selectedValue`, `open-change` becomes `openChange`, and `on-open-change` becomes `onOpenChange`). A function prop does not need an `on-` prefix; that prefix is only an API naming convention. Use `on-click` when a component intentionally exposes an `onClick` prop, because lowercase `onclick` is reserved for the native DOM event on the boundary element.
|
|
591
593
|
- Pure bindings like `value="{count}"` are evaluated as expressions.
|
|
592
594
|
- For dynamic inline styles in authored templates, prefer `pp-style="{styleText}"` over `style="{styleText}"` so HTML/CSS tooling does not parse the brace expression as raw CSS.
|
|
593
595
|
- `pp-style` is an authoring alias. The compiler rewrites it to a native `style` attribute in rendered output.
|
|
594
596
|
- If the same element already has a static `style` attribute, `pp-style` is merged into that `style` value during compilation.
|
|
595
597
|
- Mixed text like `class="card {isActive ? 'active' : ''}"` is supported.
|
|
596
|
-
- Arrays in template expressions are joined without commas.
|
|
597
|
-
- `null`, `undefined`, and boolean expression results render as an empty string in text output.
|
|
598
|
-
- Plain objects, functions, and symbols are invalid template children; the runtime warns and omits them instead of rendering accidental strings such as `[object Object]`.
|
|
598
|
+
- Arrays in template expressions are joined without commas.
|
|
599
|
+
- `null`, `undefined`, and boolean expression results render as an empty string in text output.
|
|
600
|
+
- Plain objects, functions, and symbols are invalid template children; the runtime warns and omits them instead of rendering accidental strings such as `[object Object]`.
|
|
599
601
|
- Supported boolean attributes are normalized so truthy values emit the bare attribute and falsy values remove it.
|
|
602
|
+
- Boolean expressions bound to string-valued attributes such as `aria-pressed`, `aria-expanded`, and `data-*` serialize as the literal strings `"true"` and `"false"`, including on nested component boundaries.
|
|
600
603
|
- `<textarea value="{draft}"></textarea>` is normalized into textarea content.
|
|
601
604
|
- Use `pp-spread="{...attrs}"` to spread an object expression into attributes.
|
|
602
|
-
- `pp-spread` omits nullish values, omits known HTML boolean attributes when their value is `false`, emits them bare when `true`, preserves string-valued `aria-*`/`data-*` booleans, and escapes `&`, `"`, and `<` in emitted attribute values.
|
|
605
|
+
- `pp-spread` omits nullish values, omits known HTML boolean attributes when their value is `false`, emits them bare when `true`, preserves string-valued `aria-*`/`data-*` booleans, and escapes `&`, `"`, and `<` in emitted attribute values.
|
|
603
606
|
- Use plain `key` for keyed diffing. `pp-key` is not implemented.
|
|
604
607
|
|
|
605
608
|
Example:
|
|
@@ -633,11 +636,14 @@ The render pipeline wraps each top-level `pp-component` root in an inert `<templ
|
|
|
633
636
|
## Refs
|
|
634
637
|
|
|
635
638
|
- Refs are for imperative element access. Do not use `pp-ref` as the default way to read normal form input values on submit; prefer the form's `onsubmit` event plus `Object.fromEntries(new FormData(event.currentTarget).entries())`.
|
|
636
|
-
-
|
|
637
|
-
- Use `pp-ref="
|
|
639
|
+
- `pp-ref` works on native elements and on `x-*` component tags. On a component tag it resolves in the parent's scope and binds to the component's concrete root DOM element, so `<x-input pp-ref="{nameInput}" />` exposes the rendered `<input>` without a wrapper or `querySelector(...)`.
|
|
640
|
+
- Use the bare-name form, such as `pp-ref="nameInput"`, when the ref object or callback is already available under that name in scope. The runtime resolves this form by scope lookup.
|
|
641
|
+
- Use the brace-expression form, such as `pp-ref="{nameInput}"`, `pp-ref="{registerRef(id)}"`, or `pp-ref="{el => setNode(el)}"`, when the compiler should capture an expression. This is the preferred general form for component tags and dynamic or callback expressions.
|
|
638
642
|
- `pp.ref(null)` is the normal way to create a ref object.
|
|
639
643
|
- Callback refs and `{ current }` refs are both supported.
|
|
640
644
|
- Captured brace-form refs are compiled into an internal `data-pp-ref` token and rebound after render.
|
|
645
|
+
- Component refs are attached before layout effects and passive effects run, and detach with `null` (or a callback's returned synchronous cleanup) when the owning element unmounts.
|
|
646
|
+
- A composition component whose root is another `x-*` component forwards the ref through Caspian's layout-neutral component hosts to the eventual concrete DOM root.
|
|
641
647
|
- Plain `pp-ref` bindings are preserved across rerenders, including no-op rerenders that skip DOM diffing.
|
|
642
648
|
- Ref callbacks may be called with `null` during cleanup.
|
|
643
649
|
- The runtime generates `data-pp-ref` internally. Do not author it.
|
|
@@ -656,13 +662,26 @@ Example:
|
|
|
656
662
|
</div>
|
|
657
663
|
```
|
|
658
664
|
|
|
665
|
+
Component example:
|
|
666
|
+
|
|
667
|
+
```html
|
|
668
|
+
<div>
|
|
669
|
+
<x-input pp-ref="{nameInput}" name="name" />
|
|
670
|
+
<button onclick="nameInput.current?.focus()">Focus</button>
|
|
671
|
+
|
|
672
|
+
<script>
|
|
673
|
+
const nameInput = pp.ref(null);
|
|
674
|
+
</script>
|
|
675
|
+
</div>
|
|
676
|
+
```
|
|
677
|
+
|
|
659
678
|
## Lists and keyed diffing
|
|
660
679
|
|
|
661
680
|
- Use `pp-for` only on `<template>`.
|
|
662
681
|
- Supported forms are `item in items` and `(item, index) in items`.
|
|
663
|
-
- Collections may be arrays or synchronous iterables such as `Set`, `Map`, typed arrays, strings, and generators. Non-null non-iterable values warn and render as empty lists.
|
|
682
|
+
- Collections may be arrays or synchronous iterables such as `Set`, `Map`, typed arrays, strings, and generators. Non-null non-iterable values warn and render as empty lists.
|
|
664
683
|
- Loop content can contain interpolations, events, refs, and nested components.
|
|
665
|
-
- Event handlers inside loops capture each rendered item, so later collection changes do not retarget an existing row handler.
|
|
684
|
+
- Event handlers inside loops capture each rendered item, so later collection changes do not retarget an existing row handler.
|
|
666
685
|
- Use stable unique `key` values on repeated sibling elements.
|
|
667
686
|
- Duplicate keys trigger warnings and reduce diff quality.
|
|
668
687
|
- Keyed reconciliation preserves DOM identity across reorders and insertions.
|
|
@@ -719,9 +738,9 @@ Example:
|
|
|
719
738
|
- Push navigation resets window scroll to the top.
|
|
720
739
|
- Saved history-entry scroll state is used during history traversal instead of relying only on the live DOM scroll at the time the user clicks Back or Forward.
|
|
721
740
|
- Unmarked scrollable containers may keep their outgoing scroll on push navigation so shared shells such as sidebars, rails, and docs nav panes stay stable across child-route changes.
|
|
722
|
-
- `pp-reset-scroll="true"` on a scroll container opts that container into reset-on-navigation behavior. Use it on the main content pane of a grouped shell when page content should start at the top on each child-route navigation.
|
|
723
|
-
- `pp-scroll-key="stable-name"` gives a scroll container a stable restoration identity. Prefer it when an element has no stable `id`, or when its classes or position can change between routes.
|
|
724
|
-
- `body[pp-reset-scroll="true"]` is the global override for routes that should reset window scroll and every scrollable element.
|
|
741
|
+
- `pp-reset-scroll="true"` on a scroll container opts that container into reset-on-navigation behavior. Use it on the main content pane of a grouped shell when page content should start at the top on each child-route navigation.
|
|
742
|
+
- `pp-scroll-key="stable-name"` gives a scroll container a stable restoration identity. Prefer it when an element has no stable `id`, or when its classes or position can change between routes.
|
|
743
|
+
- `body[pp-reset-scroll="true"]` is the global override for routes that should reset window scroll and every scrollable element.
|
|
725
744
|
- Navigation dispatches `pp:navigation:start`, `pp:navigation:complete`, and `pp:navigation:error` events on `document`.
|
|
726
745
|
|
|
727
746
|
RPC notes:
|
|
@@ -864,6 +883,7 @@ These are current runtime caveats that matter for authors and AI tools:
|
|
|
864
883
|
- Nested roots without their own `script[type="text/pp"]` block are not fully isolated during parent template compilation.
|
|
865
884
|
- The global `pp` singleton auto-mounts on DOM ready, and `pp.mount()` is idempotent.
|
|
866
885
|
- `pp.effect` and `pp.layoutEffect` are cleanup-style hooks. Their callbacks are not promise-aware.
|
|
886
|
+
- Callback refs may return synchronous cleanup functions, which run instead of a later `callback(null)` detach call.
|
|
867
887
|
- `pp.context()` resolves through ancestor components, not the current component's own pending providers.
|
|
868
888
|
- `pp.provideContext` is not part of the current runtime API. Use an HTML-first lowercase provider tag such as `<themecontext.provider>`.
|
|
869
889
|
- `pp.portal()` preserves logical ancestry through the registry, so context and prop refresh behavior continue to work through portaled descendants.
|