You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
116 lines
5.9 KiB
116 lines
5.9 KiB
---
|
|
title: ActiveUix — the composition root
|
|
type: reference
|
|
audience: human + agent
|
|
authority: E1 architecture — how UIX boots, which services it owns, and how it degrades
|
|
status: current
|
|
source: migrated from src/uix/active-uix/README.md (2026-07-02, docs-book F7.1)
|
|
---
|
|
|
|
# ActiveUix
|
|
|
|
`active-uix` is UIX's composition root. Its responsibility is not to be another
|
|
behavior layer, but to hand `morfo`, `soma`, `sema` and `eidos` the minimal
|
|
services they need — without components ever knowing `ActiveApp` directly.
|
|
|
|
> **Whole-system architecture**: [`architecture/active-architecture.md`](./active-architecture.md).
|
|
> **Executable contract**: [`src/uix/contracts.ts`](../../src/uix/contracts.ts), validated by
|
|
> [`contracts.test.ts`](../../src/uix/contracts.test.ts).
|
|
|
|
## Two boot modes
|
|
|
|
`createActiveUix(options)` — **standalone**. Composes its own runtime:
|
|
|
|
- creates `logger`, `timers`, `bus` and `prefs`;
|
|
- the `bus` uses `createSvelteEngineBus({ logger, clock: timers.clock })`, same
|
|
as `ActiveApp`, so listeners run under `untrack` and never create accidental
|
|
reactive dependencies;
|
|
- creates `langs`, `dom` (or `disabledDom` when `dom:false`), `clipboard`,
|
|
`format` and `events` according to the options;
|
|
- keeps `portal` as a generic portal target, so each layer adapts it to its own
|
|
API (`portalTo`) without coupling `active-uix` to that layer;
|
|
- registers the common translations and the per-component catalogs from
|
|
`src/uix/langs/components/*`.
|
|
|
|
`attachActiveUix(app, options)` — **attach** to an external `ActiveApp`:
|
|
|
|
- reuses `app.prefs`, `app.langs`, `app.dom`, `app.clipboard` and `app.format`
|
|
when they exist;
|
|
- **requires** `app.langs` and `app.dom`; if either is missing it throws a
|
|
configuration error;
|
|
- does not re-subscribe `langs` to `prefs.language` (that connection belongs to
|
|
`defineActiveLangs` inside `ActiveApp`);
|
|
- registers the common translations and the per-component catalogs;
|
|
- does not own the `app`'s lifecycle.
|
|
|
|
## Minimum contracts per module
|
|
|
|
> Executable source: [`src/uix/contracts.ts`](../../src/uix/contracts.ts).
|
|
|
|
| Module | Minimum required | Optional | Fallback when missing | Error when missing |
|
|
| --- | --- | --- | --- | --- |
|
|
| `ActiveUix` standalone | `langs` config | `clipboard:false`, `format`, `events`, `portal`, `dom:false` | creates `prefs`, core services and, with `dom:false`, a local `disabledDom` | missing `langs` config |
|
|
| `ActiveUix` attach | `ActiveApp` core + `langs`, `dom` services | `app.clipboard`, `app.format`, event engine, `portal` | none for required services | missing `langs` or `dom` on the app; the getter of an absent optional service fails explicitly |
|
|
| `SomaRuntime` | `dom` from `ActiveUix` | event engine, `langs`, `format` | none of its own | nonexistent morfo/event/part |
|
|
| `Sema` direct | `dom` or `projector` when `visual` is active | `sound`, `haptic`, `visual:false` | none of its own for UIX services | `SemaConfigError` without `dom/projector` while visual is active |
|
|
| `Eidos` | `dom` when `applyDom` | `langs`, `format`, `prefs`, mode/density sources | `applyDom:false` allows render/serialize without DOM | missing `dom` with `applyDom` active |
|
|
| `ADom` direct | caller's target/window/document | breakpoints/window | `disabledDom` only when the caller asks for it | ADom's own errors without a real DOM |
|
|
|
|
## Ownership and degradation rules
|
|
|
|
1. **Only composition roots create shared services.** `morfo`, `soma`, `sema`,
|
|
`eidos` and components never create `dom`, `langs`, `prefs`, `format`,
|
|
`clipboard` or equivalents: they receive them from `ActiveUix`.
|
|
2. **`dom:false` only degrades in standalone.** `ActiveUix` exposes a local
|
|
`disabledDom` and passes it to `EngineSemantic` too; Sema/events never fall
|
|
back to direct DOM writes. In attach there is no compensating creation: if
|
|
the app has no `dom`, `attachActiveUix(app)` fails. **`disabledDom` is
|
|
deliberately MIXED** (AUX-2, 2026-07-11): write-shaped calls (`apply`,
|
|
`listen`, …) no-op silently, but reads that MUST return a value —
|
|
`measure`, `raf`, `getDocument` / `getWindow` — **throw
|
|
`ActiveUixDomDisabledError`**; a component that measures under
|
|
`dom:false` dies loudly instead of computing from a phantom layout.
|
|
3. **`langs` is not `locale`.** `prefs.language` feeds translations;
|
|
`prefs.locale` feeds formats. They never mix.
|
|
4. **`clipboard` is a capability service, not visual DOM.** Standalone creates
|
|
it unless `clipboard:false`; attach consumes it from `app.clipboard` when a
|
|
layer asks for it, and fails with an explicit error if it was not declared.
|
|
5. **`prefs.direction` is the effective direction preference**; `html[dir]` is
|
|
only its DOM projection.
|
|
6. **`ActiveUix` does not auto-project preferences onto the DOM.** `arts/prefs`
|
|
projects the cross-modal attrs (`dir`, `data-motion`, `data-sound`,
|
|
`data-haptic`) via `createActivePrefsDomProjection`; `ActiveEidos` projects
|
|
the visual ones (`data-theme`, `data-mode`, `data-density`). The `frontend`
|
|
artifact was retired and must not reappear as a `locale` source.
|
|
7. **`ActiveUix` neither creates nor knows `Soma` or `Eidos`.** `Soma.create(...)`
|
|
creates its own scope and `Soma.runtime(...)`; `ActiveEidos.create(...)`
|
|
creates the visual scope when the app needs runtime CSS.
|
|
|
|
## Booting a UIX shell
|
|
|
|
A shell that uses visual components wires three pieces explicitly:
|
|
|
|
```ts
|
|
const uix = createActiveUix({ langs, prefs: { schema } });
|
|
|
|
setActiveUix(uix);
|
|
Soma.create();
|
|
|
|
const prefsProjection = createActivePrefsDomProjection({
|
|
prefs: uix.prefs,
|
|
dom: uix.dom
|
|
});
|
|
|
|
const eidos = ActiveEidos.create({
|
|
theme: 'base',
|
|
modeSource,
|
|
applyDom: true
|
|
});
|
|
```
|
|
|
|
`prefsProjection` owns `dir`, `data-motion`, `data-sound` and `data-haptic`.
|
|
`ActiveEidos` owns `data-theme`, `data-mode` and `data-density`. Light/dark
|
|
mode goes to `ActiveEidos.modeSource`, not to `prefs.theme` — `theme` is not
|
|
part of UIX's core prefs preset and writing it raises
|
|
`prefs::unknown_dimension`.
|