@playfast/reform 0.0.5 → 0.0.7
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/boundary/boundary.d.ts +72 -0
- package/dist/boundary/boundary.d.ts.map +1 -0
- package/dist/boundary/boundary.js +83 -0
- package/dist/boundary/boundary.js.map +1 -0
- package/dist/calc/asyncCalc.d.ts +91 -0
- package/dist/calc/asyncCalc.d.ts.map +1 -0
- package/dist/calc/asyncCalc.js +95 -0
- package/dist/calc/asyncCalc.js.map +1 -0
- package/{src/calc/asyncData.ts → dist/calc/asyncData.d.ts} +22 -53
- package/dist/calc/asyncData.d.ts.map +1 -0
- package/dist/calc/asyncData.js +34 -0
- package/dist/calc/asyncData.js.map +1 -0
- package/dist/calc/calc.d.ts +57 -0
- package/dist/calc/calc.d.ts.map +1 -0
- package/dist/calc/calc.js +58 -0
- package/dist/calc/calc.js.map +1 -0
- package/dist/calc/calcFamily.d.ts +57 -0
- package/dist/calc/calcFamily.d.ts.map +1 -0
- package/dist/calc/calcFamily.js +124 -0
- package/dist/calc/calcFamily.js.map +1 -0
- package/dist/calc/compose.d.ts +16 -0
- package/dist/calc/compose.d.ts.map +1 -0
- package/dist/calc/compose.js +7 -0
- package/dist/calc/compose.js.map +1 -0
- package/dist/channel/channel.d.ts +115 -0
- package/dist/channel/channel.d.ts.map +1 -0
- package/dist/channel/channel.js +138 -0
- package/dist/channel/channel.js.map +1 -0
- package/dist/compose/composition.d.ts +72 -0
- package/dist/compose/composition.d.ts.map +1 -0
- package/dist/compose/composition.js +46 -0
- package/dist/compose/composition.js.map +1 -0
- package/{src/compose/host.ts → dist/compose/host.d.ts} +8 -6
- package/dist/compose/host.d.ts.map +1 -0
- package/dist/compose/host.js +6 -0
- package/dist/compose/host.js.map +1 -0
- package/dist/compose/props.d.ts +13 -0
- package/dist/compose/props.d.ts.map +1 -0
- package/{src/compose/props.ts → dist/compose/props.js} +5 -3
- package/dist/compose/props.js.map +1 -0
- package/dist/compose/provide.d.ts +22 -0
- package/dist/compose/provide.d.ts.map +1 -0
- package/dist/compose/provide.js +28 -0
- package/dist/compose/provide.js.map +1 -0
- package/{src/compose/slot.ts → dist/compose/slot.d.ts} +19 -36
- package/dist/compose/slot.d.ts.map +1 -0
- package/dist/compose/slot.js +23 -0
- package/dist/compose/slot.js.map +1 -0
- package/dist/compose/ui.d.ts +135 -0
- package/dist/compose/ui.d.ts.map +1 -0
- package/dist/compose/ui.js +63 -0
- package/dist/compose/ui.js.map +1 -0
- package/dist/definition/definition.d.ts +33 -0
- package/dist/definition/definition.d.ts.map +1 -0
- package/dist/definition/definition.js +42 -0
- package/dist/definition/definition.js.map +1 -0
- package/dist/event/event.d.ts +33 -0
- package/dist/event/event.d.ts.map +1 -0
- package/dist/event/event.js +30 -0
- package/dist/event/event.js.map +1 -0
- package/dist/event/eventGroup.d.ts +9 -0
- package/dist/event/eventGroup.d.ts.map +1 -0
- package/dist/event/eventGroup.js +4 -0
- package/dist/event/eventGroup.js.map +1 -0
- package/{src/feature/feature.ts → dist/feature/feature.d.ts} +92 -178
- package/dist/feature/feature.d.ts.map +1 -0
- package/dist/feature/feature.js +98 -0
- package/dist/feature/feature.js.map +1 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +62 -0
- package/dist/index.js.map +1 -0
- package/{src/internal/capture.ts → dist/internal/capture.d.ts} +11 -13
- package/dist/internal/capture.d.ts.map +1 -0
- package/dist/internal/capture.js +12 -0
- package/dist/internal/capture.js.map +1 -0
- package/{src/internal/ctx.ts → dist/internal/ctx.d.ts} +4 -8
- package/dist/internal/ctx.d.ts.map +1 -0
- package/dist/internal/ctx.js +2 -0
- package/dist/internal/ctx.js.map +1 -0
- package/dist/internal/errors.d.ts +89 -0
- package/dist/internal/errors.d.ts.map +1 -0
- package/dist/internal/errors.js +102 -0
- package/dist/internal/errors.js.map +1 -0
- package/dist/internal/inspect.d.ts +17 -0
- package/dist/internal/inspect.d.ts.map +1 -0
- package/dist/internal/inspect.js +32 -0
- package/dist/internal/inspect.js.map +1 -0
- package/dist/internal/queryDriver.d.ts +65 -0
- package/dist/internal/queryDriver.d.ts.map +1 -0
- package/dist/internal/queryDriver.js +134 -0
- package/dist/internal/queryDriver.js.map +1 -0
- package/dist/internal/reuse.d.ts +10 -0
- package/dist/internal/reuse.d.ts.map +1 -0
- package/dist/internal/reuse.js +68 -0
- package/dist/internal/reuse.js.map +1 -0
- package/dist/internal/scheduler.d.ts +47 -0
- package/dist/internal/scheduler.d.ts.map +1 -0
- package/dist/internal/scheduler.js +70 -0
- package/dist/internal/scheduler.js.map +1 -0
- package/{src/internal/seeds.ts → dist/internal/seeds.d.ts} +3 -6
- package/dist/internal/seeds.d.ts.map +1 -0
- package/dist/internal/seeds.js +17 -0
- package/dist/internal/seeds.js.map +1 -0
- package/dist/internal/sources.d.ts +39 -0
- package/dist/internal/sources.d.ts.map +1 -0
- package/dist/internal/sources.js +59 -0
- package/dist/internal/sources.js.map +1 -0
- package/dist/internal/stateRegistry.d.ts +2 -0
- package/dist/internal/stateRegistry.d.ts.map +1 -0
- package/dist/internal/stateRegistry.js +28 -0
- package/dist/internal/stateRegistry.js.map +1 -0
- package/dist/internal/store.d.ts +47 -0
- package/dist/internal/store.d.ts.map +1 -0
- package/dist/internal/store.js +73 -0
- package/dist/internal/store.js.map +1 -0
- package/{src/internal/track.ts → dist/internal/track.d.ts} +11 -15
- package/dist/internal/track.d.ts.map +1 -0
- package/dist/internal/track.js +19 -0
- package/dist/internal/track.js.map +1 -0
- package/dist/procedure/procedure.d.ts +40 -0
- package/dist/procedure/procedure.d.ts.map +1 -0
- package/dist/procedure/procedure.js +50 -0
- package/dist/procedure/procedure.js.map +1 -0
- package/dist/reducer/reducer.d.ts +44 -0
- package/dist/reducer/reducer.d.ts.map +1 -0
- package/dist/reducer/reducer.js +63 -0
- package/dist/reducer/reducer.js.map +1 -0
- package/dist/remote/remoteState.d.ts +119 -0
- package/dist/remote/remoteState.d.ts.map +1 -0
- package/dist/remote/remoteState.js +270 -0
- package/dist/remote/remoteState.js.map +1 -0
- package/dist/runtime/bus.d.ts +27 -0
- package/dist/runtime/bus.d.ts.map +1 -0
- package/{src/runtime/bus.ts → dist/runtime/bus.js} +8 -23
- package/dist/runtime/bus.js.map +1 -0
- package/dist/runtime/loop.d.ts +45 -0
- package/dist/runtime/loop.d.ts.map +1 -0
- package/dist/runtime/loop.js +117 -0
- package/dist/runtime/loop.js.map +1 -0
- package/dist/scene/scene.d.ts +44 -0
- package/dist/scene/scene.d.ts.map +1 -0
- package/dist/scene/scene.js +31 -0
- package/dist/scene/scene.js.map +1 -0
- package/dist/state/state.d.ts +37 -0
- package/dist/state/state.d.ts.map +1 -0
- package/dist/state/state.js +46 -0
- package/dist/state/state.js.map +1 -0
- package/dist/state/stateFamily.d.ts +79 -0
- package/dist/state/stateFamily.d.ts.map +1 -0
- package/dist/state/stateFamily.js +99 -0
- package/dist/state/stateFamily.js.map +1 -0
- package/dist/state/stateGroup.d.ts +50 -0
- package/dist/state/stateGroup.d.ts.map +1 -0
- package/dist/state/stateGroup.js +54 -0
- package/dist/state/stateGroup.js.map +1 -0
- package/{src/state/token.ts → dist/state/token.d.ts} +13 -21
- package/dist/state/token.d.ts.map +1 -0
- package/dist/state/token.js +20 -0
- package/dist/state/token.js.map +1 -0
- package/dist/synced/syncedStore.d.ts +51 -0
- package/dist/synced/syncedStore.d.ts.map +1 -0
- package/dist/synced/syncedStore.js +43 -0
- package/dist/synced/syncedStore.js.map +1 -0
- package/{src/ui/node.ts → dist/ui/node.d.ts} +3 -3
- package/dist/ui/node.d.ts.map +1 -0
- package/dist/ui/node.js +2 -0
- package/dist/ui/node.js.map +1 -0
- package/{src/ui/trigger.ts → dist/ui/trigger.d.ts} +2 -1
- package/dist/ui/trigger.d.ts.map +1 -0
- package/dist/ui/trigger.js +2 -0
- package/dist/ui/trigger.js.map +1 -0
- package/dist/wire/tree.d.ts +66 -0
- package/dist/wire/tree.d.ts.map +1 -0
- package/dist/wire/tree.js +60 -0
- package/dist/wire/tree.js.map +1 -0
- package/dist/wire/triggers.d.ts +44 -0
- package/dist/wire/triggers.d.ts.map +1 -0
- package/dist/wire/triggers.js +31 -0
- package/dist/wire/triggers.js.map +1 -0
- package/package.json +32 -11
- package/src/boundary/boundary.ts +0 -192
- package/src/calc/asyncCalc.ts +0 -267
- package/src/calc/calc.ts +0 -120
- package/src/calc/calcFamily.ts +0 -194
- package/src/calc/compose.ts +0 -69
- package/src/channel/channel.ts +0 -265
- package/src/compose/composition.ts +0 -112
- package/src/compose/provide.ts +0 -70
- package/src/compose/ui.ts +0 -97
- package/src/definition/definition.ts +0 -74
- package/src/event/event.ts +0 -65
- package/src/event/eventGroup.ts +0 -14
- package/src/index.ts +0 -140
- package/src/internal/errors.ts +0 -69
- package/src/internal/inspect.ts +0 -34
- package/src/internal/queryDriver.ts +0 -247
- package/src/internal/reuse.ts +0 -73
- package/src/internal/scheduler.ts +0 -91
- package/src/internal/sources.ts +0 -104
- package/src/internal/store.ts +0 -105
- package/src/procedure/procedure.ts +0 -89
- package/src/reducer/reducer.ts +0 -137
- package/src/remote/remoteState.ts +0 -571
- package/src/runtime/loop.ts +0 -169
- package/src/scene/scene.ts +0 -76
- package/src/state/state.ts +0 -91
- package/src/state/stateFamily.ts +0 -171
- package/src/state/stateGroup.ts +0 -78
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Context, Effect, Layer, type Schema } from 'effect';
|
|
2
|
+
import type { YieldWrap } from 'effect/Utils';
|
|
3
|
+
import { type Manifest } from '../definition/definition';
|
|
4
|
+
import { type Ctx } from '../internal/ctx';
|
|
5
|
+
import type { Tracker } from '../internal/track';
|
|
6
|
+
import { type SlotHost } from './host';
|
|
7
|
+
import type { Node, SlotClass } from './slot';
|
|
8
|
+
import type { UiClass, UiContract } from './ui';
|
|
9
|
+
import { Props } from './props';
|
|
10
|
+
/** Everything the host injects per render: the instance props, the dependency tracker, and slot bindings. */
|
|
11
|
+
export interface RenderEnv {
|
|
12
|
+
readonly props: unknown;
|
|
13
|
+
readonly tracker: Tracker;
|
|
14
|
+
readonly slots: SlotHost;
|
|
15
|
+
}
|
|
16
|
+
/** A mounted composition: given a render environment, produces the current frame's node. */
|
|
17
|
+
export interface CompositionService {
|
|
18
|
+
readonly render: (env: RenderEnv) => Effect.Effect<Node, never, never>;
|
|
19
|
+
}
|
|
20
|
+
export interface CompositionConfig {
|
|
21
|
+
readonly title: string;
|
|
22
|
+
readonly description?: string;
|
|
23
|
+
readonly props?: Schema.Schema<any, any>;
|
|
24
|
+
readonly states?: ReadonlyArray<unknown>;
|
|
25
|
+
readonly calcs?: ReadonlyArray<unknown>;
|
|
26
|
+
readonly events?: ReadonlyArray<unknown>;
|
|
27
|
+
readonly slots?: Record<string, SlotClass>;
|
|
28
|
+
readonly ui: {
|
|
29
|
+
readonly manifest: Manifest & {
|
|
30
|
+
readonly kind: 'Ui';
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
type PropsOf<Config> = Config extends {
|
|
35
|
+
props: Schema.Schema<infer P, any>;
|
|
36
|
+
} ? P : unknown;
|
|
37
|
+
export interface CompositionClass<out P, out C extends UiContract = UiContract> {
|
|
38
|
+
new (): {};
|
|
39
|
+
readonly manifest: Manifest & {
|
|
40
|
+
readonly kind: 'Composition';
|
|
41
|
+
} & CompositionConfig;
|
|
42
|
+
/** Phantom carrying the props type for `provide(slot, composition)` checks. */
|
|
43
|
+
readonly Props: P;
|
|
44
|
+
/**
|
|
45
|
+
* Phantom carrying the resolved UI contract (props + events + slots). It lets
|
|
46
|
+
* reflection consumers — proofs, the dev tool — recover the full contract from
|
|
47
|
+
* a composition value and stay fully typed. Covariant (output only); the
|
|
48
|
+
* invariant `impl` tag is never stored here, so no variance regression.
|
|
49
|
+
*/
|
|
50
|
+
readonly Contract: C;
|
|
51
|
+
readonly tag: Context.Tag<CompositionService, CompositionService>;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* A component's logic. The *definition* (`Composition.make`) is a reflectable
|
|
55
|
+
* manifest that doubles as a requirement/tag; the *implementation*
|
|
56
|
+
* (`Composition.live`) is the synchronous body, provided separately and
|
|
57
|
+
* checked against it.
|
|
58
|
+
*/
|
|
59
|
+
export declare const make: <const Config extends CompositionConfig, C extends UiContract>(name: string, config: Config & {
|
|
60
|
+
readonly ui: UiClass<C>;
|
|
61
|
+
}) => CompositionClass<PropsOf<Config>, C>;
|
|
62
|
+
/**
|
|
63
|
+
* Wire a composition's synchronous logic (D2): read state, acquire triggers,
|
|
64
|
+
* resolve the UI, return the view. Its requirements (minus `Props`, which the
|
|
65
|
+
* host injects per render) surface as the Layer's `RIn`; the runtime runs the
|
|
66
|
+
* body per render within the captured context.
|
|
67
|
+
*/
|
|
68
|
+
export declare const live: <P, Eff extends YieldWrap<Effect.Effect<unknown, never, unknown>>>(composition: CompositionClass<P, any>, body: () => Generator<Eff, Node, never>) => Layer.Layer<CompositionService, never, Exclude<Ctx<Eff>, Props>>;
|
|
69
|
+
/** Run a mounted composition for one frame, producing its node. */
|
|
70
|
+
export declare const render: (service: CompositionService, env: RenderEnv) => Effect.Effect<Node, never, never>;
|
|
71
|
+
export {};
|
|
72
|
+
//# sourceMappingURL=composition.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composition.d.ts","sourceRoot":"","sources":["../../src/compose/composition.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Context, Effect, Layer } from 'effect';
|
|
2
|
+
import { definitionClass } from '../definition/definition';
|
|
3
|
+
import {} from '../internal/ctx';
|
|
4
|
+
import { CurrentTracker } from '../internal/track';
|
|
5
|
+
import { CurrentSlots } from './host';
|
|
6
|
+
import { Props } from './props';
|
|
7
|
+
/**
|
|
8
|
+
* A component's logic. The *definition* (`Composition.make`) is a reflectable
|
|
9
|
+
* manifest that doubles as a requirement/tag; the *implementation*
|
|
10
|
+
* (`Composition.live`) is the synchronous body, provided separately and
|
|
11
|
+
* checked against it.
|
|
12
|
+
*/
|
|
13
|
+
export const make = (name,
|
|
14
|
+
// Constrain `ui` to the full `UiClass<C>` so `C` is inferred here; the stored
|
|
15
|
+
// manifest still sees only the erased `{ manifest }` carrier (CompositionConfig),
|
|
16
|
+
// so the manifest type — and its variance — is unchanged.
|
|
17
|
+
config) => {
|
|
18
|
+
const tag = Context.GenericTag(`reform/composition/${name}`);
|
|
19
|
+
const manifest = { kind: 'Composition', name, ...config };
|
|
20
|
+
return definitionClass({ manifest, tag });
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Wire a composition's synchronous logic (D2): read state, acquire triggers,
|
|
24
|
+
* resolve the UI, return the view. Its requirements (minus `Props`, which the
|
|
25
|
+
* host injects per render) surface as the Layer's `RIn`; the runtime runs the
|
|
26
|
+
* body per render within the captured context.
|
|
27
|
+
*/
|
|
28
|
+
export const live = (
|
|
29
|
+
// `live` doesn't use the contract type; accept any composition.
|
|
30
|
+
composition, body) => {
|
|
31
|
+
const logic = Effect.gen(body);
|
|
32
|
+
return Layer.effect(composition.tag, Effect.gen(function* () {
|
|
33
|
+
// Capture the build-time context (state stores, calc, ui, bus). `Props`,
|
|
34
|
+
// the tracker, and slots are injected per render below.
|
|
35
|
+
const context = yield* Effect.context();
|
|
36
|
+
const render = (env) =>
|
|
37
|
+
// Total once fully provided: the body is synchronous, reads can't fail,
|
|
38
|
+
// and every requirement is now satisfied (D2). `Effect.gen` widens the
|
|
39
|
+
// error channel to `unknown` for a generic body, so we restate it.
|
|
40
|
+
logic.pipe(Effect.provideService(Props, env.props), Effect.provideService(CurrentTracker, env.tracker), Effect.provideService(CurrentSlots, env.slots), Effect.provide(context));
|
|
41
|
+
return { render };
|
|
42
|
+
}));
|
|
43
|
+
};
|
|
44
|
+
/** Run a mounted composition for one frame, producing its node. */
|
|
45
|
+
export const render = (service, env) => service.render(env);
|
|
46
|
+
//# sourceMappingURL=composition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composition.js","sourceRoot":"","sources":["../../src/compose/composition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAe,MAAM,QAAQ,CAAA;AAE5D,OAAO,EAAiB,eAAe,EAAE,MAAM,0BAA0B,CAAA;AACzE,OAAO,EAAY,MAAM,iBAAiB,CAAA;AAE1C,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAClD,OAAO,EAAE,YAAY,EAAiB,MAAM,QAAQ,CAAA;AAGpD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AA+C/B;;;;;GAKG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAClB,IAAY;AACZ,8EAA8E;AAC9E,kFAAkF;AAClF,0DAA0D;AAC1D,MAA4C,EACN,EAAE;IACxC,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAC5B,sBAAsB,IAAI,EAAE,CAC7B,CAAA;IACD,MAAM,QAAQ,GAAG,EAAE,IAAI,EAAE,aAAsB,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,CAAA;IAClE,OAAO,eAAe,CAAuC,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAA;AACjF,CAAC,CAAA;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG;AAClB,gEAAgE;AAChE,WAAqC,EACrC,IAAuC,EAC2B,EAAE;IACpE,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC9B,OAAO,KAAK,CAAC,MAAM,CACjB,WAAW,CAAC,GAAG,EACf,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,yEAAyE;QACzE,wDAAwD;QACxD,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,EAA4B,CAAA;QACjE,MAAM,MAAM,GAAG,CAAC,GAAc,EAAqC,EAAE;QACnE,wEAAwE;QACxE,uEAAuE;QACvE,mEAAmE;QACnE,KAAK,CAAC,IAAI,CACR,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,EACvC,MAAM,CAAC,cAAc,CAAC,cAAc,EAAE,GAAG,CAAC,OAAO,CAAC,EAClD,MAAM,CAAC,cAAc,CAAC,YAAY,EAAE,GAAG,CAAC,KAAK,CAAC,EAC9C,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CACa,CAAA;QACxC,OAAO,EAAE,MAAM,EAAE,CAAA;IACnB,CAAC,CAAC,CACH,CAAA;AACH,CAAC,CAAA;AAED,mEAAmE;AACnE,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,OAA2B,EAAE,GAAc,EAAqC,EAAE,CACvG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { Context } from 'effect'
|
|
2
|
-
import type { Node } from './slot'
|
|
3
|
-
|
|
1
|
+
import { Context } from 'effect';
|
|
2
|
+
import type { Node } from './slot';
|
|
4
3
|
/**
|
|
5
4
|
* Binds a parent's slots to concrete child renderers. The host package
|
|
6
5
|
* (`@reform/react`) builds one per composition instance from the manifest's
|
|
@@ -8,8 +7,11 @@ import type { Node } from './slot'
|
|
|
8
7
|
* child. Core stays renderer-neutral — it only defines this hole.
|
|
9
8
|
*/
|
|
10
9
|
export interface SlotHost {
|
|
11
|
-
|
|
10
|
+
slot(name: string): (props: unknown) => Node;
|
|
12
11
|
}
|
|
13
|
-
|
|
12
|
+
declare const CurrentSlotsBase: Context.TagClass<CurrentSlots, 'reform/Slots', SlotHost>;
|
|
14
13
|
/** The active composition's slot bindings, provided per render by the host. */
|
|
15
|
-
export class CurrentSlots extends
|
|
14
|
+
export declare class CurrentSlots extends CurrentSlotsBase {
|
|
15
|
+
}
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=host.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/compose/host.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AAChC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAElC;;;;;GAKG;AACH,MAAM,WAAW,QAAQ;IACvB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CAC7C;AAED,QAAA,MAAM,gBAAgB,EAAE,OAAO,CAAC,QAAQ,CAAC,YAAY,EAAE,cAAc,EAAE,QAAQ,CACxB,CAAA;AAEvD,+EAA+E;AAC/E,qBAAa,YAAa,SAAQ,gBAAgB;CAAG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/compose/host.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AAahC,MAAM,gBAAgB,GACpB,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAA0B,CAAA;AAEvD,+EAA+E;AAC/E,MAAM,OAAO,YAAa,SAAQ,gBAAgB;CAAG"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Context } from 'effect';
|
|
2
|
+
/**
|
|
3
|
+
* The current composition instance's props. Bound per render by the runtime; a
|
|
4
|
+
* composition body reads them with `const { todo } = yield* Props`.
|
|
5
|
+
*
|
|
6
|
+
* (Per-instance typing of Props is DESIGN #26 — for now the value is opaque and
|
|
7
|
+
* narrowed at the use site against the composition's declared props schema.)
|
|
8
|
+
*/
|
|
9
|
+
declare const PropsBase: Context.TagClass<Props, 'reform/Props', any>;
|
|
10
|
+
export declare class Props extends PropsBase {
|
|
11
|
+
}
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=props.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"props.d.ts","sourceRoot":"","sources":["../../src/compose/props.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AAEhC;;;;;;GAMG;AACH,QAAA,MAAM,SAAS,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,CAGzD,CAAA;AACH,qBAAa,KAAM,SAAQ,SAAS;CAAG"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { Context } from 'effect'
|
|
2
|
-
|
|
1
|
+
import { Context } from 'effect';
|
|
3
2
|
/**
|
|
4
3
|
* The current composition instance's props. Bound per render by the runtime; a
|
|
5
4
|
* composition body reads them with `const { todo } = yield* Props`.
|
|
@@ -7,4 +6,7 @@ import { Context } from 'effect'
|
|
|
7
6
|
* (Per-instance typing of Props is DESIGN #26 — for now the value is opaque and
|
|
8
7
|
* narrowed at the use site against the composition's declared props schema.)
|
|
9
8
|
*/
|
|
10
|
-
|
|
9
|
+
const PropsBase = Context.Tag('reform/Props')();
|
|
10
|
+
export class Props extends PropsBase {
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=props.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"props.js","sourceRoot":"","sources":["../../src/compose/props.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AAEhC;;;;;;GAMG;AACH,MAAM,SAAS,GAAiD,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAGxF,CAAA;AACH,MAAM,OAAO,KAAM,SAAQ,SAAS;CAAG"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Layer } from 'effect';
|
|
2
|
+
import type { CompositionClass } from './composition';
|
|
3
|
+
import { type EngineServices, type FeatureClass, type ProvidedBy, type RequireCarrier } from '../feature/feature';
|
|
4
|
+
import { type SlotChild, type SlotClass } from './slot';
|
|
5
|
+
import { type UiClass, type UiContract, type ViewImpl } from './ui';
|
|
6
|
+
/**
|
|
7
|
+
* Wire an implementation to a contract. Provides a `.make` presentation to a UI
|
|
8
|
+
* contract, a child composition into a parent's slot, or a `Feature` into a slot.
|
|
9
|
+
* The compose code never imports its implementations — they meet here.
|
|
10
|
+
*/
|
|
11
|
+
export declare function provide<C extends UiContract>(contract: UiClass<C>, view: ViewImpl<C>): Layer.Layer<ViewImpl<C>>;
|
|
12
|
+
export declare function provide<Comp extends CompositionClass<any, any>>(hole: SlotClass<Comp>, composition: Comp): Layer.Layer<CompositionClass<unknown>>;
|
|
13
|
+
/**
|
|
14
|
+
* Fill a slot with a feature. The slot's child composition type
|
|
15
|
+
* (`CompositionClass<P, C>`) must match the feature's mounted composition, so the
|
|
16
|
+
* facade/contract stays typed. The returned layer surfaces the feature's shared
|
|
17
|
+
* requirement (`EngineServices | ProvidedBy<Requires>`) as an open `RIn`, so the
|
|
18
|
+
* scene that wires it won't compile unless it provides the matching `Core` — even
|
|
19
|
+
* for a lazy feature whose own `.live` layer isn't built until mount.
|
|
20
|
+
*/
|
|
21
|
+
export declare function provide<Comp extends CompositionClass<any, any>, ROut, Requires extends ReadonlyArray<RequireCarrier>>(hole: SlotClass<Comp>, feature: FeatureClass<Comp extends CompositionClass<infer P, any> ? P : never, Comp extends CompositionClass<any, infer C> ? C : never, ROut, Requires>): Layer.Layer<SlotChild, never, EngineServices | ProvidedBy<Requires>>;
|
|
22
|
+
//# sourceMappingURL=provide.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provide.d.ts","sourceRoot":"","sources":["../../src/compose/provide.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,EAAE,MAAM,QAAQ,CAAA;AAE5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AACrD,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,YAAY,EAEjB,KAAK,UAAU,EACf,KAAK,cAAc,EACpB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAU,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,QAAQ,CAAA;AAC/D,OAAO,EAAQ,KAAK,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,QAAQ,EAAE,MAAM,MAAM,CAAA;AAEzE;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,UAAU,EAC1C,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,EACpB,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,GAChB,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;AAC3B,wBAAgB,OAAO,CAAC,IAAI,SAAS,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,EAC7D,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,EACrB,WAAW,EAAE,IAAI,GAChB,KAAK,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAA;AACzC;;;;;;;GAOG;AACH,wBAAgB,OAAO,CACrB,IAAI,SAAS,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,EACvC,IAAI,EACJ,QAAQ,SAAS,aAAa,CAAC,cAAc,CAAC,EAE9C,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,EACrB,OAAO,EAAE,YAAY,CACnB,IAAI,SAAS,gBAAgB,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,EACvD,IAAI,SAAS,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,EACvD,IAAI,EACJ,QAAQ,CACT,GACA,KAAK,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,EAAE,cAAc,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Layer } from 'effect';
|
|
2
|
+
import { InvalidProvideTarget } from '../internal/errors';
|
|
3
|
+
import { isFeature, } from '../feature/feature';
|
|
4
|
+
import { isSlot } from './slot';
|
|
5
|
+
import { isUi } from './ui';
|
|
6
|
+
export function provide(target, impl) {
|
|
7
|
+
// Discriminate the target by its nominal brand, not by which DI-hole property
|
|
8
|
+
// happens to exist: a UI contract provides under its `impl` tag, a slot under
|
|
9
|
+
// its `tag`. Anything else is a wiring mistake. The overloads above pair
|
|
10
|
+
// `impl` with the chosen tag; this implementation sees both erased, so view
|
|
11
|
+
// the tag loosely (the one documented cast) to provide the service under it.
|
|
12
|
+
const tag = (isUi(target) ? target.impl : isSlot(target) ? target.tag : undefined);
|
|
13
|
+
if (tag === undefined)
|
|
14
|
+
throw new InvalidProvideTarget();
|
|
15
|
+
if (isFeature(impl)) {
|
|
16
|
+
const eager = impl.eagerModule;
|
|
17
|
+
// Lazy: bind the `FeatureBinding`; the host drives load → mount, painting the
|
|
18
|
+
// placeholders. Default: bind the composition (so the existing `Compose` path
|
|
19
|
+
// renders it, no host, no flash) and merge the eager `.live` layer, whose `RIn`
|
|
20
|
+
// surfaces to the scene. Either way the overload's return type carries the
|
|
21
|
+
// shared `RIn`, so the scene still type-demands `Core`.
|
|
22
|
+
return eager === undefined
|
|
23
|
+
? Layer.succeed(tag, impl.binding)
|
|
24
|
+
: Layer.merge(Layer.succeed(tag, impl.binding.composition), eager.layer);
|
|
25
|
+
}
|
|
26
|
+
return Layer.succeed(tag, impl);
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=provide.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provide.js","sourceRoot":"","sources":["../../src/compose/provide.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAEzD,OAAO,EAGL,SAAS,GAGV,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,MAAM,EAAkC,MAAM,QAAQ,CAAA;AAC/D,OAAO,EAAE,IAAI,EAAgD,MAAM,MAAM,CAAA;AAoCzE,MAAM,UAAU,OAAO,CAAC,MAAe,EAAE,IAAa;IACpD,8EAA8E;IAC9E,8EAA8E;IAC9E,yEAAyE;IACzE,4EAA4E;IAC5E,6EAA6E;IAC7E,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAEpE,CAAA;IACb,IAAI,GAAG,KAAK,SAAS;QAAE,MAAM,IAAI,oBAAoB,EAAE,CAAA;IACvD,IAAI,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;QACpB,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAA;QAC9B,8EAA8E;QAC9E,8EAA8E;QAC9E,gFAAgF;QAChF,2EAA2E;QAC3E,wDAAwD;QACxD,OAAO,KAAK,KAAK,SAAS;YACxB,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC;YAClC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAA;IAC5E,CAAC;IACD,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;AACjC,CAAC"}
|
|
@@ -1,22 +1,17 @@
|
|
|
1
|
-
import { Context } from 'effect'
|
|
2
|
-
import {
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export type { Node }
|
|
8
|
-
|
|
1
|
+
import { Context } from 'effect';
|
|
2
|
+
import type { CompositionClass } from './composition';
|
|
3
|
+
import type { FeatureBinding } from '../feature/feature';
|
|
4
|
+
import type { Node } from '../ui/node';
|
|
5
|
+
export type { Node };
|
|
9
6
|
/** Any composition, used where only the slot's structural role matters. */
|
|
10
|
-
type AnyComposition = CompositionClass<any, any
|
|
11
|
-
|
|
7
|
+
type AnyComposition = CompositionClass<any, any>;
|
|
12
8
|
/**
|
|
13
9
|
* What a slot can be filled with: a plain child composition (the host renders it
|
|
14
10
|
* directly), or a `FeatureBinding` from `provide(slot, Feature)` (the host drives
|
|
15
11
|
* its lazy/eager mount lifecycle). The slot's DI tag holds one of these; the host
|
|
16
12
|
* discriminates by the `FeatureBinding` brand.
|
|
17
13
|
*/
|
|
18
|
-
export type SlotChild = CompositionClass<unknown> | FeatureBinding
|
|
19
|
-
|
|
14
|
+
export type SlotChild = CompositionClass<unknown> | FeatureBinding;
|
|
20
15
|
/**
|
|
21
16
|
* Phantom instance shape: `ItemSlot` used as a *type* denotes this. It carries
|
|
22
17
|
* the child *composition* type `Comp`, so the slot knows both the external props
|
|
@@ -25,9 +20,8 @@ export type SlotChild = CompositionClass<unknown> | FeatureBinding
|
|
|
25
20
|
* proof facade, drive.
|
|
26
21
|
*/
|
|
27
22
|
export interface SlotInstance<Comp extends AnyComposition> {
|
|
28
|
-
|
|
23
|
+
readonly _slot: Comp;
|
|
29
24
|
}
|
|
30
|
-
|
|
31
25
|
/**
|
|
32
26
|
* A DI hole for a child composition. The parent declares
|
|
33
27
|
* `slot('Item')<typeof TodoItem>()` and renders through it; the concrete child
|
|
@@ -38,29 +32,18 @@ export interface SlotInstance<Comp extends AnyComposition> {
|
|
|
38
32
|
* by `provide`'s signature, not the (invariant) tag.
|
|
39
33
|
*/
|
|
40
34
|
/** Nominal brand identifying a slot at runtime (Effect's `TypeId` idiom). */
|
|
41
|
-
export const SlotTypeId: unique symbol
|
|
42
|
-
export type SlotTypeId = typeof SlotTypeId
|
|
43
|
-
|
|
35
|
+
export declare const SlotTypeId: unique symbol;
|
|
36
|
+
export type SlotTypeId = typeof SlotTypeId;
|
|
44
37
|
export interface SlotClass<Comp extends AnyComposition = AnyComposition> {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
38
|
+
new (): SlotInstance<Comp>;
|
|
39
|
+
readonly [SlotTypeId]: SlotTypeId;
|
|
40
|
+
readonly kind: 'Slot';
|
|
41
|
+
/** Internal DI tag the filling child (composition or feature binding) is provided under. */
|
|
42
|
+
readonly tag: Context.Tag<SlotChild, SlotChild>;
|
|
50
43
|
}
|
|
51
|
-
|
|
52
44
|
/** Whether a value is a slot — discriminates a `provide` target by brand. */
|
|
53
|
-
export const isSlot
|
|
54
|
-
(typeof u === 'function' || typeof u === 'object') && u !== null && SlotTypeId in u
|
|
55
|
-
|
|
45
|
+
export declare const isSlot: (u: unknown) => u is SlotClass;
|
|
56
46
|
/** The props a slot renders with — the child composition's external props. */
|
|
57
|
-
export type SlotProps<S> = S extends SlotInstance<infer Comp> ? Comp['Props'] : never
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
(name: string) =>
|
|
61
|
-
// Defaulted so a slot whose child carries no meaningful props/contract can be
|
|
62
|
-
// declared bare (`slot('Tree')()`); pass `typeof Child` to type the facade.
|
|
63
|
-
<Comp extends AnyComposition = AnyComposition>(): SlotClass<Comp> => {
|
|
64
|
-
const tag = Context.GenericTag<SlotChild, SlotChild>(`reform/slot/${name}`)
|
|
65
|
-
return definitionClass<SlotClass<Comp>>({ [SlotTypeId]: SlotTypeId, kind: 'Slot' as const, tag })
|
|
66
|
-
}
|
|
47
|
+
export type SlotProps<S> = S extends SlotInstance<infer Comp> ? Comp['Props'] : never;
|
|
48
|
+
export declare const slot: (name: string) => <Comp extends AnyComposition = AnyComposition>() => SlotClass<Comp>;
|
|
49
|
+
//# sourceMappingURL=slot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slot.d.ts","sourceRoot":"","sources":["../../src/compose/slot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AAEhC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAEtC,YAAY,EAAE,IAAI,EAAE,CAAA;AAEpB,2EAA2E;AAC3E,KAAK,cAAc,GAAG,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;AAEhD;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAAG,gBAAgB,CAAC,OAAO,CAAC,GAAG,cAAc,CAAA;AAElE;;;;;;GAMG;AACH,MAAM,WAAW,YAAY,CAAC,IAAI,SAAS,cAAc;IACvD,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAA;CACrB;AAED;;;;;;;;GAQG;AACH,6EAA6E;AAC7E,eAAO,MAAM,UAAU,EAAE,OAAO,MAAkC,CAAA;AAClE,MAAM,MAAM,UAAU,GAAG,OAAO,UAAU,CAAA;AAE1C,MAAM,WAAW,SAAS,CAAC,IAAI,SAAS,cAAc,GAAG,cAAc;IACrE,QAAQ,YAAY,CAAC,IAAI,CAAC,CAAA;IAC1B,QAAQ,CAAC,CAAC,UAAU,CAAC,EAAE,UAAU,CAAA;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,4FAA4F;IAC5F,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;CAChD;AAED,6EAA6E;AAC7E,eAAO,MAAM,MAAM,GAAI,GAAG,OAAO,KAAG,CAAC,IAAI,SAC4C,CAAA;AAErF,8EAA8E;AAC9E,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,SAAS,YAAY,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,KAAK,CAAA;AAErF,eAAO,MAAM,IAAI,GACd,MAAM,MAAM,MAGZ,IAAI,SAAS,cAAc,GAAG,cAAc,OAAK,SAAS,CAAC,IAAI,CAG/D,CAAA"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Context } from 'effect';
|
|
2
|
+
import { definitionClass } from '../definition/definition';
|
|
3
|
+
/**
|
|
4
|
+
* A DI hole for a child composition. The parent declares
|
|
5
|
+
* `slot('Item')<typeof TodoItem>()` and renders through it; the concrete child
|
|
6
|
+
* is wired with `provide(Item, TodoItem)`, so the parent never imports the
|
|
7
|
+
* child's *implementation* (the `typeof` is a type-only reference to the
|
|
8
|
+
* definition). `Comp` lives only in the phantom instance (so `SlotClass` is
|
|
9
|
+
* covariant and a `{ Item: ItemSlot }` map is well-typed); the match is enforced
|
|
10
|
+
* by `provide`'s signature, not the (invariant) tag.
|
|
11
|
+
*/
|
|
12
|
+
/** Nominal brand identifying a slot at runtime (Effect's `TypeId` idiom). */
|
|
13
|
+
export const SlotTypeId = Symbol.for('reform/Slot');
|
|
14
|
+
/** Whether a value is a slot — discriminates a `provide` target by brand. */
|
|
15
|
+
export const isSlot = (u) => (typeof u === 'function' || typeof u === 'object') && u !== null && SlotTypeId in u;
|
|
16
|
+
export const slot = (name) =>
|
|
17
|
+
// Defaulted so a slot whose child carries no meaningful props/contract can be
|
|
18
|
+
// declared bare (`slot('Tree')()`); pass `typeof Child` to type the facade.
|
|
19
|
+
() => {
|
|
20
|
+
const tag = Context.GenericTag(`reform/slot/${name}`);
|
|
21
|
+
return definitionClass({ [SlotTypeId]: SlotTypeId, kind: 'Slot', tag });
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=slot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slot.js","sourceRoot":"","sources":["../../src/compose/slot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AAChC,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AA6B1D;;;;;;;;GAQG;AACH,6EAA6E;AAC7E,MAAM,CAAC,MAAM,UAAU,GAAkB,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;AAWlE,6EAA6E;AAC7E,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,CAAU,EAAkB,EAAE,CACnD,CAAC,OAAO,CAAC,KAAK,UAAU,IAAI,OAAO,CAAC,KAAK,QAAQ,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,UAAU,IAAI,CAAC,CAAA;AAKrF,MAAM,CAAC,MAAM,IAAI,GACf,CAAC,IAAY,EAAE,EAAE;AACjB,8EAA8E;AAC9E,4EAA4E;AAC5E,GAAkE,EAAE;IAClE,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAuB,eAAe,IAAI,EAAE,CAAC,CAAA;IAC3E,OAAO,eAAe,CAAkB,EAAE,CAAC,UAAU,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,MAAe,EAAE,GAAG,EAAE,CAAC,CAAA;AACnG,CAAC,CAAA"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import type { FunctionComponent } from 'react';
|
|
2
|
+
import { Context, Effect, type Schema } from 'effect';
|
|
3
|
+
import { type Manifest } from '../definition/definition';
|
|
4
|
+
import type { Trigger } from '../ui/trigger';
|
|
5
|
+
import { type Node, type SlotClass, type SlotInstance, type SlotProps } from './slot';
|
|
6
|
+
export interface UiContract {
|
|
7
|
+
props: unknown;
|
|
8
|
+
slots?: Record<string, SlotInstance<any>>;
|
|
9
|
+
events?: Record<string, Trigger<any>>;
|
|
10
|
+
}
|
|
11
|
+
type PropsOf<C extends UiContract> = C['props'];
|
|
12
|
+
type EventsOf<C extends UiContract> = C extends {
|
|
13
|
+
events: infer E;
|
|
14
|
+
} ? E : Record<never, never>;
|
|
15
|
+
type SlotsOf<C extends UiContract> = C extends {
|
|
16
|
+
slots: infer S;
|
|
17
|
+
} ? {
|
|
18
|
+
readonly [K in keyof S]: FunctionComponent<Partial<SlotProps<S[K]> & {
|
|
19
|
+
readonly slotKey?: string;
|
|
20
|
+
}>>;
|
|
21
|
+
} : Record<never, never>;
|
|
22
|
+
/** What the composition logic calls: props + handlers in, a node out. Slots are bound by the renderer. */
|
|
23
|
+
export type LogicView<C extends UiContract> = (props: PropsOf<C>, events?: EventsOf<C>) => Node;
|
|
24
|
+
/** What `.make` authors: the pure presentation. Slots are injected by the renderer. */
|
|
25
|
+
export type ViewImpl<C extends UiContract> = (props: PropsOf<C>, slots: SlotsOf<C>, events: EventsOf<C>) => Node;
|
|
26
|
+
/** Nominal brand identifying a UI contract at runtime (Effect's `TypeId` idiom). */
|
|
27
|
+
export declare const UiTypeId: unique symbol;
|
|
28
|
+
export type UiTypeId = typeof UiTypeId;
|
|
29
|
+
/**
|
|
30
|
+
* The reflectable descriptor a contract carries. The wire `props` / `events`
|
|
31
|
+
* schemas are present *only* on the schema (wired) form — the type-only form
|
|
32
|
+
* carries neither, so a local contract has no schema cost and no schema surface.
|
|
33
|
+
*/
|
|
34
|
+
export interface UiManifest extends Manifest {
|
|
35
|
+
readonly kind: 'Ui';
|
|
36
|
+
readonly props?: Schema.Schema<any, any>;
|
|
37
|
+
readonly events?: Readonly<Record<string, Schema.Schema<any, any>>>;
|
|
38
|
+
}
|
|
39
|
+
/** A `UiManifest` whose wire schema is present — the runtime brand of a remote-capable contract. */
|
|
40
|
+
export interface WiredUiManifest extends UiManifest {
|
|
41
|
+
readonly props: Schema.Schema<any, any>;
|
|
42
|
+
}
|
|
43
|
+
export interface UiClass<C extends UiContract> extends Effect.Effect<LogicView<C>, never, ViewImpl<C>> {
|
|
44
|
+
new (): {};
|
|
45
|
+
readonly [UiTypeId]: UiTypeId;
|
|
46
|
+
readonly manifest: UiManifest;
|
|
47
|
+
/** Internal DI tag the `Ui.make` presentation is provided under. */
|
|
48
|
+
readonly impl: Context.Tag<ViewImpl<C>, ViewImpl<C>>;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Recover a contract's `UiContract` type from its `Ui` class — `Ui.Contract<typeof
|
|
52
|
+
* SomeUi>`. Lets a consumer (a proof, a reflection tool) name the contract derived
|
|
53
|
+
* from a wired `ui('X', {…})` without re-declaring it.
|
|
54
|
+
*/
|
|
55
|
+
export type Contract<U> = U extends UiClass<infer C> ? C : never;
|
|
56
|
+
/**
|
|
57
|
+
* A contract authored with wire schemas. Structurally a `UiClass<C>` whose
|
|
58
|
+
* manifest *carries* the schemas (`WiredUiManifest`), so it is the subtype the
|
|
59
|
+
* remote seam (`provideRemote`, the wire registry) demands while plain `provide`
|
|
60
|
+
* / `scene` / `Composition.make` keep accepting any `UiClass<C>`.
|
|
61
|
+
*/
|
|
62
|
+
export type WiredUi<C extends UiContract> = UiClass<C> & {
|
|
63
|
+
readonly manifest: WiredUiManifest;
|
|
64
|
+
};
|
|
65
|
+
/** The wire schemas a contract is authored from: props, a payload schema per event, and
|
|
66
|
+
* (type-only) the slots the view fills. Slots carry no wire schema — the children that
|
|
67
|
+
* fill them are their own contracts — but declaring them here threads typed slots into
|
|
68
|
+
* the derived contract, so a WIRED contract can also have slots (e.g. a parent whose
|
|
69
|
+
* props the client reads AND that renders slot children). */
|
|
70
|
+
export interface WireSchemas {
|
|
71
|
+
readonly props: Schema.Schema<any, any>;
|
|
72
|
+
readonly events?: Readonly<Record<string, Schema.Schema<any, any>>>;
|
|
73
|
+
readonly slots?: Readonly<Record<string, SlotClass>>;
|
|
74
|
+
}
|
|
75
|
+
type DerivedEvents<Sch extends WireSchemas> = Sch extends {
|
|
76
|
+
readonly events: infer E extends Record<string, Schema.Schema<any, any>>;
|
|
77
|
+
} ? {
|
|
78
|
+
readonly [K in keyof E]: Trigger<Schema.Schema.Type<E[K]>>;
|
|
79
|
+
} : Record<never, never>;
|
|
80
|
+
type DerivedSlots<Sch extends WireSchemas> = Sch extends {
|
|
81
|
+
readonly slots: infer S extends Record<string, SlotClass>;
|
|
82
|
+
} ? {
|
|
83
|
+
readonly [K in keyof S]: InstanceType<S[K]>;
|
|
84
|
+
} : Record<never, never>;
|
|
85
|
+
/**
|
|
86
|
+
* The `UiContract` a set of wire schemas denotes — props and event-payload
|
|
87
|
+
* *types* derived from the schemas via `Schema.Type`, plus any declared slots. The
|
|
88
|
+
* schema is the single source of truth; the contract type is inferred, never written
|
|
89
|
+
* a second time.
|
|
90
|
+
*/
|
|
91
|
+
export type DerivedContract<Sch extends WireSchemas> = {
|
|
92
|
+
readonly props: Schema.Schema.Type<Sch['props']>;
|
|
93
|
+
readonly slots: DerivedSlots<Sch>;
|
|
94
|
+
readonly events: DerivedEvents<Sch>;
|
|
95
|
+
};
|
|
96
|
+
/** Whether a value is a UI contract — discriminates a `provide` target by brand. */
|
|
97
|
+
export declare const isUi: (u: unknown) => u is UiClass<UiContract>;
|
|
98
|
+
/**
|
|
99
|
+
* A renderer-neutral UI contract. The logic resolves it (`yield* TodoAppUi`) to
|
|
100
|
+
* a `(props, events) => node` view with slots already bound; `.make` authors the
|
|
101
|
+
* presentation. Core defines the contract; `@reform/react` does the rendering.
|
|
102
|
+
*
|
|
103
|
+
* Two authoring forms, one source of truth each:
|
|
104
|
+
*
|
|
105
|
+
* - **Type-only (local):** `ui('Counter')<{ props: { count: number } }>()` — no
|
|
106
|
+
* schema, no ceremony, exactly as before.
|
|
107
|
+
* - **Schema (wired):** `ui('Counter', { props: S.Struct({ count: S.Number }) })`
|
|
108
|
+
* — the schema *is* the definition; the contract type is derived via
|
|
109
|
+
* `Schema.Type` (never re-written), and the result is a `WiredUi` the remote
|
|
110
|
+
* seam accepts. Make a local contract remote by rewriting this one line.
|
|
111
|
+
*/
|
|
112
|
+
export declare function ui(name: string): <C extends UiContract>() => UiClass<C>;
|
|
113
|
+
export declare function ui<const Sch extends WireSchemas>(name: string, schemas: Sch): WiredUi<DerivedContract<Sch>>;
|
|
114
|
+
/** Brand under which a `Ui.make` view carries its own contract. */
|
|
115
|
+
export declare const UiViewContract: unique symbol;
|
|
116
|
+
export type UiViewContract = typeof UiViewContract;
|
|
117
|
+
/**
|
|
118
|
+
* A `Ui.make` view that carries its contract, so a consumer can recover the
|
|
119
|
+
* contract (its wire name + props schema) straight from the view — no separate
|
|
120
|
+
* registration call. This is what makes the remote client view-set
|
|
121
|
+
* (`remoteViews<AppContract>({ Some: SomeView, … })`) work with the very same
|
|
122
|
+
* `Ui.make` views the local renderer uses.
|
|
123
|
+
*/
|
|
124
|
+
export type MadeView<C extends UiContract> = ViewImpl<C> & {
|
|
125
|
+
readonly [UiViewContract]: UiClass<C>;
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* Author the pure presentation for a contract — `Ui.make(TodoAppUi, (props,
|
|
129
|
+
* slots, events) => node)`. The contract argument fixes the view's types AND is
|
|
130
|
+
* carried on the returned view (`MadeView`), so the same view is reusable as a
|
|
131
|
+
* remote client presentation. Wire the result with `provide(contract, view)`.
|
|
132
|
+
*/
|
|
133
|
+
export declare const make: <C extends UiContract>(contract: UiClass<C>, view: ViewImpl<C>) => MadeView<C>;
|
|
134
|
+
export {};
|
|
135
|
+
//# sourceMappingURL=ui.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../src/compose/ui.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Context, Effect, Option } from 'effect';
|
|
2
|
+
import { yieldableClass } from '../definition/definition';
|
|
3
|
+
import { CaptureSink } from '../internal/capture';
|
|
4
|
+
import { SlotRenderingUnavailable } from '../internal/errors';
|
|
5
|
+
import { CurrentSlots } from './host';
|
|
6
|
+
import {} from './slot';
|
|
7
|
+
/** Nominal brand identifying a UI contract at runtime (Effect's `TypeId` idiom). */
|
|
8
|
+
export const UiTypeId = Symbol.for('reform/Ui');
|
|
9
|
+
/** Whether a value is a UI contract — discriminates a `provide` target by brand. */
|
|
10
|
+
export const isUi = (u) => (typeof u === 'function' || typeof u === 'object') && u !== null && UiTypeId in u;
|
|
11
|
+
const buildUi = (name, manifest) => {
|
|
12
|
+
const impl = Context.GenericTag(`reform/ui/${name}`);
|
|
13
|
+
const read = Effect.gen(function* () {
|
|
14
|
+
const render = yield* impl;
|
|
15
|
+
// Slots are bound by the host (`@reform/react`) per composition instance.
|
|
16
|
+
// Core has no renderer, so without a host every slot access throws.
|
|
17
|
+
const host = yield* Effect.serviceOption(CurrentSlots);
|
|
18
|
+
const slots = new Proxy({}, {
|
|
19
|
+
get(_t, key) {
|
|
20
|
+
if (Option.isNone(host)) {
|
|
21
|
+
throw new SlotRenderingUnavailable({ slot: String(key) });
|
|
22
|
+
}
|
|
23
|
+
return host.value.slot(String(key));
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
// A capturing host (proofs, the dev tool) reports each render's observable
|
|
27
|
+
// surface without replacing the presentation. Absent in production.
|
|
28
|
+
const sink = yield* Effect.serviceOption(CaptureSink);
|
|
29
|
+
return (props, events) => {
|
|
30
|
+
if (Option.isSome(sink)) {
|
|
31
|
+
sink.value.record({
|
|
32
|
+
name,
|
|
33
|
+
props,
|
|
34
|
+
events: (events ?? {}),
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return render(props, slots, (events ?? {}));
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
return yieldableClass(read, {
|
|
41
|
+
[UiTypeId]: UiTypeId,
|
|
42
|
+
manifest,
|
|
43
|
+
impl,
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
export function ui(name, schemas) {
|
|
47
|
+
if (schemas === undefined) {
|
|
48
|
+
return () => buildUi(name, { kind: 'Ui', name });
|
|
49
|
+
}
|
|
50
|
+
const eventFields = schemas.events === undefined ? {} : { events: schemas.events };
|
|
51
|
+
const manifest = { kind: 'Ui', name, props: schemas.props, ...eventFields };
|
|
52
|
+
return buildUi(name, manifest);
|
|
53
|
+
}
|
|
54
|
+
/** Brand under which a `Ui.make` view carries its own contract. */
|
|
55
|
+
export const UiViewContract = Symbol.for('reform/ui/view-contract');
|
|
56
|
+
/**
|
|
57
|
+
* Author the pure presentation for a contract — `Ui.make(TodoAppUi, (props,
|
|
58
|
+
* slots, events) => node)`. The contract argument fixes the view's types AND is
|
|
59
|
+
* carried on the returned view (`MadeView`), so the same view is reusable as a
|
|
60
|
+
* remote client presentation. Wire the result with `provide(contract, view)`.
|
|
61
|
+
*/
|
|
62
|
+
export const make = (contract, view) => Object.assign(view, { [UiViewContract]: contract });
|
|
63
|
+
//# sourceMappingURL=ui.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../src/compose/ui.ts"],"names":[],"mappings":"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"}
|