@almadar/ui 6.51.2 → 6.53.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/{EntityBindingContext-BbxrwSb9.d.ts → AwaitingSkeletonContext-Bh399p1x.d.ts} +17 -2
- package/dist/{Canvas3DHost-CLC_jXh_.d.ts → Canvas3DHost-B-y2TNij.d.ts} +1 -1
- package/dist/{FileTree-RKQqRhIM.d.ts → FileTree-DUi7e7Z8.d.ts} +5 -5
- package/dist/{GameAudioProvider-BgWLggIy.d.ts → GameAudioProvider-DyBvYP2c.d.ts} +1 -1
- package/dist/{NavStackContext-B-XLULCO.d.ts → NavStackContext-04NLdXsY.d.ts} +8 -0
- package/dist/Typography-JGSDH4JP.js +5 -0
- package/dist/{UISlotContext-DNM8iXna.d.ts → UISlotContext-CS487Uoc.d.ts} +1 -1
- package/dist/{UISlotRenderer-7UYHFW4S.js → UISlotRenderer-JT34I3O7.js} +9 -9
- package/dist/avl/index.cjs +39958 -38525
- package/dist/avl/index.d.ts +8 -5
- package/dist/avl/index.js +37 -26
- package/dist/{chunk-JXUYEO7U.js → chunk-2LFBQ4IS.js} +7 -1
- package/dist/{chunk-GIPZSCND.js → chunk-3EF5SDIJ.js} +31157 -31206
- package/dist/{chunk-GHXWGQTX.js → chunk-4OZDHCZV.js} +1 -1
- package/dist/{chunk-HQDKHLFG.js → chunk-64WACXM7.js} +15 -1
- package/dist/{chunk-FGHRVJCI.js → chunk-6O37FCX4.js} +13 -2
- package/dist/{chunk-BUEIZY54.js → chunk-7LM6I3NA.js} +8 -7
- package/dist/chunk-CBIJP5PL.js +284 -0
- package/dist/{chunk-MWPX2O4M.js → chunk-GMDMOYXD.js} +3 -16
- package/dist/{chunk-YKHNK5JH.js → chunk-GODZKHAL.js} +11 -4
- package/dist/{chunk-T7IH5ABO.js → chunk-IKULQIDX.js} +199 -88
- package/dist/{chunk-NTO555KF.js → chunk-JRW33U35.js} +183 -62
- package/dist/{chunk-OLZ3EEML.js → chunk-KQXXO42S.js} +106 -90
- package/dist/chunk-OKWD7LPO.js +80 -0
- package/dist/{chunk-YHY5K2Y7.js → chunk-PEST66PN.js} +6 -0
- package/dist/{chunk-L55SAFKL.js → chunk-UGHAADU5.js} +77 -1
- package/dist/{chunk-6CFYRP4S.js → chunk-VHTJRS2N.js} +4 -8
- package/dist/{chunk-R4V7IZQP.js → chunk-WPNM2KC6.js} +2 -2
- package/dist/{cn-CO-0rolG.d.ts → cn-ClXGlIOY.d.ts} +2 -2
- package/dist/components/index.cjs +46084 -44766
- package/dist/components/index.d.ts +645 -699
- package/dist/components/index.js +621 -13
- package/dist/context/index.cjs +20 -7
- package/dist/context/index.d.ts +3 -3
- package/dist/context/index.js +3 -3
- package/dist/hooks/index.cjs +126 -9
- package/dist/hooks/index.d.ts +32 -7
- package/dist/hooks/index.js +7 -7
- package/dist/lib/drawable/three/index.cjs +79 -2
- package/dist/lib/drawable/three/index.d.ts +3 -3
- package/dist/lib/drawable/three/index.js +7 -7
- package/dist/lib/index.cjs +116 -2
- package/dist/lib/index.d.ts +29 -6
- package/dist/lib/index.js +6 -5
- package/dist/locales/index.cjs +231 -3
- package/dist/locales/index.js +155 -3
- package/dist/{paintDispatch-CMgOyVjS.d.ts → paintDispatch-_6EhJCiL.d.ts} +6 -6
- package/dist/providers/index.cjs +36404 -35028
- package/dist/providers/index.d.ts +34 -9
- package/dist/providers/index.js +82 -19
- package/dist/renderer/index.cjs +6 -0
- package/dist/renderer/index.d.ts +1 -1
- package/dist/renderer/index.js +1 -1
- package/dist/runtime/index.cjs +37861 -36437
- package/dist/runtime/index.d.ts +6 -4
- package/dist/runtime/index.js +11 -11
- package/dist/ssr/index.cjs +584 -181
- package/dist/ssr/index.d.cts +36 -44
- package/dist/ssr/index.d.ts +36 -44
- package/dist/ssr/index.js +527 -124
- package/dist/{themeTokens-CN9WCXQc.d.ts → themeTokens-Ccu7EmGY.d.ts} +4 -2
- package/dist/{useUISlots-CwUWM1ra.d.ts → useUISlots-1dk2TR4j.d.ts} +1 -9
- package/dist/{verificationRegistry-DBHfOR9y.d.ts → verificationRegistry-CD7Xb40L.d.ts} +1 -1
- package/locales/ar.json +77 -1
- package/locales/en.json +77 -1
- package/locales/sl.json +77 -1
- package/package.json +13 -10
- package/tailwind-preset.cjs +37 -1
- package/themes/_base.css +114 -8
- package/themes/_contract.md +6 -0
- package/themes/almadar-website.css +2 -0
- package/themes/almadar.css +2 -0
- package/themes/aqua.css +5 -3
- package/themes/arabesque.css +9 -7
- package/themes/art-deco.css +5 -3
- package/themes/art-nouveau.css +4 -0
- package/themes/atelier.css +10 -8
- package/themes/bauhaus.css +2 -0
- package/themes/bloomberg-dense.css +13 -11
- package/themes/blueprint.css +2 -0
- package/themes/clay.css +2 -0
- package/themes/comic.css +12 -10
- package/themes/constructivist.css +2 -0
- package/themes/corporate.css +4 -2
- package/themes/cyberpunk.css +2 -0
- package/themes/frutiger-aero.css +2 -0
- package/themes/game-adventure.css +1 -0
- package/themes/game-rpg.css +1 -0
- package/themes/game-sci-fi.css +1 -0
- package/themes/game-ui-pack.css +1 -0
- package/themes/gazette.css +10 -8
- package/themes/glass.css +17 -15
- package/themes/gothic.css +2 -0
- package/themes/ink-wash.css +2 -0
- package/themes/kawaii.css +2 -0
- package/themes/kiosk.css +17 -15
- package/themes/linear-clean.css +12 -10
- package/themes/luxury.css +2 -0
- package/themes/mac-classic.css +2 -0
- package/themes/material.css +2 -0
- package/themes/memphis.css +2 -0
- package/themes/mid-century.css +2 -0
- package/themes/minimalist.css +2 -0
- package/themes/mudcloth.css +2 -0
- package/themes/neon.css +2 -0
- package/themes/neumorphic.css +2 -0
- package/themes/newsprint.css +2 -0
- package/themes/notion-editorial.css +12 -10
- package/themes/pixel.css +2 -0
- package/themes/prism.css +20 -18
- package/themes/retro.css +2 -0
- package/themes/risograph.css +2 -0
- package/themes/scandi.css +2 -0
- package/themes/sketch.css +2 -0
- package/themes/solarpunk.css +2 -0
- package/themes/steampunk.css +2 -0
- package/themes/swiss.css +2 -0
- package/themes/terminal.css +8 -6
- package/themes/trait-wars.css +2 -0
- package/themes/ukiyo-e.css +2 -0
- package/themes/vaporwave.css +2 -0
- package/themes/victorian.css +2 -0
- package/themes/wabi-sabi.css +2 -0
- package/themes/win95.css +2 -0
- package/themes/wireframe.css +2 -0
- package/themes/zine.css +2 -0
- package/dist/Typography-2Z3JKWHN.js +0 -5
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { runTickFrame } from './chunk-DQTV6QVS.js';
|
|
2
|
-
import { ALL_SLOTS } from './chunk-
|
|
3
|
-
import { UISlotRenderer } from './chunk-
|
|
4
|
-
import { Box } from './chunk-
|
|
5
|
-
import { Typography } from './chunk-
|
|
2
|
+
import { ALL_SLOTS } from './chunk-VHTJRS2N.js';
|
|
3
|
+
import { UISlotRenderer } from './chunk-3EF5SDIJ.js';
|
|
4
|
+
import { Box } from './chunk-7LM6I3NA.js';
|
|
5
|
+
import { Typography } from './chunk-GMDMOYXD.js';
|
|
6
|
+
import { beginPending, endPending } from './chunk-JRW33U35.js';
|
|
6
7
|
import { useEventBus } from './chunk-6EV3OEBQ.js';
|
|
7
|
-
import { registerTrait, unregisterTrait, perfTimeAsync } from './chunk-
|
|
8
|
+
import { registerTrait, unregisterTrait, perfTimeAsync } from './chunk-KQXXO42S.js';
|
|
8
9
|
import { bindTraitStateGetter, registerTraitSnapshot, recordTransition, recordingTransport, recordServerResponse } from './chunk-O7OLVVBR.js';
|
|
9
|
-
import { isNotificationSlot } from './chunk-
|
|
10
|
+
import { isNotificationSlot } from './chunk-PEST66PN.js';
|
|
10
11
|
import React, { useState, useMemo, useEffect, useRef, useCallback, useSyncExternalStore } from 'react';
|
|
11
12
|
import { schemaToIR, getPage, clearSchemaCache as clearSchemaCache$1, applyListenPayloadMapping, buildResolvedTraitConfigs, collectCallsiteCaptureChildren, walkSExpr, isRenderBindingMarker, containsEntityBinding, isSExpr, isEventPayloadValue, RENDER_BINDING_MARKER } from '@almadar/core';
|
|
12
13
|
import { createLogger } from '@almadar/logger';
|
|
13
|
-
import { LIFECYCLE_EVENTS, InMemoryPersistence, createInProcessTransport, buildTraitIndex, createMemoryCircuitStore, createIndexStageRunner, evaluateOrbitalEvent, createClientKernel,
|
|
14
|
-
import { useUser, useArbitraryClassStyles, getAllPages, matchPathAmong, CurrentPagePathProvider, NavStackProvider, OrbitalProvider, useNavStack, VerificationProvider, EntitySchemaProvider, OrbitalThemeProvider, ServerBridgeProvider, useServerBridge, EntityBindingContext } from '@almadar/ui/providers';
|
|
14
|
+
import { collectListenerTargets, LIFECYCLE_EVENTS, InMemoryPersistence, createInProcessTransport, buildTraitIndex, createMemoryCircuitStore, createIndexStageRunner, evaluateOrbitalEvent, createClientKernel, createTickScheduler, isValidCronExpression, parseDurationString, UNMOUNT_EVENT, createClientEffectHandlers, EffectExecutor, isSExpression, collectDeclaredConfigDefaults, createContextFromBindings, normalizeCallSiteConfigToValues } from '@almadar/runtime';
|
|
15
|
+
import { useUser, useArbitraryClassStyles, getAllPages, matchPathAmong, CurrentPagePathProvider, NavStackProvider, OrbitalProvider, useNavStack, VerificationProvider, EntitySchemaProvider, OrbitalThemeProvider, ServerBridgeProvider, useServerBridge, EntityBindingContext, AwaitingSkeletonContext } from '@almadar/ui/providers';
|
|
15
16
|
import { evaluateListenPayloadExpr, evaluate, createMinimalContext, evaluateGuard, executeEffects } from '@almadar/evaluator';
|
|
16
17
|
import { getPatternDefinition } from '@almadar/core/patterns';
|
|
17
18
|
import { isKnownStdOperator } from '@almadar/std/registry';
|
|
@@ -269,6 +270,18 @@ function useCircuitKernel(traitBindings, options) {
|
|
|
269
270
|
[baseTransport]
|
|
270
271
|
);
|
|
271
272
|
const orbitalName = options.orbitals[0]?.name ?? "";
|
|
273
|
+
const topology = useMemo(() => {
|
|
274
|
+
let resolve = () => void 0;
|
|
275
|
+
const promise = new Promise((r) => {
|
|
276
|
+
resolve = r;
|
|
277
|
+
});
|
|
278
|
+
return { promise, resolve };
|
|
279
|
+
}, [effectiveTransport]);
|
|
280
|
+
const awaitTopology = options.awaitTopology === true;
|
|
281
|
+
const confirmedCarries = options.carriesCircuitState ?? false;
|
|
282
|
+
useEffect(() => {
|
|
283
|
+
if (!awaitTopology) topology.resolve({ carriesCircuitState: confirmedCarries });
|
|
284
|
+
}, [awaitTopology, confirmedCarries, topology]);
|
|
272
285
|
const rawKernel = useMemo(() => createClientKernel({
|
|
273
286
|
orbitalName,
|
|
274
287
|
traitIndex,
|
|
@@ -281,7 +294,8 @@ function useCircuitKernel(traitBindings, options) {
|
|
|
281
294
|
...options.contextExtensions !== void 0 ? { contextExtensions: options.contextExtensions } : {},
|
|
282
295
|
...options.debug !== void 0 ? { debug: options.debug } : {},
|
|
283
296
|
...options.logContext !== void 0 ? { logContext: options.logContext } : {},
|
|
284
|
-
carriesCircuitState:
|
|
297
|
+
carriesCircuitState: false,
|
|
298
|
+
topology: topology.promise,
|
|
285
299
|
...effectiveTransport !== void 0 ? { transport: effectiveTransport } : {}
|
|
286
300
|
}), [
|
|
287
301
|
orbitalName,
|
|
@@ -295,50 +309,16 @@ function useCircuitKernel(traitBindings, options) {
|
|
|
295
309
|
options.contextExtensions,
|
|
296
310
|
options.debug,
|
|
297
311
|
options.logContext,
|
|
298
|
-
|
|
312
|
+
topology,
|
|
299
313
|
effectiveTransport
|
|
300
314
|
]);
|
|
301
|
-
const rawKernelRef = useRef(rawKernel);
|
|
302
|
-
rawKernelRef.current = rawKernel;
|
|
303
|
-
const awaitTopology = options.awaitTopology === true;
|
|
304
|
-
const holdRef = useRef(awaitTopology);
|
|
305
|
-
holdRef.current = awaitTopology;
|
|
306
|
-
const heldRef = useRef([]);
|
|
307
|
-
useEffect(() => {
|
|
308
|
-
if (awaitTopology) return;
|
|
309
|
-
const held = heldRef.current;
|
|
310
|
-
heldRef.current = [];
|
|
311
|
-
for (const release of held) release();
|
|
312
|
-
}, [awaitTopology, rawKernel]);
|
|
313
315
|
const kernel = useMemo(() => ({
|
|
314
316
|
store: rawKernel.store,
|
|
315
|
-
dispatch: (request) => {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
return new Promise((resolve, reject) => {
|
|
319
|
-
heldRef.current.push(() => {
|
|
320
|
-
rawKernelRef.current.dispatch(stamped).then(resolve, reject);
|
|
321
|
-
});
|
|
322
|
-
});
|
|
323
|
-
}
|
|
317
|
+
dispatch: (request, hooks) => rawKernel.dispatch(request.clientId !== void 0 ? request : { ...request, clientId: getTabClientId() }, hooks),
|
|
318
|
+
dispatchMount: (seeds, hooks, base = {}) => rawKernel.dispatchMount(seeds, hooks, base.clientId !== void 0 ? base : { ...base, clientId: getTabClientId() }),
|
|
319
|
+
dispatchProgress: (request) => rawKernel.dispatchProgress(request.clientId !== void 0 ? request : { ...request, clientId: getTabClientId() })
|
|
324
320
|
}), [rawKernel]);
|
|
325
|
-
|
|
326
|
-
kernelRef.current = kernel;
|
|
327
|
-
useEffect(() => {
|
|
328
|
-
if (!effectiveTransport?.subscribe) return;
|
|
329
|
-
return effectiveTransport.subscribe((emitted) => {
|
|
330
|
-
const targets = collectListenerTargets(traitIndex, emitted.source, emitted.event, emitted.payload);
|
|
331
|
-
for (const target of targets) {
|
|
332
|
-
void kernelRef.current.dispatch({
|
|
333
|
-
event: target.triggers,
|
|
334
|
-
...target.payload !== void 0 ? { payload: target.payload } : {},
|
|
335
|
-
...target.entityId !== void 0 ? { entityId: target.entityId } : {},
|
|
336
|
-
targetTrait: target.listenerTrait
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
}, { clientId: getTabClientId() });
|
|
340
|
-
}, [effectiveTransport, traitIndex]);
|
|
341
|
-
return { kernel, store, traitIndex };
|
|
321
|
+
return { kernel, store, traitIndex, transport: effectiveTransport };
|
|
342
322
|
}
|
|
343
323
|
var log2 = createLogger("almadar:ui:circuit:bus-ingress");
|
|
344
324
|
function useBusIngress(traitBindings, traitIndex, settle, eventBus) {
|
|
@@ -363,8 +343,12 @@ function useBusIngress(traitBindings, traitIndex, settle, eventBus) {
|
|
|
363
343
|
const dispatch = (traitName, eventKey, payload, source) => {
|
|
364
344
|
if (!claim(source, traitName, eventKey)) return;
|
|
365
345
|
const tick = source?.tick;
|
|
346
|
+
const pendingKey = source?.pendingKey;
|
|
347
|
+
if (pendingKey !== void 0) beginPending(pendingKey);
|
|
366
348
|
void settle(traitName, eventKey, payload, tick).catch((err) => {
|
|
367
349
|
log2.error("dispatch:failed", { trait: traitName, event: eventKey, error: String(err) });
|
|
350
|
+
}).finally(() => {
|
|
351
|
+
if (pendingKey !== void 0) endPending(pendingKey);
|
|
368
352
|
});
|
|
369
353
|
};
|
|
370
354
|
for (const binding of traitBindings) {
|
|
@@ -514,7 +498,7 @@ function resolveLambdaBindings(body, params, item, index) {
|
|
|
514
498
|
return body;
|
|
515
499
|
}
|
|
516
500
|
var LazySlotContentRenderer = React.lazy(
|
|
517
|
-
() => import('./UISlotRenderer-
|
|
501
|
+
() => import('./UISlotRenderer-JT34I3O7.js').then((m) => ({ default: m.SlotContentRenderer }))
|
|
518
502
|
);
|
|
519
503
|
function deferLambdaEntityExprs(value) {
|
|
520
504
|
if (typeof value === "string") {
|
|
@@ -638,12 +622,15 @@ function useSlotFlush(uiSlots, embeddedTraits) {
|
|
|
638
622
|
uiSlotsRef.current = uiSlots;
|
|
639
623
|
const embeddedTraitsRef = useRef(embeddedTraits);
|
|
640
624
|
embeddedTraitsRef.current = embeddedTraits;
|
|
625
|
+
const writtenRef = useRef(/* @__PURE__ */ new Map());
|
|
626
|
+
const keyOf = (slot, trait) => `${slot}\0${trait}`;
|
|
641
627
|
const flushSlot = useCallback((traitName, slot, patterns, source) => {
|
|
642
628
|
const slots = uiSlotsRef.current;
|
|
643
629
|
const embedded = embeddedTraitsRef.current;
|
|
644
630
|
if (patterns.length === 0) {
|
|
645
631
|
flushLog.debug("clear", { traitName, slot });
|
|
646
632
|
slots.clearBySource(slot, traitName);
|
|
633
|
+
writtenRef.current.set(keyOf(slot, traitName), { kind: "clear", slot, trait: traitName });
|
|
647
634
|
return;
|
|
648
635
|
}
|
|
649
636
|
const last = patterns[patterns.length - 1];
|
|
@@ -652,19 +639,20 @@ function useSlotFlush(uiSlots, embeddedTraits) {
|
|
|
652
639
|
const props = convertFnFormLambdasInProps(rawProps, typeof patternType === "string" ? patternType : void 0);
|
|
653
640
|
const isEmbedded = (embedded?.has(traitName) ?? false) && !isNotificationSlot(slot);
|
|
654
641
|
if (isEmbedded) {
|
|
655
|
-
|
|
642
|
+
const content = {
|
|
656
643
|
pattern: patternType,
|
|
657
644
|
props,
|
|
658
645
|
slot,
|
|
659
646
|
priority: 0,
|
|
660
|
-
animation: "fade",
|
|
661
647
|
transitionEvent: source?.event,
|
|
662
648
|
fromState: source?.state,
|
|
663
649
|
entity: source?.entity
|
|
664
|
-
}
|
|
650
|
+
};
|
|
651
|
+
slots.updateTraitContent(traitName, content);
|
|
652
|
+
writtenRef.current.set(keyOf(slot, traitName), { kind: "trait", trait: traitName, content });
|
|
665
653
|
return;
|
|
666
654
|
}
|
|
667
|
-
|
|
655
|
+
const config = {
|
|
668
656
|
target: slot,
|
|
669
657
|
pattern: patternType,
|
|
670
658
|
props,
|
|
@@ -672,7 +660,9 @@ function useSlotFlush(uiSlots, embeddedTraits) {
|
|
|
672
660
|
transitionEvent: source?.event,
|
|
673
661
|
fromState: source?.state,
|
|
674
662
|
entity: source?.entity
|
|
675
|
-
}
|
|
663
|
+
};
|
|
664
|
+
slots.render(config);
|
|
665
|
+
writtenRef.current.set(keyOf(slot, traitName), { kind: "render", config });
|
|
676
666
|
}, []);
|
|
677
667
|
const applyClientEffects = useCallback((clientEffects, clientEffectsByTrait, onNavigate, onNavigateBack, activeTraits) => {
|
|
678
668
|
const slots = uiSlotsRef.current;
|
|
@@ -687,13 +677,18 @@ function useSlotFlush(uiSlots, embeddedTraits) {
|
|
|
687
677
|
const { bareTraitRef, patternType, props: unwrapped } = unwrapPattern(pattern);
|
|
688
678
|
const isEmbedded = (embedded?.has(sourceTrait) ?? false) && !isNotificationSlot(slot);
|
|
689
679
|
const propsValue = bareTraitRef !== void 0 ? bareTraitRef : { ...unwrapped ?? {}, ...rawProps };
|
|
690
|
-
const props = convertFnFormLambdasInProps(propsValue);
|
|
680
|
+
const props = convertFnFormLambdasInProps(propsValue, typeof patternType === "string" ? patternType : void 0);
|
|
691
681
|
if (pattern === null) {
|
|
692
682
|
slots.clearBySource(slot, sourceTrait);
|
|
683
|
+
writtenRef.current.set(keyOf(slot, sourceTrait), { kind: "clear", slot, trait: sourceTrait });
|
|
693
684
|
} else if (isEmbedded) {
|
|
694
|
-
|
|
685
|
+
const content = { pattern: patternType, props, slot, priority: 0, transitionEvent: event, fromState };
|
|
686
|
+
slots.updateTraitContent(sourceTrait, content);
|
|
687
|
+
writtenRef.current.set(keyOf(slot, sourceTrait), { kind: "trait", trait: sourceTrait, content });
|
|
695
688
|
} else {
|
|
696
|
-
|
|
689
|
+
const config = { target: slot, pattern: patternType, props, sourceTrait, transitionEvent: event, fromState };
|
|
690
|
+
slots.render(config);
|
|
691
|
+
writtenRef.current.set(keyOf(slot, sourceTrait), { kind: "render", config });
|
|
697
692
|
}
|
|
698
693
|
} else if (kind === "navigate") {
|
|
699
694
|
const [, route, params, options] = effect;
|
|
@@ -703,7 +698,26 @@ function useSlotFlush(uiSlots, embeddedTraits) {
|
|
|
703
698
|
}
|
|
704
699
|
}
|
|
705
700
|
}, []);
|
|
706
|
-
|
|
701
|
+
const checkpoint = useCallback(() => new Map(writtenRef.current), []);
|
|
702
|
+
const rollback = useCallback((cp) => {
|
|
703
|
+
const slots = uiSlotsRef.current;
|
|
704
|
+
for (const [key, now] of writtenRef.current) {
|
|
705
|
+
const then = cp.get(key);
|
|
706
|
+
if (then === now) continue;
|
|
707
|
+
if (then === void 0 || then.kind === "clear") {
|
|
708
|
+
if (now.kind === "render") slots.clearBySource(now.config.target, now.config.sourceTrait ?? "kernel");
|
|
709
|
+
else if (now.kind === "trait") {
|
|
710
|
+
flushLog.warn("rollback:embedded-frame-kept", { trait: now.trait });
|
|
711
|
+
}
|
|
712
|
+
} else if (then.kind === "render") {
|
|
713
|
+
slots.render(then.config);
|
|
714
|
+
} else {
|
|
715
|
+
slots.updateTraitContent(then.trait, then.content);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
writtenRef.current = new Map(cp);
|
|
719
|
+
}, []);
|
|
720
|
+
return useMemo(() => ({ flushSlot, applyClientEffects, checkpoint, rollback }), [flushSlot, applyClientEffects, checkpoint, rollback]);
|
|
707
721
|
}
|
|
708
722
|
var log3 = createLogger("almadar:ui:circuit:effect-runner");
|
|
709
723
|
async function runCircuitEffects(params) {
|
|
@@ -1096,6 +1110,25 @@ function sameFields(a, b) {
|
|
|
1096
1110
|
}
|
|
1097
1111
|
return true;
|
|
1098
1112
|
}
|
|
1113
|
+
function useAwaitingSkeletonSource(store, traitIndex, embeddedTraits) {
|
|
1114
|
+
return useMemo(() => {
|
|
1115
|
+
const activeRenders = () => {
|
|
1116
|
+
const renders = [];
|
|
1117
|
+
for (const awaiting of store.awaiting.list()) {
|
|
1118
|
+
const transitions = traitIndex.byName.get(awaiting.trait)?.irTrait.stateMachine?.transitions ?? [];
|
|
1119
|
+
const taken = transitions.find((t) => t.event === awaiting.event && t.from === awaiting.from);
|
|
1120
|
+
if (taken?.awaitRender) renders.push(...taken.awaitRender);
|
|
1121
|
+
}
|
|
1122
|
+
return renders;
|
|
1123
|
+
};
|
|
1124
|
+
return {
|
|
1125
|
+
forSlot: (slot) => activeRenders().find((r) => r.slot === slot && !(embeddedTraits?.has(r.trait) ?? false))?.skeleton,
|
|
1126
|
+
forTrait: (traitName) => activeRenders().find((r) => r.trait === traitName)?.skeleton,
|
|
1127
|
+
subscribe: (callback) => store.awaiting.subscribeAll(callback),
|
|
1128
|
+
getVersion: () => store.awaiting.getVersion()
|
|
1129
|
+
};
|
|
1130
|
+
}, [store, traitIndex, embeddedTraits]);
|
|
1131
|
+
}
|
|
1099
1132
|
|
|
1100
1133
|
// hooks/useTraitStateMachine.ts
|
|
1101
1134
|
var stateLog = createLogger("almadar:ui:state-transitions");
|
|
@@ -1114,7 +1147,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
1114
1147
|
const { user: contextViewer } = useUser();
|
|
1115
1148
|
const userContext = options.user ?? contextViewer ?? void 0;
|
|
1116
1149
|
const observer = useMemo(() => createCircuitVerificationObserver(), []);
|
|
1117
|
-
const { kernel, store, traitIndex } = useCircuitKernel(traitBindings, {
|
|
1150
|
+
const { kernel, store, traitIndex, transport } = useCircuitKernel(traitBindings, {
|
|
1118
1151
|
orbitals: options.orbitals,
|
|
1119
1152
|
...options.traitConfigsByName !== void 0 ? { traitConfigsByName: options.traitConfigsByName } : {},
|
|
1120
1153
|
...options.transport !== void 0 ? { transport: options.transport } : {},
|
|
@@ -1144,6 +1177,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
1144
1177
|
...userContext !== void 0 ? { user: userContext } : {}
|
|
1145
1178
|
});
|
|
1146
1179
|
const entityBindingSource = useEntityBindingSource(store, traitIndex);
|
|
1180
|
+
const awaitingSkeletonSource = useAwaitingSkeletonSource(store, traitIndex, options.embeddedTraits);
|
|
1147
1181
|
const activeTraitNamesRef = useRef(/* @__PURE__ */ new Set());
|
|
1148
1182
|
useEffect(() => {
|
|
1149
1183
|
activeTraitNamesRef.current = new Set(traitIndex.byName.keys());
|
|
@@ -1191,11 +1225,41 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
1191
1225
|
for (const unreg of snapshotUnregs) unreg();
|
|
1192
1226
|
};
|
|
1193
1227
|
}, [traitBindings, store, traitIndex]);
|
|
1228
|
+
const afterSettle = useCallback(async (traitName, eventKey, payload, transitioned, repaints, composedBefore) => {
|
|
1229
|
+
if (transitioned) {
|
|
1230
|
+
const entityByTrait = {};
|
|
1231
|
+
for (const [name, entry] of traitIndex.byName) {
|
|
1232
|
+
const row = store.frames.get(entry.frameKey);
|
|
1233
|
+
if (row !== void 0) entityByTrait[name] = row;
|
|
1234
|
+
}
|
|
1235
|
+
const repainted = new Set(repaints.map((e) => e.traitName));
|
|
1236
|
+
const serverComposed = new Set([...store.callsitePayloads].filter(([child, composed]) => composedBefore.get(child) !== composed).map(([child]) => child));
|
|
1237
|
+
await reRenderCallsiteCaptureChildren(traitName, payload ?? {}, entityByTrait, repainted, serverComposed);
|
|
1238
|
+
}
|
|
1239
|
+
options.onEventProcessed?.(eventKey, payload);
|
|
1240
|
+
}, [traitIndex, store, reRenderCallsiteCaptureChildren, options.onEventProcessed]);
|
|
1241
|
+
const settleOutcome = useCallback(async (traitName, eventKey, payload, outcome, composedBefore) => {
|
|
1242
|
+
recordDispatchVerdict(traitIndex.byName.get(traitName)?.orbitalName ?? traitName, eventKey, { response: outcome.response });
|
|
1243
|
+
const settledEffects = outcome.localPainted && outcome.serverEffects !== void 0 ? outcome.serverEffects : outcome.response;
|
|
1244
|
+
slotFlush.applyClientEffects(
|
|
1245
|
+
settledEffects.clientEffects ?? [],
|
|
1246
|
+
settledEffects.clientEffectsByTrait,
|
|
1247
|
+
options.navigate,
|
|
1248
|
+
options.navigateBack,
|
|
1249
|
+
activeTraitNamesRef.current
|
|
1250
|
+
);
|
|
1251
|
+
for (const emitted of outcome.response.emittedEvents) {
|
|
1252
|
+
eventBus.emit(`UI:${emitted.event}`, emitted.payload, { ...emitted.source ?? {}, dispatched: true });
|
|
1253
|
+
}
|
|
1254
|
+
stateLog.debug("dispatch:settled", { traitName, eventKey, mode: outcome.mode, transitioned: outcome.response.transitioned });
|
|
1255
|
+
await afterSettle(traitName, eventKey, payload, outcome.response.transitioned, outcome.response.clientEffectsByTrait ?? [], composedBefore);
|
|
1256
|
+
}, [slotFlush, traitIndex, eventBus, options.navigate, options.navigateBack, afterSettle]);
|
|
1194
1257
|
const dispatchAndSettle = useCallback(async (traitName, eventKey, payload, tick) => {
|
|
1195
1258
|
const entityId = typeof payload?.entityId === "string" ? payload.entityId : void 0;
|
|
1196
1259
|
const orbitalName = traitIndex.byName.get(traitName)?.orbitalName ?? traitName;
|
|
1197
1260
|
let outcome;
|
|
1198
1261
|
const composedBefore = new Map(store.callsitePayloads);
|
|
1262
|
+
let beforeLocalPaint;
|
|
1199
1263
|
try {
|
|
1200
1264
|
outcome = await kernel.dispatch({
|
|
1201
1265
|
event: eventKey,
|
|
@@ -1203,35 +1267,80 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
1203
1267
|
...entityId !== void 0 ? { entityId } : {},
|
|
1204
1268
|
...tick !== void 0 ? { tick } : {},
|
|
1205
1269
|
targetTrait: traitName
|
|
1270
|
+
}, {
|
|
1271
|
+
onLocal: (local) => {
|
|
1272
|
+
beforeLocalPaint = slotFlush.checkpoint();
|
|
1273
|
+
slotFlush.applyClientEffects(
|
|
1274
|
+
local.clientEffects ?? [],
|
|
1275
|
+
local.clientEffectsByTrait,
|
|
1276
|
+
options.navigate,
|
|
1277
|
+
options.navigateBack,
|
|
1278
|
+
activeTraitNamesRef.current
|
|
1279
|
+
);
|
|
1280
|
+
}
|
|
1206
1281
|
});
|
|
1207
1282
|
} catch (err) {
|
|
1283
|
+
if (beforeLocalPaint !== void 0) slotFlush.rollback(beforeLocalPaint);
|
|
1208
1284
|
recordDispatchVerdict(orbitalName, eventKey, { error: err instanceof Error ? err : String(err) });
|
|
1209
1285
|
throw err;
|
|
1210
1286
|
}
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
outcome.response.clientEffects ?? [],
|
|
1214
|
-
outcome.response.clientEffectsByTrait,
|
|
1215
|
-
options.navigate,
|
|
1216
|
-
options.navigateBack,
|
|
1217
|
-
activeTraitNamesRef.current
|
|
1218
|
-
);
|
|
1219
|
-
for (const emitted of outcome.response.emittedEvents) {
|
|
1220
|
-
eventBus.emit(`UI:${emitted.event}`, emitted.payload, { ...emitted.source ?? {}, dispatched: true });
|
|
1287
|
+
if (outcome.localPainted && !outcome.response.success && beforeLocalPaint !== void 0) {
|
|
1288
|
+
slotFlush.rollback(beforeLocalPaint);
|
|
1221
1289
|
}
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1290
|
+
await settleOutcome(traitName, eventKey, payload, outcome, composedBefore);
|
|
1291
|
+
}, [kernel, slotFlush, traitIndex, store, options.navigate, options.navigateBack, settleOutcome]);
|
|
1292
|
+
const progressAndSettle = useCallback(async (traitName, eventKey, payload) => {
|
|
1293
|
+
const entityId = typeof payload?.entityId === "string" ? payload.entityId : void 0;
|
|
1294
|
+
const composedBefore = new Map(store.callsitePayloads);
|
|
1295
|
+
const outcome = await kernel.dispatchProgress({
|
|
1296
|
+
event: eventKey,
|
|
1297
|
+
...payload !== void 0 ? { payload } : {},
|
|
1298
|
+
...entityId !== void 0 ? { entityId } : {},
|
|
1299
|
+
targetTrait: traitName
|
|
1300
|
+
});
|
|
1301
|
+
await settleOutcome(traitName, eventKey, payload, outcome, composedBefore);
|
|
1302
|
+
}, [kernel, store, settleOutcome]);
|
|
1303
|
+
useEffect(() => {
|
|
1304
|
+
if (!transport?.subscribe) return;
|
|
1305
|
+
return transport.subscribe((emitted, target) => {
|
|
1306
|
+
for (const t of collectListenerTargets(traitIndex, emitted.source, emitted.event, emitted.payload)) {
|
|
1307
|
+
void (target === "origin" ? progressAndSettle(t.listenerTrait, t.triggers, t.payload) : dispatchAndSettle(t.listenerTrait, t.triggers, t.payload));
|
|
1228
1308
|
}
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1309
|
+
}, { clientId: getTabClientId() });
|
|
1310
|
+
}, [transport, traitIndex, progressAndSettle, dispatchAndSettle]);
|
|
1311
|
+
const mountAndSettle = useCallback(async (seeds, payload) => {
|
|
1312
|
+
const composedBefore = new Map(store.callsitePayloads);
|
|
1313
|
+
let beforeLocalPaint;
|
|
1314
|
+
let outcome;
|
|
1315
|
+
try {
|
|
1316
|
+
outcome = await kernel.dispatchMount(seeds, {
|
|
1317
|
+
onLocal: (_trait, local) => {
|
|
1318
|
+
if (beforeLocalPaint === void 0) beforeLocalPaint = slotFlush.checkpoint();
|
|
1319
|
+
slotFlush.applyClientEffects(local.clientEffects ?? [], local.clientEffectsByTrait, options.navigate, options.navigateBack, activeTraitNamesRef.current);
|
|
1320
|
+
}
|
|
1321
|
+
}, { payload });
|
|
1322
|
+
} catch (err) {
|
|
1323
|
+
if (beforeLocalPaint !== void 0) slotFlush.rollback(beforeLocalPaint);
|
|
1324
|
+
for (const seed of seeds) {
|
|
1325
|
+
recordDispatchVerdict(traitIndex.byName.get(seed.trait)?.orbitalName ?? seed.trait, seed.event, { error: err instanceof Error ? err : String(err) });
|
|
1326
|
+
}
|
|
1327
|
+
throw err;
|
|
1232
1328
|
}
|
|
1233
|
-
|
|
1234
|
-
|
|
1329
|
+
if (!outcome.success && beforeLocalPaint !== void 0) slotFlush.rollback(beforeLocalPaint);
|
|
1330
|
+
slotFlush.applyClientEffects(outcome.serverEffects.clientEffects ?? [], outcome.serverEffects.clientEffectsByTrait, options.navigate, options.navigateBack, activeTraitNamesRef.current);
|
|
1331
|
+
const emitted = [...outcome.seeds.flatMap((seed) => seed.local.emittedEvents), ...outcome.emittedEvents];
|
|
1332
|
+
for (const e of emitted) {
|
|
1333
|
+
eventBus.emit(`UI:${e.event}`, e.payload, { ...e.source ?? {}, dispatched: true });
|
|
1334
|
+
}
|
|
1335
|
+
const serverRepaints = outcome.serverEffects.clientEffectsByTrait ?? [];
|
|
1336
|
+
for (const seed of outcome.seeds) {
|
|
1337
|
+
recordDispatchVerdict(traitIndex.byName.get(seed.trait)?.orbitalName ?? seed.trait, seed.event, {
|
|
1338
|
+
response: { ...seed.local, success: outcome.success, ...outcome.error !== void 0 ? { error: outcome.error } : {} }
|
|
1339
|
+
});
|
|
1340
|
+
stateLog.debug("mount:settled", { traitName: seed.trait, eventKey: seed.event, mode: seed.mode, transitioned: seed.local.transitioned });
|
|
1341
|
+
await afterSettle(seed.trait, seed.event, payload, seed.local.transitioned, [...seed.local.clientEffectsByTrait ?? [], ...serverRepaints], composedBefore);
|
|
1342
|
+
}
|
|
1343
|
+
}, [kernel, slotFlush, traitIndex, store, eventBus, options.navigate, options.navigateBack, afterSettle]);
|
|
1235
1344
|
useBusIngress(traitBindings, traitIndex, dispatchAndSettle, eventBus);
|
|
1236
1345
|
const sendEvent = useCallback((eventKey, payload) => {
|
|
1237
1346
|
const normalized = normalizeEventKey(eventKey);
|
|
@@ -1272,17 +1381,19 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
1272
1381
|
if (mount.initialized.has(traitName)) continue;
|
|
1273
1382
|
mount.initialized.add(traitName);
|
|
1274
1383
|
const lifecycleEvent = LIFECYCLE_EVENTS.find((evt) => store.manager.canHandleEvent(traitName, evt));
|
|
1275
|
-
if (lifecycleEvent !== void 0) entering.push({ traitName, lifecycleEvent });
|
|
1384
|
+
if (lifecycleEvent !== void 0) entering.push({ trait: traitName, event: lifecycleEvent });
|
|
1276
1385
|
}
|
|
1277
|
-
store.mount.mounting(entering.map((e) => e.
|
|
1278
|
-
|
|
1279
|
-
void
|
|
1386
|
+
store.mount.mounting(entering.map((e) => e.trait));
|
|
1387
|
+
if (entering.length > 0) {
|
|
1388
|
+
void mountAndSettle(entering, { ...options.initPayload ?? {} }).catch((err) => {
|
|
1389
|
+
stateLog.warn("mount:failed", { traits: entering.map((e) => e.trait), error: String(err) });
|
|
1390
|
+
});
|
|
1280
1391
|
}
|
|
1281
1392
|
mountedRef.current = mount;
|
|
1282
|
-
}, [traitBindings, store,
|
|
1393
|
+
}, [traitBindings, store, mountAndSettle, mountKey]);
|
|
1283
1394
|
useSyncExternalStore(store.subscribe, store.getVersion, store.getVersion);
|
|
1284
1395
|
const traitStates = useMemo(() => store.manager.getAllStates(), [store, store.getVersion()]);
|
|
1285
|
-
return { traitStates, sendEvent, getTraitState, canHandleEvent, entityBindingSource };
|
|
1396
|
+
return { traitStates, sendEvent, getTraitState, canHandleEvent, entityBindingSource, awaitingSkeletonSource };
|
|
1286
1397
|
}
|
|
1287
1398
|
|
|
1288
1399
|
// runtime/fitContent.ts
|
|
@@ -1353,7 +1464,7 @@ function TraitInitializer({ traits, routeParams, mountKey, orbitals, onNavigate,
|
|
|
1353
1464
|
}, localFallbackTimeoutMs ?? 5e3);
|
|
1354
1465
|
return () => clearTimeout(timer);
|
|
1355
1466
|
}, [hasBridge, bridge.connected, onLocalFallback, localFallbackTimeoutMs]);
|
|
1356
|
-
const { entityBindingSource } = useTraitStateMachine(traits, uiSlots, {
|
|
1467
|
+
const { entityBindingSource, awaitingSkeletonSource } = useTraitStateMachine(traits, uiSlots, {
|
|
1357
1468
|
orbitals,
|
|
1358
1469
|
...onNavigate !== void 0 ? { navigate: onNavigate } : {},
|
|
1359
1470
|
...onNavigateBack !== void 0 ? { navigateBack: onNavigateBack } : {},
|
|
@@ -1364,7 +1475,7 @@ function TraitInitializer({ traits, routeParams, mountKey, orbitals, onNavigate,
|
|
|
1364
1475
|
...mountKey !== void 0 ? { mountKey } : {},
|
|
1365
1476
|
...hasBridge ? { transport: bridge.transport, carriesCircuitState: bridge.carriesCircuitState, awaitTopology: !bridge.topologyKnown } : { persistence }
|
|
1366
1477
|
});
|
|
1367
|
-
return /* @__PURE__ */ jsx(EntityBindingContext.Provider, { value: entityBindingSource, children });
|
|
1478
|
+
return /* @__PURE__ */ jsx(EntityBindingContext.Provider, { value: entityBindingSource, children: /* @__PURE__ */ jsx(AwaitingSkeletonContext.Provider, { value: awaitingSkeletonSource, children }) });
|
|
1368
1479
|
}
|
|
1369
1480
|
var CONTENT_STAGE_WIDTH = 480;
|
|
1370
1481
|
function FitToBox({ children, mode = "box" }) {
|