# Client-side Integration Design This document describes how to integrate browser-side capabilities with the server-components framework while preserving the core product promise: application code should remain Java-first. The goal is not to turn applications into JavaScript applications. The goal is to keep the always-loaded `js-client` small, then load reusable JavaScript capability modules only when a Java component asks for browser-native behavior such as drag-and-drop, pan/zoom, graph rendering, canvas drawing, FLIP animations, maps, charts, or editor widgets. For the target class of Java business and realtime operational UIs, this project should be sufficient as the only UI dependency for nearly all common production needs. When a block is missing, teams should be able to build it themselves, often with AI assistance, by composing framework primitives rather than introducing a new frontend stack. Third-party JavaScript libraries remain escape hatches for specialized renderers, algorithms, or domains whose complexity is not worth owning in the framework. Target first-party functionality scope: - layout, panels, modals, drawers, tabs - forms, validation, schema-driven editors - tables, filtering, pagination, selection - navigation, routing, auth shells - theming and design tokens - notifications, toasts, command/search palettes - drag/drop, resize, sortable, pan/zoom - standard charts and live graphs - node diagrams and workflows to a solid baseline - animation primitives - accessibility defaults This is a target design. Some primitives already exist (`evalJs`, element references, DOM events, static resources); others are called out below as framework gaps that should be implemented before building serious bridge APIs. ## Current Primitives | API | Purpose | Returns | |-------------------------------------------|------------------------|-----------------------------------| | `ctx.evalJs(code)` | Execute JS on client | `CompletableFuture` | | `ctx.evalJs(code, callback)` | Execute with callback | `void` | | `ctx.propertiesByRef(ref).get(prop)` | Read element property | `CompletableFuture` | | `ctx.propertiesByRef(ref).set(prop, val)` | Write element property | `void` | | `ElementRef` + `elementId(ref)` | Reference DOM element | Server-side handle | | `onAfterRendered()` | Lifecycle hook | Called after DOM exists | Current gaps to close: - `evalJs(...)` supports server to browser execution, but richer capabilities need a reusable resource loader (`ensureScript`, `ensureStylesheet`, cache modes, lifecycle cleanup). - The client exposes a custom callback hook, but the server protocol must route custom browser callbacks into server-side semantic events. - Built-in DOM event payloads are intentionally sparse. Pointer-heavy capabilities should emit semantic events (`dragCommitted`, `nodeMoved`, `edgeCreated`) rather than raw `pointermove` floods. - Application code should not write JavaScript strings directly. JavaScript should be hidden behind Java components, contracts, DSL helpers, and capability descriptors. Recommended implementation order: 1. Add server decoding/routing for semantic custom callbacks. 2. Add `RSP.resources` and `RSP.capabilities` to the client kernel. 3. Add Java resource/capability wrappers so application code does not call `evalJs` directly. 4. Add the common interaction runtime for drag/drop, pan/zoom, selection, and FLIP. 5. Build specific bridges such as maps, live graphs, diagrams, kanban, and editors on top. --- ## Refined Architecture The integration stack should have four layers: ```text Application Java Pure Java contracts, services, components, state records, DSL calls Java capability APIs DiagramView, LiveGraphView, SortableList, DragDrop, Animation, MapView Client capability runtime Resource loading, mount/update/unmount, callbacks, descriptors, interaction registry On-demand JavaScript modules Pointer capture, hit testing, transforms, FLIP, chart/canvas/SVG/library rendering ``` The always-loaded `js-client` remains the kernel: - WebSocket connection and protocol dispatch - DOM patch application - basic DOM event forwarding - `evalJs(...)` - element lookup - resource loading and callback transport Everything richer should be loaded on demand. ## Pure Java Application Contract Application-level code should talk in Java concepts and should not see JavaScript: ```java nodeGraph() .nodes(state.nodes()) .edges(state.edges()) .panZoom(true) .draggableNodes(true) .onNodeMoved(DiagramEvents.NODE_MOVED) .onEdgeCreated(DiagramEvents.EDGE_CREATED); ``` For generic gestures: ```java div( interaction() .draggable() .dropGroup("kanban-card") .commitOnEnd(KanbanEvents.CARD_DROPPED), text(card.title()) ) ``` Under the hood, those Java helpers render normal DOM/SVG/container elements, attach serialized descriptors, ensure the required JavaScript module is loaded, mount the behavior after render, and translate browser gestures into server-side semantic events. ## Common JavaScript Capability Runtime Specific bridges should not each invent pointer handling, callback transport, cleanup, or animation scheduling. A common runtime should provide: - resource loader: `RSP.resources.ensureScript(...)`, `ensureStylesheet(...)`, inline style injection, cache modes - capability registry: mount/update/unmount by component id - callback transport: `RSP.callbacks.emit(name, payload)` - descriptor scanning: find `data-rsp-capability` nodes after server patches - pointer utilities: pointer capture, drag tracking, hit testing, throttling, debouncing - interaction primitives: drag, drop, resize, sortable, selection rectangle, pan/zoom - animation primitives: FLIP measurement, enter/leave/move animations, reduced-motion handling - cleanup: remove listeners, observers, animation frames, and bridge instances when components unmount Specific bridges become thin consumers: | Bridge | Reuses | Adds | |------------------|--------------------------------------|---------------------------------------------| | Diagram | drag, pan/zoom, callbacks, animation | ports, edges, node positions, edge previews | | Sortable list | drag/drop, hit testing | item ordering and placeholders | | Kanban | drag/drop, sortable | columns, lane constraints, card moves | | Live graph/chart | resource loader, animation loop | axes, data buffers, rendering strategy | | Map | loader, callbacks, lifecycle | Leaflet/OpenLayers integration | ## On-Demand Library Loading with Caching ### The Concept Instead of including all libraries in ``, load them on demand when a component first needs them. Application code should not call this directly; capability components do it internally. ```java // Low-level primitive used by a Java capability component. ctx.evalJs(""" RSP.resources.ensureScript('/res/rsp-diagram.js') .then(() => RSP.diagram.mount('diagram-42', descriptor)); """); ``` ### CacheMode Enum ```java public enum CacheMode { NO_CACHE, // Execute every time CACHE, // Cache by script hash, execute once per session CACHE_GLOBAL // Cache globally across sessions (localStorage) } ``` --- ## On-Demand CSS Loading CSS can also be pushed on demand when a component needs it. ### Enhanced API for CSS ```java public interface ClientResources { // Load CSS by URL (cached by URL) CompletableFuture ensureStylesheet(String url); // Load CSS with integrity check CompletableFuture ensureStylesheet(String url, String integrityHash); // Inject inline CSS (cached by hash) CompletableFuture injectCss(String cssId, String css, CacheMode cacheMode); // Remove previously injected CSS CompletableFuture removeCss(String cssId); } ``` ### Client-Side CSS Implementation ```javascript class Client { constructor() { this.loadedStylesheets = new Set(); this.injectedStyles = new Map(); // cssId ->