Repository navigation
Description
Task
Extract the reusable Leptos functionality currently in crates/framework/framework-ui into crates/leptos, and make framework-view consume that library through explicit optional integration.
The intended package name is stackpress-leptos (stackpress_leptos in Rust), distinct from the upstream leptos dependency. Final public module/feature/facade names should be frozen at the design checkpoint.
The goal is to let another Leptos project use the components and reusable rendering functionality without adopting Stackpress's application host, view plugin, page protocol or persistence model.
Related: #14 (framework plugin integration), #15 (preferences consolidation into view), #16 (server-family paths).
Current behavior and evidence
Baseline: remote trial/3 at 74319ac366f3397b684ee5fa8007651c19e54292; the UI/view sources cited here match the inspected local checkout.
- UI manifest directly depends on view; its
ssrfeature enablesstackpress-framework-view/server. - Renderer uses view-specific page snapshots, contracts, limits, assets, errors and renderer traits.
- Routing consumes/re-exports view's route catalog and location types.
- Display helpers also expose view types/errors, so decoupling requires more than moving the main renderer.
- UI state already has reusable root-scoped theme/notification behavior with explicit values and no persistence.
- Admin manifest and numerous examples consume the old UI crate/features.
Simply relocating the existing code and reversing the dependency would create an invalid cycle:
framework-view → stackpress-leptos → framework-view
Target dependency direction
Arrows mean "depends on":
Independent Leptos application ──────────→ stackpress-leptos → upstream Leptos
Stackpress application → framework-view ────────────↑
stackpress-leptos must have no dependency back to framework-view, stackpress-server, the root facade or framework preference/SQL/schema/admin integration. Generic UI consumes explicit values/callbacks rather than reaching into Stackpress services or persistence.
Responsibility split
| crates/leptos | framework-view |
|---|---|
| Reusable components/layouts and reactive contexts | Stackpress page/plugin registration |
| Generic formatting and sanitized rich content | Public page snapshots/assets/status/location contracts |
| Generic Leptos rendering/resource machinery where independently useful | Adapters implementing Stackpress renderer contracts |
| Generic navigation/display primitives | Compiled Stackpress route-catalog adapter |
| Appropriate SSR/hydrate/CSR support | Optional selection of Leptos implementation and host lifecycle integration |
Audit synchronous, async and streaming renderers/replay individually. Move protocol-specific wrappers into view; avoid rewriting mature rendering machinery or promising that every current renderer is already generic.
Consumer examples
Proposed future imports, not existing APIs:
// Another Leptos project: no Stackpress host/plugin required.
use stackpress_leptos::components::{Input, Popover};// Stackpress application: host integration stays in the view feature.
// Proposed entry point coordinated with #14:
app.plugin("views", stackpress_framework_view::plugin::register)?;A native consumer manifest could select the library independently:
[dependencies]
leptos = { version = "=0.8.22", default-features = false, features = ["ssr"] }
[dependencies.stackpress-leptos]
path = "../rust/crates/leptos"
default-features = false
features = ["ssr"]The path is illustrative for an external project alongside the checkout. Publication/crates.io availability is not assumed. Build hydrate/CSR consumers separately.
Acceptance criteria
- Freeze the module/API/feature migration map, including render/replay ownership, safe navigation types, and compatibility decisions.
- Establish
crates/leptosas the reusable library and remove its dependency on framework-view/server and other Stackpress host/persistence integration. - Move Stackpress-specific page/route/render adapters into framework-view. Leptos integration is optional; page contracts remain available without acquiring the Leptos dependency.
- Provide direct component/library use and ordinary view-plugin integration; importing a UI library never registers routes/services or starts listeners.
- Preserve component behavior, accessibility, CSS/assets, public page/seed compatibility, hydration, rendering limits, cancellation and stream ownership. Document deliberate Rust API changes; do not silently weaken validation.
- Add a minimal independent consumer with no view/server dependency. Prove native SSR and separate WASM hydrate/CSR use, plus feature-specific proofs for moved async/stream/rich/format behavior as applicable.
- Update root workspace/facade/features, framework-admin dependencies and generated import templates, examples, build/proof scripts, fixtures, docs and live architecture records. Coordinate Consolidate framework-preferences into framework-view with optional presentation plugins #15 and Group server crates under crates/server/server and crates/server/http #16 paths.
- Verify selected normal dependency graphs: independent UI excludes Stackpress host/view/persistence/generation; view without Leptos features excludes Leptos; browser graphs exclude native services.
- Run meaningful behavior tests, doctests and the required three review/refactoring rounds. Report the existing development/publication coverage policy and actual platform limitations.
Scope boundaries
No new plugin framework, runtime loading, visual redesign, dependency/toolchain upgrades, renderer-default widening, publication or deployment. Keep mutually exclusive SSR/hydrate/CSR builds separate. Existing streaming remains opt-in and does not become part of the default view plugin.
This is an extraction and integration task, not a path-only rename. #15 still puts host-owned preference selection/persistence in view; reusable theme/language/notification contexts belong in the independent library.
Activity
cblanquera commentedon Oct 27, 2026
Suggested implementation approach
The direction is to extract the reusable library and make view the integration owner. The symbols and features below are design sketches, not existing compile-verified APIs.
1. Inventory dependencies before moving files
Classify every current UI module:
crates/leptos.Search source and public signatures, including display helpers. Replacing only the manifest dependency would leave types such as
PublicLocationandViewErrorleaking into the reusable API.Keep one authority for shared safety rules. For example, locate a genuinely generic safe-href value/parser at the lower layer if both layers need it, then adapt Stackpress locations explicitly. Do not replace checked locations with arbitrary strings or copy subtly different validators into both crates.
2. Let view own the adapter wrapper
An illustrative synchronous adapter design:
Its
PageRenderer<T>implementation should validate the existing page contract, adapt public page data into component input, call the generic renderer, then perform the existing seed/asset/HTML-limit processing in the proper order. Preserve current head evaluation, escaping and error precedence; do not assume these can be reordered safely.The reusable renderer should use its own generic errors/options and component output. It must not expose
PageSnapshot,PageContractorViewError.Audit async/streaming separately: preserve request-local Owner lifetime, Send boundaries, cancellation, bounded buffering, replay compatibility and opt-in defaults. Existing internal worker/runtime supervision is not permission to create an additional layer of detached rendering tasks.
3. Use optional integration features without reverse edges
Illustrative view manifest fragment:
Retain view's existing optional
serverdefinition and target gating. These proposed names require a feature matrix review. In the extracted library,ssrmust no longer forward toframework-view/server. Its only Stackpress identity should be package ownership; it is a normal library, not a mandatory host plugin.Keep upstream
leptosdistinct fromstackpress-leptos, and decide facade aliases explicitly. Map old rootframework-ui-*features deliberately rather than silently changing which layer they select. Never use one all-features build to combine mutually exclusive render modes.4. Adapt preferences from view to generic reactive values
Keep #15's persistence and host-policy work in view. Let the reusable library receive explicit initial values and callbacks.
For example, the existing
ThemeStateconcept can retain its generic behavior:A view adapter maps its persistent
ThemePreferenceinto this UI value. That mapping should be exhaustive, including System, and preserve before-paint/hydration agreement. It should not givestackpress-leptosaccess to cookie parsing, native file stores or view'sPreferencestype.Use the same direction for locale/dictionaries, flash-to-notification display and allowed-action hints. Actual authorization remains at the host operation boundary even when the view plugin is absent.
5. Migrate consumers and prove independent use
Update framework-admin plus all generated import/feature templates before regenerating owned output. Existing gallery/shared examples are not sufficient independence evidence if they still depend on view/language/application contracts.
Create a small consumer outside the application graph, with its own selected build modes, depending on upstream Leptos and the new library only. Prove real component rendering/interaction, not just successful imports.
Suggested checks:
These commands assume the fixture defines the illustrated forwarding features. Use a separate CSR build too, and browser behavior proofs for actual hydration/interaction. Native test coverage is not numeric WASM coverage.
A temporary old-package shim may re-export the lower library and, if necessary, view adapters. Neither new owner may depend back on that shim. Document a removal plan and exact API paths rather than preserving a cycle.
6. Coordinate staged work
Agree the shared dependency/module map with #15 before editing; both touch locale/theme/presentation ownership. Implement the acyclic extraction first, adapt view, migrate callers and validate parity. Align #14's plugin entry points with this resulting boundary and #16's actual server dependency paths.
Complete review rounds for complexity, responsibility/abstraction and consistency/Rustdoc. Validate preserved page snapshots/HTML, mounted routing, UI accessibility, cancellation and opt-in streaming. Report native/browser/packaged target evidence separately. No development listener, package publication or dependency upgrade is required by this task.
Add issue #17 design checkpoint (stackpress-leptos extraction)
Record G41: issue #17 removes stackpress-framework-ui outright; each …
Extract stackpress-leptos and make framework-view's Leptos integratio…
Record issue #17 part 1 as verified and merged
Add an independent stackpress-leptos consumer, graph audits and libra…
Record issue #17 part 2 as verified and merged
Review rounds for issue #17 (part 3)
Clarify the facade's leptos feature docs (issue #17 review round 3)
Record issue #17 part 3 as verified and merged