@almadar/core 7.10.1 → 7.12.0

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.
@@ -1,8 +1,141 @@
1
- import { T as TraitEventContract, E as Entity, a as TraitEventListener, b as TraitConfig, c as EntityField, d as EntityPersistence, e as EntityRow, U as UseDeclaration, f as EntityRef, g as TraitRef, P as PageRef, O as OrbitalDefinition, h as OrbitalSchema, i as Trait, j as Page, k as PageRefObject, l as TraitReference } from './schema-VTi4U3sS.js';
1
+ import { U as UISlot, E as Effect, T as Trait, R as RenderUIEffect, a as TraitEventContract, b as Entity, c as TraitEventListener, d as TraitConfig, e as EntityField, f as EntityPersistence, g as EntityRow, h as UseDeclaration, i as EntityRef, j as TraitRef, P as PageRef, O as OrbitalDefinition, k as OrbitalSchema, l as Page, m as PageRefObject, n as TraitReference } from './schema-DyPfxNwk.js';
2
2
  import { S as SExpr } from './expression-eBO9-SQM.js';
3
- export { C as ComposeBehaviorsInput, a as ComposeBehaviorsResult, E as EventWiringEntry, L as LayoutStrategy, b as applyEventWiring, c as composeBehaviors, d as detectLayoutStrategy } from './compose-behaviors-UN56dMBD.js';
3
+ export { C as ComposeBehaviorsInput, a as ComposeBehaviorsResult, E as EventWiringEntry, L as LayoutStrategy, b as applyEventWiring, c as composeBehaviors, d as detectLayoutStrategy } from './compose-behaviors-D9fgB76L.js';
4
+ import { AnyPatternConfig } from '@almadar/patterns';
4
5
  import 'zod';
