description, kind
| description | kind |
|---|---|
| Slot registry pure core for the dsh web client: SlotMap declaration merging, the single register composition API, four-share props types, store seats, and the renderer install contract. | package-library |
@deepseek-ai/dsh-client-ui-slots
English | 中文
Summary
dsh-client-ui-slots is the pure core of the web client's slot system: the type-level contract every UI feature composes through. One register({ name, children?, store?, inject?, ...kind }, Component) call contributes a component into a declared slot and, in the same breath, declares child slots, a store seat, and the registrant's business face. The component is checked at the call site against ComposedProps — the intersection of four shares, each derived from its single source of truth — so a wrong composition fails to compile. Chain-kind slots invert keyed routing: entries self-nominate through a pure selector instead of the dispatch site picking an entryKey. The package is React-free and Cordis-free at runtime (React types only); ui-renderer owns the engine implementation and React bindings.
Table of Contents
- Use this package
- Understand the implementation
- Further Exploration
- Model Experience
- Known Limitations and Deferred Work
- Dev Note
Use this package
Compose UI through this package whenever you write a client plugin: register a component into a slot your parent declared, or declare child slots your component renders. The four kinds cover the composition shapes — single (one occupant), list (ordered entries), keyed (dispatch by a key), and chain (entries elect themselves).
The four props shares
Every registered component receives props composed from four shares: the runtime share (owner from the parent's renderSlot call site, plus the session standard kit and global seat), the child-render share (renderSlot statically narrowed to the declared children keys), the store share (the declared handle's selector hook and draft-stripped actions), and the business share (inferred from the inject factory's return). Components reference ComposedProps; they never re-type a share locally.
Store seats
A register call may declare a store seat with store: defineStore(...): init infers the state schema and actions is the complete draft-transform write set. Components read through the selector hook and write through the baked callbacks; the engine implementation of defineStore lives in the runtime package and satisfies the DefineStore contract exported here.
Declaration discipline
Declaring a slot is claiming it: the registering entry becomes the only entry allowed to render that key, and registering into an undeclared slot, declaring an already-declared child, mounting one shared handle under two scopes, or registering a chain without select throws at load. An entry's disposer collapses its declared child slots recursively — ledger rows, contributions, and store mounts die on one lifecycle axis.
Understand the implementation
Implementation internals — click to expand
The design is one table: declaration = render authorization = runtime spec. SlotMap is declared empty here and merged by consumers via declare module augmentation, exactly like the standard-kit interfaces (SessionStandardProps, GlobalStandardProps), which the runtime package merges with real members.
Registration and routing
SlotCore seeds the a-priori 'root' slot at construction and enforces load-time validation. ChainSelect selectors run in ascending priority order (ties in registration order); the first non-null return elects its entry and becomes the component's matched prop, and all-null falls to the owner's renderSlotChain fallback (ChainRenderOpts). Each key carries a declaration epoch that advances only on declaration and collapse; ui-renderer uses it for ctx.slots.inject, independently from ordinary entry versions.
The renderer contract
renderer.ts carries the installation contract (SlotRenderer, SlotRendererHost) plus StaleAuthorizationError/SlotOwnershipError; ui-renderer owns both the implementation and its plugin-lifecycle installation. Engine products and the renderer host contract carry bare snapshot sources (getSnapshot/subscribe), never React hooks — hook binding belongs to the render machinery.
Further Exploration
These pages cover the engine, the renderer, and the composition model.
- Slot declaration injection decision — the lifecycle rules behind
ctx.slots.inject. - ui-renderer — the React slot renderer implementing this package's install contract.
- Slot system standard — the definitive composition model.
- Web client architecture — the loading chain and object layer this registry plugs into.
Model Experience
None, as the package is a browser-side UI plugin layer that registers nothing model-facing.
KV Cache effect
None; this package neither assembles nor sends a provider request.
Known Limitations and Deferred Work
These limits define the registry's scaling behavior and accepted type noise; they are current package constraints.
isLivescans all records linearly — fine at UI-plugin registration counts (tens); revisit with an entry→record backref if ledgers ever grow hot.- The
__rendersphantom anchor is visible onPropsRenderSlots— the same accepted noise as the type-chain design's__accepts: generic method signatures compare loosely across key unions, so the contravariant marker is what enforces "component key set ⊆ children declaration".
Dev Note
Working context for maintainers — click to expand
None.