@almadar/ui 4.23.0 → 4.25.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.
- package/dist/avl/index.cjs +102 -16
- package/dist/avl/index.js +102 -16
- package/dist/components/index.cjs +48 -6
- package/dist/components/index.js +48 -6
- package/dist/context/UISlotContext.d.ts +2 -2
- package/dist/hooks/useUISlots.d.ts +65 -7
- package/dist/providers/index.cjs +48 -6
- package/dist/providers/index.js +48 -6
- package/dist/runtime/fn-form-lambda.d.ts +4 -3
- package/dist/runtime/index.cjs +102 -16
- package/dist/runtime/index.js +102 -16
- package/package.json +2 -2
|
@@ -1,4 +1,36 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* useUISlots Hook
|
|
3
|
+
*
|
|
4
|
+
* Core hook for managing UI slot rendering in the trait-driven architecture.
|
|
5
|
+
* Traits use render_ui effects to dynamically render content into slots.
|
|
6
|
+
*
|
|
7
|
+
* Slots:
|
|
8
|
+
* - main: Primary content area
|
|
9
|
+
* - sidebar: Left/right sidebar
|
|
10
|
+
* - modal: Modal overlay
|
|
11
|
+
* - drawer: Slide-in drawer
|
|
12
|
+
* - overlay: Full-screen overlay
|
|
13
|
+
* - center: Centered popup
|
|
14
|
+
* - toast: Toast notifications
|
|
15
|
+
* - hud-top: Game HUD top bar
|
|
16
|
+
* - hud-bottom: Game HUD bottom bar
|
|
17
|
+
* - floating: Draggable floating panel
|
|
18
|
+
*
|
|
19
|
+
* Multi-source model (2026-04-24):
|
|
20
|
+
* A slot can receive renders from multiple source traits across independent
|
|
21
|
+
* batches (e.g. in the playground, ProbeCreate renders "main" on INIT, then
|
|
22
|
+
* later ProbePersistor cascades a render into "main" too). Prior code stored
|
|
23
|
+
* a single SlotContent per slot and last-writer-wins silently dropped
|
|
24
|
+
* earlier traits' frames. Internally the manager now holds a
|
|
25
|
+
* `Record<UISlot, Record<sourceKey, SlotContent>>` map and consumers see an
|
|
26
|
+
* aggregated view: a single SlotContent for single-source slots, or a
|
|
27
|
+
* synthetic `stack` wrapper when 2+ sources are active simultaneously.
|
|
28
|
+
* This mirrors the compiled-path page layout's VStack-of-trait-views.
|
|
29
|
+
*
|
|
30
|
+
* @packageDocumentation
|
|
31
|
+
*/
|
|
32
|
+
import type React from 'react';
|
|
33
|
+
import type { EventPayloadValue, RenderItemLambda } from '@almadar/core';
|
|
2
34
|
/**
|
|
3
35
|
* Valid UI slot names
|
|
4
36
|
*/
|
|
@@ -8,13 +40,39 @@ export type UISlot = 'main' | 'sidebar' | 'modal' | 'drawer' | 'overlay' | 'cent
|
|
|
8
40
|
*/
|
|
9
41
|
export type SlotAnimation = 'fade' | 'slide' | 'scale' | 'none';
|
|
10
42
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
43
|
+
* Render-prop callback after fn-form-lambda conversion or
|
|
44
|
+
* `wrapCallbackForEvent` wrapping. Pattern components consume these as
|
|
45
|
+
* `renderItem` / `onTabChange` / `onClick` / etc. The arg list is
|
|
46
|
+
* contravariant (`never[]` accepts any caller shape — event handlers,
|
|
47
|
+
* 2-arg `(item, index)` render-props, etc.); the return is the union of
|
|
48
|
+
* shapes seen at this layer. Pattern-level prop types narrow the
|
|
49
|
+
* signature for each consumer downstream.
|
|
50
|
+
*/
|
|
51
|
+
export type SlotCallback = (...args: never[]) => void | React.ReactNode | EventPayloadValue;
|
|
52
|
+
/**
|
|
53
|
+
* Render-ui prop value: any leaf flowing from a `(render-ui slot {...})`
|
|
54
|
+
* effect into a React pattern component. The union enumerates every
|
|
55
|
+
* shape the renderer can receive — no `unknown` escape hatch.
|
|
56
|
+
*
|
|
57
|
+
* - JSON primitives (`string`, `number`, `boolean`, `Date`, `null`,
|
|
58
|
+
* `undefined`) come through `BindingResolver`.
|
|
59
|
+
* - `RenderItemLambda` is the unconverted tuple form `["fn", arg, body]`;
|
|
60
|
+
* `SlotCallback` is the post-conversion callable form.
|
|
61
|
+
* - `React.ReactNode` covers substituted `<TraitFrame>` elements.
|
|
62
|
+
* - The recursive array + object branches mirror the `EventPayloadValue`
|
|
63
|
+
* shape but with `SlotPropValue` leaves so functions and React nodes
|
|
64
|
+
* can appear at any depth (e.g. `tabs[].content: "@trait.X"` surviving
|
|
65
|
+
* substitution into a `ReactElement`).
|
|
66
|
+
*/
|
|
67
|
+
export type SlotPropValue = string | number | boolean | Date | null | undefined | RenderItemLambda | SlotCallback | React.ReactElement | ReadonlyArray<SlotPropValue> | {
|
|
68
|
+
readonly [key: string]: SlotPropValue;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Pattern-specific props carried by a rendered slot. The slot manager
|
|
72
|
+
* routes these from `(render-ui slot {...})` effects to React pattern
|
|
73
|
+
* components without coercion.
|
|
16
74
|
*/
|
|
17
|
-
export type SlotProps = Record<string,
|
|
75
|
+
export type SlotProps = Record<string, SlotPropValue>;
|
|
18
76
|
/**
|
|
19
77
|
* Content rendered in a slot
|
|
20
78
|
*/
|
package/dist/providers/index.cjs
CHANGED
|
@@ -38289,7 +38289,8 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
|
|
|
38289
38289
|
if (!child || typeof child !== "object") return null;
|
|
38290
38290
|
const childId = `${parentId}-${index}`;
|
|
38291
38291
|
const childPath = parentPath === "root" ? `root.children.${index}` : `${parentPath}.children.${index}`;
|
|
38292
|
-
const
|
|
38292
|
+
const childAsRecord = child;
|
|
38293
|
+
const { type: _childType, props: nestedProps, _id: _childNodeId, children: _childChildren, ...flatProps } = childAsRecord;
|
|
38293
38294
|
const resolvedProps = nestedProps !== void 0 ? nestedProps : flatProps;
|
|
38294
38295
|
if (_childChildren !== void 0 && nestedProps === void 0) {
|
|
38295
38296
|
resolvedProps.children = _childChildren;
|
|
@@ -38317,7 +38318,46 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
|
|
|
38317
38318
|
});
|
|
38318
38319
|
}
|
|
38319
38320
|
function isPatternConfig(value) {
|
|
38320
|
-
|
|
38321
|
+
if (value === null || value === void 0) return false;
|
|
38322
|
+
if (typeof value !== "object") return false;
|
|
38323
|
+
if (Array.isArray(value)) return false;
|
|
38324
|
+
if (React115__namespace.default.isValidElement(value)) return false;
|
|
38325
|
+
if (value instanceof Date) return false;
|
|
38326
|
+
if (typeof value === "function") return false;
|
|
38327
|
+
const record = value;
|
|
38328
|
+
return "type" in record && typeof record.type === "string";
|
|
38329
|
+
}
|
|
38330
|
+
function isPlainConfigObject(value) {
|
|
38331
|
+
if (React115__namespace.default.isValidElement(value)) return false;
|
|
38332
|
+
if (value instanceof Date) return false;
|
|
38333
|
+
const proto = Object.getPrototypeOf(value);
|
|
38334
|
+
return proto === Object.prototype || proto === null;
|
|
38335
|
+
}
|
|
38336
|
+
function substituteTraitRefsDeep(value, pathKey) {
|
|
38337
|
+
if (typeof value === "string") {
|
|
38338
|
+
const match = TRAIT_BINDING_RE.exec(value);
|
|
38339
|
+
if (match) {
|
|
38340
|
+
const traitName = match[1];
|
|
38341
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TraitFrame, { traitName }, `${pathKey}:${traitName}`);
|
|
38342
|
+
}
|
|
38343
|
+
return value;
|
|
38344
|
+
}
|
|
38345
|
+
if (typeof value === "number" || typeof value === "boolean" || value === null || value === void 0 || typeof value === "function") {
|
|
38346
|
+
return value;
|
|
38347
|
+
}
|
|
38348
|
+
if (Array.isArray(value)) {
|
|
38349
|
+
return value.map(
|
|
38350
|
+
(item, i) => substituteTraitRefsDeep(item, `${pathKey}[${i}]`)
|
|
38351
|
+
);
|
|
38352
|
+
}
|
|
38353
|
+
if (typeof value === "object" && isPlainConfigObject(value)) {
|
|
38354
|
+
const out = {};
|
|
38355
|
+
for (const [k, v] of Object.entries(value)) {
|
|
38356
|
+
out[k] = substituteTraitRefsDeep(v, `${pathKey}.${k}`);
|
|
38357
|
+
}
|
|
38358
|
+
return out;
|
|
38359
|
+
}
|
|
38360
|
+
return value;
|
|
38321
38361
|
}
|
|
38322
38362
|
function renderPatternProps(props, onDismiss) {
|
|
38323
38363
|
const rendered = {};
|
|
@@ -38325,17 +38365,19 @@ function renderPatternProps(props, onDismiss) {
|
|
|
38325
38365
|
if (key === "children") {
|
|
38326
38366
|
rendered[key] = value;
|
|
38327
38367
|
} else if (isPatternConfig(value)) {
|
|
38368
|
+
const nestedProps = {};
|
|
38369
|
+
for (const [k, v] of Object.entries(value)) {
|
|
38370
|
+
if (k !== "type") nestedProps[k] = v;
|
|
38371
|
+
}
|
|
38328
38372
|
const childContent = {
|
|
38329
38373
|
id: `prop-${key}`,
|
|
38330
38374
|
pattern: value.type,
|
|
38331
|
-
props:
|
|
38332
|
-
Object.entries(value).filter(([k]) => k !== "type")
|
|
38333
|
-
),
|
|
38375
|
+
props: nestedProps,
|
|
38334
38376
|
priority: 0
|
|
38335
38377
|
};
|
|
38336
38378
|
rendered[key] = /* @__PURE__ */ jsxRuntime.jsx(SlotContentRenderer, { content: childContent, onDismiss });
|
|
38337
38379
|
} else {
|
|
38338
|
-
rendered[key] = value;
|
|
38380
|
+
rendered[key] = substituteTraitRefsDeep(value, `prop:${key}`);
|
|
38339
38381
|
}
|
|
38340
38382
|
}
|
|
38341
38383
|
return rendered;
|
package/dist/providers/index.js
CHANGED
|
@@ -38244,7 +38244,8 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
|
|
|
38244
38244
|
if (!child || typeof child !== "object") return null;
|
|
38245
38245
|
const childId = `${parentId}-${index}`;
|
|
38246
38246
|
const childPath = parentPath === "root" ? `root.children.${index}` : `${parentPath}.children.${index}`;
|
|
38247
|
-
const
|
|
38247
|
+
const childAsRecord = child;
|
|
38248
|
+
const { type: _childType, props: nestedProps, _id: _childNodeId, children: _childChildren, ...flatProps } = childAsRecord;
|
|
38248
38249
|
const resolvedProps = nestedProps !== void 0 ? nestedProps : flatProps;
|
|
38249
38250
|
if (_childChildren !== void 0 && nestedProps === void 0) {
|
|
38250
38251
|
resolvedProps.children = _childChildren;
|
|
@@ -38272,7 +38273,46 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
|
|
|
38272
38273
|
});
|
|
38273
38274
|
}
|
|
38274
38275
|
function isPatternConfig(value) {
|
|
38275
|
-
|
|
38276
|
+
if (value === null || value === void 0) return false;
|
|
38277
|
+
if (typeof value !== "object") return false;
|
|
38278
|
+
if (Array.isArray(value)) return false;
|
|
38279
|
+
if (React115__default.isValidElement(value)) return false;
|
|
38280
|
+
if (value instanceof Date) return false;
|
|
38281
|
+
if (typeof value === "function") return false;
|
|
38282
|
+
const record = value;
|
|
38283
|
+
return "type" in record && typeof record.type === "string";
|
|
38284
|
+
}
|
|
38285
|
+
function isPlainConfigObject(value) {
|
|
38286
|
+
if (React115__default.isValidElement(value)) return false;
|
|
38287
|
+
if (value instanceof Date) return false;
|
|
38288
|
+
const proto = Object.getPrototypeOf(value);
|
|
38289
|
+
return proto === Object.prototype || proto === null;
|
|
38290
|
+
}
|
|
38291
|
+
function substituteTraitRefsDeep(value, pathKey) {
|
|
38292
|
+
if (typeof value === "string") {
|
|
38293
|
+
const match = TRAIT_BINDING_RE.exec(value);
|
|
38294
|
+
if (match) {
|
|
38295
|
+
const traitName = match[1];
|
|
38296
|
+
return /* @__PURE__ */ jsx(TraitFrame, { traitName }, `${pathKey}:${traitName}`);
|
|
38297
|
+
}
|
|
38298
|
+
return value;
|
|
38299
|
+
}
|
|
38300
|
+
if (typeof value === "number" || typeof value === "boolean" || value === null || value === void 0 || typeof value === "function") {
|
|
38301
|
+
return value;
|
|
38302
|
+
}
|
|
38303
|
+
if (Array.isArray(value)) {
|
|
38304
|
+
return value.map(
|
|
38305
|
+
(item, i) => substituteTraitRefsDeep(item, `${pathKey}[${i}]`)
|
|
38306
|
+
);
|
|
38307
|
+
}
|
|
38308
|
+
if (typeof value === "object" && isPlainConfigObject(value)) {
|
|
38309
|
+
const out = {};
|
|
38310
|
+
for (const [k, v] of Object.entries(value)) {
|
|
38311
|
+
out[k] = substituteTraitRefsDeep(v, `${pathKey}.${k}`);
|
|
38312
|
+
}
|
|
38313
|
+
return out;
|
|
38314
|
+
}
|
|
38315
|
+
return value;
|
|
38276
38316
|
}
|
|
38277
38317
|
function renderPatternProps(props, onDismiss) {
|
|
38278
38318
|
const rendered = {};
|
|
@@ -38280,17 +38320,19 @@ function renderPatternProps(props, onDismiss) {
|
|
|
38280
38320
|
if (key === "children") {
|
|
38281
38321
|
rendered[key] = value;
|
|
38282
38322
|
} else if (isPatternConfig(value)) {
|
|
38323
|
+
const nestedProps = {};
|
|
38324
|
+
for (const [k, v] of Object.entries(value)) {
|
|
38325
|
+
if (k !== "type") nestedProps[k] = v;
|
|
38326
|
+
}
|
|
38283
38327
|
const childContent = {
|
|
38284
38328
|
id: `prop-${key}`,
|
|
38285
38329
|
pattern: value.type,
|
|
38286
|
-
props:
|
|
38287
|
-
Object.entries(value).filter(([k]) => k !== "type")
|
|
38288
|
-
),
|
|
38330
|
+
props: nestedProps,
|
|
38289
38331
|
priority: 0
|
|
38290
38332
|
};
|
|
38291
38333
|
rendered[key] = /* @__PURE__ */ jsx(SlotContentRenderer, { content: childContent, onDismiss });
|
|
38292
38334
|
} else {
|
|
38293
|
-
rendered[key] = value;
|
|
38335
|
+
rendered[key] = substituteTraitRefsDeep(value, `prop:${key}`);
|
|
38294
38336
|
}
|
|
38295
38337
|
}
|
|
38296
38338
|
return rendered;
|
|
@@ -10,17 +10,18 @@
|
|
|
10
10
|
* @packageDocumentation
|
|
11
11
|
*/
|
|
12
12
|
import type { EntityRow, RenderItemLambda } from "@almadar/core";
|
|
13
|
-
|
|
13
|
+
import type { SlotProps, SlotPropValue } from "../hooks/useUISlots";
|
|
14
|
+
export declare function isFnFormLambda(value: SlotPropValue): value is RenderItemLambda;
|
|
14
15
|
/**
|
|
15
16
|
* Walk a pattern body replacing every `@<argName>.path` string with the
|
|
16
17
|
* value at `path` of `arg`. Mirrors the compiler's inline substitution
|
|
17
18
|
* for `renderItem` lambda bodies.
|
|
18
19
|
*/
|
|
19
|
-
export declare function resolveLambdaBindings(body:
|
|
20
|
+
export declare function resolveLambdaBindings(body: SlotPropValue, argName: string, arg: EntityRow): SlotPropValue;
|
|
20
21
|
/**
|
|
21
22
|
* Walk a pattern's props (and recursively their nested children),
|
|
22
23
|
* converting every fn-form lambda value into a React render-prop
|
|
23
24
|
* function. Pure on inputs without lambdas: returns the props object
|
|
24
25
|
* unchanged by reference.
|
|
25
26
|
*/
|
|
26
|
-
export declare function convertFnFormLambdasInProps(props:
|
|
27
|
+
export declare function convertFnFormLambdasInProps(props: SlotProps): SlotProps;
|
package/dist/runtime/index.cjs
CHANGED
|
@@ -37882,7 +37882,8 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
|
|
|
37882
37882
|
if (!child || typeof child !== "object") return null;
|
|
37883
37883
|
const childId = `${parentId}-${index}`;
|
|
37884
37884
|
const childPath = parentPath === "root" ? `root.children.${index}` : `${parentPath}.children.${index}`;
|
|
37885
|
-
const
|
|
37885
|
+
const childAsRecord = child;
|
|
37886
|
+
const { type: _childType, props: nestedProps, _id: _childNodeId, children: _childChildren, ...flatProps } = childAsRecord;
|
|
37886
37887
|
const resolvedProps = nestedProps !== void 0 ? nestedProps : flatProps;
|
|
37887
37888
|
if (_childChildren !== void 0 && nestedProps === void 0) {
|
|
37888
37889
|
resolvedProps.children = _childChildren;
|
|
@@ -37910,7 +37911,46 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
|
|
|
37910
37911
|
});
|
|
37911
37912
|
}
|
|
37912
37913
|
function isPatternConfig(value) {
|
|
37913
|
-
|
|
37914
|
+
if (value === null || value === void 0) return false;
|
|
37915
|
+
if (typeof value !== "object") return false;
|
|
37916
|
+
if (Array.isArray(value)) return false;
|
|
37917
|
+
if (React113__namespace.default.isValidElement(value)) return false;
|
|
37918
|
+
if (value instanceof Date) return false;
|
|
37919
|
+
if (typeof value === "function") return false;
|
|
37920
|
+
const record = value;
|
|
37921
|
+
return "type" in record && typeof record.type === "string";
|
|
37922
|
+
}
|
|
37923
|
+
function isPlainConfigObject(value) {
|
|
37924
|
+
if (React113__namespace.default.isValidElement(value)) return false;
|
|
37925
|
+
if (value instanceof Date) return false;
|
|
37926
|
+
const proto = Object.getPrototypeOf(value);
|
|
37927
|
+
return proto === Object.prototype || proto === null;
|
|
37928
|
+
}
|
|
37929
|
+
function substituteTraitRefsDeep(value, pathKey) {
|
|
37930
|
+
if (typeof value === "string") {
|
|
37931
|
+
const match = TRAIT_BINDING_RE.exec(value);
|
|
37932
|
+
if (match) {
|
|
37933
|
+
const traitName = match[1];
|
|
37934
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TraitFrame, { traitName }, `${pathKey}:${traitName}`);
|
|
37935
|
+
}
|
|
37936
|
+
return value;
|
|
37937
|
+
}
|
|
37938
|
+
if (typeof value === "number" || typeof value === "boolean" || value === null || value === void 0 || typeof value === "function") {
|
|
37939
|
+
return value;
|
|
37940
|
+
}
|
|
37941
|
+
if (Array.isArray(value)) {
|
|
37942
|
+
return value.map(
|
|
37943
|
+
(item, i) => substituteTraitRefsDeep(item, `${pathKey}[${i}]`)
|
|
37944
|
+
);
|
|
37945
|
+
}
|
|
37946
|
+
if (typeof value === "object" && isPlainConfigObject(value)) {
|
|
37947
|
+
const out = {};
|
|
37948
|
+
for (const [k, v] of Object.entries(value)) {
|
|
37949
|
+
out[k] = substituteTraitRefsDeep(v, `${pathKey}.${k}`);
|
|
37950
|
+
}
|
|
37951
|
+
return out;
|
|
37952
|
+
}
|
|
37953
|
+
return value;
|
|
37914
37954
|
}
|
|
37915
37955
|
function renderPatternProps(props, onDismiss) {
|
|
37916
37956
|
const rendered = {};
|
|
@@ -37918,17 +37958,19 @@ function renderPatternProps(props, onDismiss) {
|
|
|
37918
37958
|
if (key === "children") {
|
|
37919
37959
|
rendered[key] = value;
|
|
37920
37960
|
} else if (isPatternConfig(value)) {
|
|
37961
|
+
const nestedProps = {};
|
|
37962
|
+
for (const [k, v] of Object.entries(value)) {
|
|
37963
|
+
if (k !== "type") nestedProps[k] = v;
|
|
37964
|
+
}
|
|
37921
37965
|
const childContent = {
|
|
37922
37966
|
id: `prop-${key}`,
|
|
37923
37967
|
pattern: value.type,
|
|
37924
|
-
props:
|
|
37925
|
-
Object.entries(value).filter(([k]) => k !== "type")
|
|
37926
|
-
),
|
|
37968
|
+
props: nestedProps,
|
|
37927
37969
|
priority: 0
|
|
37928
37970
|
};
|
|
37929
37971
|
rendered[key] = /* @__PURE__ */ jsxRuntime.jsx(SlotContentRenderer, { content: childContent, onDismiss });
|
|
37930
37972
|
} else {
|
|
37931
|
-
rendered[key] = value;
|
|
37973
|
+
rendered[key] = substituteTraitRefsDeep(value, `prop:${key}`);
|
|
37932
37974
|
}
|
|
37933
37975
|
}
|
|
37934
37976
|
return rendered;
|
|
@@ -38271,7 +38313,7 @@ function resolveLambdaBindings(body, argName, arg) {
|
|
|
38271
38313
|
let cur = arg;
|
|
38272
38314
|
for (const seg of path.split(".")) {
|
|
38273
38315
|
if (cur === null || cur === void 0) return void 0;
|
|
38274
|
-
if (typeof cur !== "object") return void 0;
|
|
38316
|
+
if (typeof cur !== "object" || Array.isArray(cur)) return void 0;
|
|
38275
38317
|
cur = cur[seg];
|
|
38276
38318
|
}
|
|
38277
38319
|
return cur;
|
|
@@ -38287,7 +38329,7 @@ function resolveLambdaBindings(body, argName, arg) {
|
|
|
38287
38329
|
if (Array.isArray(body)) {
|
|
38288
38330
|
return body.map((b) => resolveLambdaBindings(b, argName, arg));
|
|
38289
38331
|
}
|
|
38290
|
-
if (body !== null && typeof body === "object") {
|
|
38332
|
+
if (body !== null && typeof body === "object" && !React113__namespace.default.isValidElement(body) && !(body instanceof Date) && typeof body !== "function") {
|
|
38291
38333
|
const out = {};
|
|
38292
38334
|
for (const [k, v] of Object.entries(body)) {
|
|
38293
38335
|
out[k] = resolveLambdaBindings(v, argName, arg);
|
|
@@ -38306,7 +38348,7 @@ function getSlotContentRenderer2() {
|
|
|
38306
38348
|
function makeLambdaFn(argName, lambdaBody, callerKey) {
|
|
38307
38349
|
return (item, index) => {
|
|
38308
38350
|
const resolvedBody = resolveLambdaBindings(lambdaBody, argName, item);
|
|
38309
|
-
if (resolvedBody === null || typeof resolvedBody !== "object" || Array.isArray(resolvedBody)) {
|
|
38351
|
+
if (resolvedBody === null || typeof resolvedBody !== "object" || Array.isArray(resolvedBody) || typeof resolvedBody === "function" || React113__namespace.default.isValidElement(resolvedBody) || resolvedBody instanceof Date) {
|
|
38310
38352
|
return null;
|
|
38311
38353
|
}
|
|
38312
38354
|
const record = resolvedBody;
|
|
@@ -38314,12 +38356,14 @@ function makeLambdaFn(argName, lambdaBody, callerKey) {
|
|
|
38314
38356
|
return null;
|
|
38315
38357
|
}
|
|
38316
38358
|
const SlotContentRenderer2 = getSlotContentRenderer2();
|
|
38359
|
+
const childProps = {};
|
|
38360
|
+
for (const [k, v] of Object.entries(record)) {
|
|
38361
|
+
if (k !== "type") childProps[k] = v;
|
|
38362
|
+
}
|
|
38317
38363
|
const childContent = {
|
|
38318
38364
|
id: `lambda-${callerKey}-${index}`,
|
|
38319
38365
|
pattern: record.type,
|
|
38320
|
-
props:
|
|
38321
|
-
Object.entries(record).filter(([k]) => k !== "type")
|
|
38322
|
-
),
|
|
38366
|
+
props: childProps,
|
|
38323
38367
|
priority: 0
|
|
38324
38368
|
};
|
|
38325
38369
|
return React113__namespace.default.createElement(SlotContentRenderer2, { content: childContent });
|
|
@@ -38332,15 +38376,16 @@ function convertNode(node, callerKey) {
|
|
|
38332
38376
|
const [, argName, body] = node;
|
|
38333
38377
|
return makeLambdaFn(argName, body, callerKey);
|
|
38334
38378
|
}
|
|
38379
|
+
const arr = node;
|
|
38335
38380
|
let anyChanged = false;
|
|
38336
|
-
const mapped =
|
|
38381
|
+
const mapped = arr.map((item, i) => {
|
|
38337
38382
|
const next = convertNode(item, `${callerKey}[${i}]`);
|
|
38338
38383
|
if (next !== item) anyChanged = true;
|
|
38339
38384
|
return next;
|
|
38340
38385
|
});
|
|
38341
38386
|
return anyChanged ? mapped : node;
|
|
38342
38387
|
}
|
|
38343
|
-
if (typeof node === "object") {
|
|
38388
|
+
if (typeof node === "object" && !React113__namespace.default.isValidElement(node) && !(node instanceof Date)) {
|
|
38344
38389
|
return convertObjectProps(node);
|
|
38345
38390
|
}
|
|
38346
38391
|
return node;
|
|
@@ -39531,6 +39576,7 @@ function prepareSchemaForPreview(input) {
|
|
|
39531
39576
|
// runtime/OrbPreview.tsx
|
|
39532
39577
|
init_logger();
|
|
39533
39578
|
var xOrbitalLog2 = createLogger("almadar:runtime:cross-orbital");
|
|
39579
|
+
var navLog = createLogger("almadar:runtime:navigation");
|
|
39534
39580
|
function normalizeChild(child) {
|
|
39535
39581
|
if (typeof child === "string") return child;
|
|
39536
39582
|
if (child === null || typeof child !== "object" || Array.isArray(child)) {
|
|
@@ -39606,6 +39652,19 @@ function TraitInitializer({ traits: traits2, orbitalNames, onNavigate, onLocalFa
|
|
|
39606
39652
|
}, [bridge.connected, bridge.sendEvent, orbitalNames, uiSlots, onNavigate, embeddedTraits]);
|
|
39607
39653
|
const opts = orbitalNames ? { onEventProcessed, navigate: onNavigate, traitConfigsByName, orbitalsByTrait, embeddedTraits } : { navigate: onNavigate, persistence, traitConfigsByName, orbitalsByTrait, embeddedTraits };
|
|
39608
39654
|
const { sendEvent } = useTraitStateMachine(traits2, uiSlots, opts);
|
|
39655
|
+
const prevTraitNamesRef = React113.useRef("");
|
|
39656
|
+
React113.useEffect(() => {
|
|
39657
|
+
const traitNames = traits2.map((b) => b.trait?.name ?? "").filter(Boolean).sort().join(",");
|
|
39658
|
+
if (prevTraitNamesRef.current && prevTraitNamesRef.current !== traitNames) {
|
|
39659
|
+
navLog.info("page:trait-set-changed", {
|
|
39660
|
+
from: prevTraitNamesRef.current,
|
|
39661
|
+
to: traitNames,
|
|
39662
|
+
action: "clearAll-slots"
|
|
39663
|
+
});
|
|
39664
|
+
uiSlots.clearAll();
|
|
39665
|
+
}
|
|
39666
|
+
prevTraitNamesRef.current = traitNames;
|
|
39667
|
+
}, [traits2, uiSlots]);
|
|
39609
39668
|
const initSentRef = React113.useRef(false);
|
|
39610
39669
|
React113.useEffect(() => {
|
|
39611
39670
|
if (!orbitalNames?.length) {
|
|
@@ -39620,6 +39679,10 @@ function TraitInitializer({ traits: traits2, orbitalNames, onNavigate, onLocalFa
|
|
|
39620
39679
|
}, 5e3);
|
|
39621
39680
|
return () => clearTimeout(fallback);
|
|
39622
39681
|
}, [traits2, orbitalNames, sendEvent, onLocalFallback]);
|
|
39682
|
+
const orbitalsKey = (orbitalNames ?? []).slice().sort().join(",");
|
|
39683
|
+
React113.useEffect(() => {
|
|
39684
|
+
initSentRef.current = false;
|
|
39685
|
+
}, [orbitalsKey]);
|
|
39623
39686
|
React113.useEffect(() => {
|
|
39624
39687
|
if (!bridge.connected || !orbitalNames?.length || initSentRef.current) return;
|
|
39625
39688
|
initSentRef.current = true;
|
|
@@ -39860,8 +39923,19 @@ function OrbPreview({
|
|
|
39860
39923
|
}, [initialPageName, currentPage]);
|
|
39861
39924
|
const handleNavigate = React113.useCallback((path) => {
|
|
39862
39925
|
const match = pages.find(({ page }) => page.path === path);
|
|
39926
|
+
navLog.info("handleNavigate", {
|
|
39927
|
+
path,
|
|
39928
|
+
matched: match?.page.name ?? null,
|
|
39929
|
+
availablePaths: pages.map((p2) => p2.page.path)
|
|
39930
|
+
});
|
|
39863
39931
|
if (match) {
|
|
39864
39932
|
setCurrentPage(match.page.name);
|
|
39933
|
+
if (typeof window !== "undefined") {
|
|
39934
|
+
const url = new URL(window.location.href);
|
|
39935
|
+
url.searchParams.set("page", path);
|
|
39936
|
+
window.history.pushState({}, "", url.toString());
|
|
39937
|
+
window.dispatchEvent(new PopStateEvent("popstate"));
|
|
39938
|
+
}
|
|
39865
39939
|
}
|
|
39866
39940
|
}, [pages]);
|
|
39867
39941
|
if (!parseResult.ok) {
|
|
@@ -39873,18 +39947,30 @@ function OrbPreview({
|
|
|
39873
39947
|
const containerRef = React113.useRef(null);
|
|
39874
39948
|
React113.useEffect(() => {
|
|
39875
39949
|
const el = containerRef.current;
|
|
39876
|
-
if (!el
|
|
39950
|
+
if (!el) return;
|
|
39951
|
+
if (pages.length <= 1) {
|
|
39952
|
+
navLog.info("interceptor:skipped", { reason: "single-page schema", pageCount: pages.length });
|
|
39953
|
+
return;
|
|
39954
|
+
}
|
|
39877
39955
|
const handler = (e) => {
|
|
39878
39956
|
const anchor = e.target.closest("a");
|
|
39879
39957
|
if (!anchor) return;
|
|
39880
39958
|
const href = anchor.getAttribute("href") ?? anchor.getAttribute("to") ?? "";
|
|
39881
|
-
|
|
39959
|
+
navLog.info("click:intercepted", {
|
|
39960
|
+
href,
|
|
39961
|
+
anchorText: anchor.textContent?.trim().slice(0, 40)
|
|
39962
|
+
});
|
|
39963
|
+
if (!href || href.startsWith("http") || href.startsWith("mailto:") || href.startsWith("#")) {
|
|
39964
|
+
navLog.info("click:skipped", { href, reason: "external/empty/hash" });
|
|
39965
|
+
return;
|
|
39966
|
+
}
|
|
39882
39967
|
e.preventDefault();
|
|
39883
39968
|
e.stopPropagation();
|
|
39884
39969
|
e.stopImmediatePropagation();
|
|
39885
39970
|
handleNavigate(href);
|
|
39886
39971
|
};
|
|
39887
39972
|
el.addEventListener("click", handler, true);
|
|
39973
|
+
navLog.info("interceptor:installed", { pageCount: pages.length, paths: pages.map((p2) => p2.page.path) });
|
|
39888
39974
|
return () => el.removeEventListener("click", handler, true);
|
|
39889
39975
|
}, [pages, handleNavigate]);
|
|
39890
39976
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|