5
- import '@almadar/patterns';
6
+
7
+ /**
8
+ * Layout-Trait Builders
9
+ *
10
+ * Helpers for constructing the canonical inline LayoutTrait pattern that
11
+ * std layout-shell molecules (`std-filtered-list`, `std-master-detail-layout`,
12
+ * etc.) use to wrap a set of atom trait references in a `(render-ui main)`
13
+ * effect with `@trait.X` slot embeds.
14
+ *
15
+ * The canonical LayoutTrait is stateless: ONE state (`composing`, initial),
16
+ * ONE transition (`INIT` self-loop) carrying two effects — `(fetch Entity
17
+ * {emit: {success, failure}})` and `(render-ui "main" <pattern-tree>)`. Atoms
18
+ * embedded via `@trait.X` slot references react to the bus events the fetch
19
+ * emits; the LayoutTrait owns no further state.
20
+ *
21
+ * Usage from a std layout-shell molecule:
22
+ *
23
+ * ```ts
24
+ * import { makeSlot, makeLayoutTrait } from '@almadar/core/builders';
25
+ *
26
+ * const layout = makeLayoutTrait({
27
+ * name: 'DashboardLayout',
28
+ * linkedEntity: 'Metric',
29
+ * fetchEntity: 'Metric',
30
+ * loadedEvent: 'MetricLoaded',
31
+ * loadFailedEvent: 'MetricLoadFailed',
32
+ * renderUI: {
33
+ * type: 'stack',
34
+ * direction: 'vertical',
35
+ * children: [
36
+ * makeSlot('StatsRow'),
37
+ * makeSlot('ChartsRow'),
38
+ * makeSlot('FeedRow'),
39
+ * ],
40
+ * },
41
+ * });
42
+ * ```
43
+ *
44
+ * @packageDocumentation
45
+ */
46
+
47
+ /**
48
+ * Build a `@trait.<name>` slot reference string. Used as a child entry in a
49
+ * pattern tree to embed another trait's render-ui at that position. The
50
+ * runtime resolves `@trait.X` to the matching trait's render-ui inline.
51
+ *
52
+ * @example makeSlot('FilteredItemSearch') // "@trait.FilteredItemSearch"
53
+ */
54
+ declare function makeSlot(traitName: string): string;
55
+ /**
56
+ * Build a `(render-ui <slot> <root>)` effect tuple. Pattern-typed sugar over
57
+ * the raw `RenderUIEffect` literal so callers don't have to spell out the
58
+ * three-element tuple form.
59
+ *
60
+ * @param slot - Canonical UI slot name (`'main'`, `'header'`, etc. — see UI_SLOTS).
61
+ * @param root - The pattern config for this slot's content. Pass `null` to clear.
62
+ */
63
+ declare function makeRenderUI(slot: UISlot, root: AnyPatternConfig | null): RenderUIEffect;
64
+ /**
65
+ * Options for {@link makeLayoutTrait}.
66
+ */
67
+ interface MakeLayoutTraitOpts {
68
+ /** Trait name, e.g. `"DashboardGridLayout"`. */
69
+ name: string;
70
+ /** Entity this layout's emits/listens bind to. */
71
+ linkedEntity: string;
72
+ /** Optional human-readable description (carried through to `Trait.description`). */
73
+ description?: string;
74
+ /**
75
+ * Entity name to fetch on INIT. When set, a `(fetch <Entity> {emit:
76
+ * {success, failure}})` effect is prepended to the INIT transition. Omit
77
+ * for purely-presentational layouts that don't load data themselves.
78
+ */
79
+ fetchEntity?: string;
80
+ /**
81
+ * Event name emitted on successful fetch. Required when `fetchEntity` is
82
+ * set; the LayoutTrait declares this event in its `emits` and uses it as
83
+ * the `success` emit-name in the fetch effect.
84
+ * Convention: `"<Entity>Loaded"`.
85
+ */
86
+ loadedEvent?: string;
87
+ /**
88
+ * Event name emitted on fetch failure. Required when `fetchEntity` is
89
+ * set. Convention: `"<Entity>LoadFailed"`.
90
+ */
91
+ loadFailedEvent?: string;
92
+ /**
93
+ * Payload schema for the loaded event. Defaults to `[{ name: "data", type:
94
+ * "[<Entity>]" }]` when `fetchEntity` is set. Provide explicitly when the
95
+ * payload should carry additional fields.
96
+ */
97
+ loadedPayloadSchema?: Array<{
98
+ name: string;
99
+ type: string;
100
+ required?: boolean;
101
+ }>;
102
+ /**
103
+ * The pattern tree for the layout's main slot. Children may include
104
+ * `@trait.X` slot strings (built via {@link makeSlot}) interleaved with
105
+ * inline pattern configs (`{ type: 'stack', ... }`). The shape conforms to
106
+ * `AnyPatternConfig` from `@almadar/patterns`.
107
+ */
108
+ renderUI: AnyPatternConfig;
109
+ /**
110
+ * Override the slot the render-ui effect targets. Defaults to `'main'`.
111
+ * Specify when the layout shell should render into a sub-slot (rare).
112
+ */
113
+ slot?: UISlot;
114
+ /**
115
+ * Additional effects appended to the INIT transition AFTER the fetch +
116
+ * render-ui pair. Most layouts don't need this; provided for advanced
117
+ * cases (analytics emit, persistence seed, etc.).
118
+ */
119
+ extraEffects?: Effect[];
120
+ }
121
+ /**
122
+ * Build the canonical stateless LayoutTrait used by std layout-shell molecules.
123
+ *
124
+ * Result shape:
125
+ * - `category: 'interaction'`, `scope: 'instance'`
126
+ * - `linkedEntity` set per the option
127
+ * - `emits` declares the loaded + loadFailed events when `fetchEntity` is set
128
+ * - One state: `'composing'` (`isInitial: true`)
129
+ * - One transition: `composing → composing` on `INIT`, with effects:
130
+ * - (when `fetchEntity` set) `['fetch', '<Entity>', { emit: { success, failure } }]`
131
+ * - `['render-ui', slot, renderUI]`
132
+ * - …`extraEffects` if provided
133
+ *
134
+ * Atoms whose trait names appear as `@trait.<name>` strings inside `renderUI`
135
+ * get embedded by the runtime when the orbital instantiates. The LayoutTrait
136
+ * itself stays stateless — all reactive behaviour lives in the embedded atoms.
137
+ */
138
+ declare function makeLayoutTrait(opts: MakeLayoutTraitOpts): Trait;
6
139
 
7
140
  /**
8
141
  * Orbital Builders
@@ -295,4 +428,4 @@ declare function compose(orbitals: (OrbitalDefinition | OrbitalSchema)[], pages:
295
428
  */
296
429
  declare function pipe(orbitals: (OrbitalDefinition | OrbitalSchema)[], events: TraitEventContract[], appName?: string): OrbitalSchema;
297
430
 
298
- export { type ComposeConnection, type ComposePage, type MakeAtomOrbitalOpts, type MakeAtomOrbitalTraitOverrides, type MakeEntityOpts, type MakeOrbitalWithUsesOpts, type MakePageOpts, type MakePageRefOpts, type MakePageRefOptsTyped, type MakeTraitRefOpts, type MakeTraitRefOptsTyped, compose, connect, ensureIdField, extractTrait, makeAtomOrbital, makeEntity, makeOrbital, makeOrbitalWithUses, makePage, makePageRef, makeSchema, makeTraitRef, mergeOrbitals, pipe, plural, wire };
431
+ export { type ComposeConnection, type ComposePage, type MakeAtomOrbitalOpts, type MakeAtomOrbitalTraitOverrides, type MakeEntityOpts, type MakeLayoutTraitOpts, type MakeOrbitalWithUsesOpts, type MakePageOpts, type MakePageRefOpts, type MakePageRefOptsTyped, type MakeTraitRefOpts, type MakeTraitRefOptsTyped, compose, connect, ensureIdField, extractTrait, makeAtomOrbital, makeEntity, makeLayoutTrait, makeOrbital, makeOrbitalWithUses, makePage, makePageRef, makeRenderUI, makeSchema, makeSlot, makeTraitRef, mergeOrbitals, pipe, plural, wire };
package/dist/builders.js CHANGED
@@ -11,7 +11,8 @@ var FieldTypeSchema = z.enum([
11
11
  "array",
12
12
  "object",
13
13
  "enum",
14
- "relation"
14
+ "relation",
15
+ "trait"
15
16
  ]);
16
17
  var RelationCardinalitySchema = z.enum([
17
18
  "one",
@@ -1090,6 +1091,83 @@ function composeBehaviors(input) {
1090
1091
  };
1091
1092
  }
1092
1093
 
1094
+ // src/builders/layout-trait.ts
1095
+ function makeSlot(traitName) {
1096
+ return `@trait.${traitName}`;
1097
+ }
1098
+ function makeRenderUI(slot, root) {
1099
+ return root === null ? ["render-ui", slot, null] : ["render-ui", slot, root];
1100
+ }
1101
+ function makeLayoutTrait(opts) {
1102
+ const slot = opts.slot ?? "main";
1103
+ const effects = [];
1104
+ const emits = [];
1105
+ const eventDefs = [
1106
+ { key: "INIT", name: "Initialize" }
1107
+ ];
1108
+ if (opts.fetchEntity) {
1109
+ if (!opts.loadedEvent || !opts.loadFailedEvent) {
1110
+ throw new Error(
1111
+ `makeLayoutTrait: fetchEntity '${opts.fetchEntity}' set but loadedEvent / loadFailedEvent are required`
1112
+ );
1113
+ }
1114
+ const payloadSchema = opts.loadedPayloadSchema ?? [{ name: "data", type: `[${opts.fetchEntity}]` }];
1115
+ emits.push(
1116
+ { event: opts.loadedEvent, scope: "internal", payloadSchema },
1117
+ {
1118
+ event: opts.loadFailedEvent,
1119
+ scope: "internal",
1120
+ payloadSchema: [
1121
+ { name: "error", type: "string" },
1122
+ { name: "code", type: "string" }
1123
+ ]
1124
+ }
1125
+ );
1126
+ eventDefs.push(
1127
+ { key: opts.loadedEvent, name: `${opts.fetchEntity} loaded`, payloadSchema },
1128
+ {
1129
+ key: opts.loadFailedEvent,
1130
+ name: `${opts.fetchEntity} load failed`,
1131
+ payloadSchema: [
1132
+ { name: "error", type: "string" },
1133
+ { name: "code", type: "string" }
1134
+ ]
1135
+ }
1136
+ );
1137
+ const fetchFx = [
1138
+ "fetch",
1139
+ opts.fetchEntity,
1140
+ { emit: { success: opts.loadedEvent, failure: opts.loadFailedEvent } }
1141
+ ];
1142
+ effects.push(fetchFx);
1143
+ }
1144
+ effects.push(makeRenderUI(slot, opts.renderUI));
1145
+ if (opts.extraEffects && opts.extraEffects.length > 0) {
1146
+ effects.push(...opts.extraEffects);
1147
+ }
1148
+ const trait = {
1149
+ name: opts.name,
1150
+ ...opts.description ? { description: opts.description } : {},
1151
+ category: "interaction",
1152
+ linkedEntity: opts.linkedEntity,
1153
+ scope: "instance",
1154
+ ...emits.length > 0 ? { emits } : {},
1155
+ stateMachine: {
1156
+ states: [{ name: "composing", isInitial: true }],
1157
+ events: eventDefs,
1158
+ transitions: [
1159
+ {
1160
+ from: "composing",
1161
+ to: "composing",
1162
+ event: "INIT",
1163
+ effects
1164
+ }
1165
+ ]
1166
+ }
1167
+ };
1168
+ return trait;
1169
+ }
1170
+
1093
1171
  // src/builders.ts
1094
1172
  function ensureIdField(fields) {
1095
1173
  if (!fields || fields.length === 0) return [{ name: "id", type: "string", required: true }];
@@ -1336,6 +1414,6 @@ function pipe(orbitals, events, appName) {
1336
1414
  };
1337
1415
  }
1338
1416
 
1339
- export { applyEventWiring, compose, composeBehaviors, connect, detectLayoutStrategy, ensureIdField, extractTrait, makeAtomOrbital, makeEntity, makeOrbital, makeOrbitalWithUses, makePage, makePageRef, makeSchema, makeTraitRef, mergeOrbitals, pipe, plural, wire };
1417
+ export { applyEventWiring, compose, composeBehaviors, connect, detectLayoutStrategy, ensureIdField, extractTrait, makeAtomOrbital, makeEntity, makeLayoutTrait, makeOrbital, makeOrbitalWithUses, makePage, makePageRef, makeRenderUI, makeSchema, makeSlot, makeTraitRef, mergeOrbitals, pipe, plural, wire };
1340
1418
  //# sourceMappingURL=builders.js.map
1341
1419
  //# sourceMappingURL=builders.js.map