@almadar/ui 6.53.1 → 6.54.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.
Files changed (49) hide show
  1. package/dist/Typography-CFI7JUVE.js +5 -0
  2. package/dist/{UISlotRenderer-P7A4SZSK.js → UISlotRenderer-QUEG6WFM.js} +7 -7
  3. package/dist/avl/index.cjs +709 -970
  4. package/dist/avl/index.js +24 -20
  5. package/dist/{avl-3d-context-MAt_NuU9.d.ts → avl-3d-context-BpBKZIbc.d.ts} +1 -0
  6. package/dist/{chunk-DQTV6QVS.js → chunk-4HC5HRHB.js} +53 -2
  7. package/dist/{chunk-HB4C27KU.js → chunk-4UP6BZ4R.js} +1 -1
  8. package/dist/{chunk-UOTYAPV5.js → chunk-FJDS4SVD.js} +3 -3
  9. package/dist/{chunk-QVXLKFUQ.js → chunk-MCKFWPT2.js} +1 -1
  10. package/dist/{chunk-7KSLPY56.js → chunk-N2V4LHFQ.js} +1 -0
  11. package/dist/{chunk-HUG25TT3.js → chunk-U2FGMHQP.js} +448 -885
  12. package/dist/{chunk-53VTY5CC.js → chunk-U3CGKPOK.js} +253 -92
  13. package/dist/{chunk-7LM6I3NA.js → chunk-Z5IYJU44.js} +1 -0
  14. package/dist/{chunk-FUQASYEW.js → chunk-Z7JWXIRE.js} +2 -2
  15. package/dist/components/index.cjs +449 -879
  16. package/dist/components/index.d.ts +5 -1
  17. package/dist/components/index.js +15 -16
  18. package/dist/context/index.cjs +2 -0
  19. package/dist/context/index.js +3 -1
  20. package/dist/hooks/index.cjs +6 -0
  21. package/dist/hooks/index.d.ts +10 -1
  22. package/dist/hooks/index.js +3 -4
  23. package/dist/lib/drawable/three/index.cjs +2 -0
  24. package/dist/lib/drawable/three/index.d.ts +2 -2
  25. package/dist/lib/drawable/three/index.js +6 -6
  26. package/dist/lib/index.cjs +1 -0
  27. package/dist/lib/index.js +3 -3
  28. package/dist/locales/index.cjs +3 -0
  29. package/dist/locales/index.js +3 -1
  30. package/dist/providers/index.cjs +444 -879
  31. package/dist/providers/index.d.ts +1 -1
  32. package/dist/providers/index.js +8 -8
  33. package/dist/runtime/index.cjs +3992 -4237
  34. package/dist/runtime/index.d.ts +22 -4
  35. package/dist/runtime/index.js +15 -12
  36. package/dist/ssr/index.cjs +2 -1
  37. package/dist/ssr/index.js +2 -1
  38. package/locales/ar.json +1 -0
  39. package/locales/en.json +1 -0
  40. package/locales/sl.json +1 -0
  41. package/package.json +7 -6
  42. package/scripts/audit-tailwind-safelist.ts +21 -1
  43. package/tailwind-preset.cjs +5 -6
  44. package/themes/_fonts.css +6 -4
  45. package/themes/_presets.css +2 -0
  46. package/themes/almadar-heritage.css +373 -0
  47. package/themes/orb.css +373 -0
  48. package/dist/Typography-7QEWUTW3.js +0 -5
  49. package/dist/chunk-E37BYSXY.js +0 -51
@@ -1,17 +1,17 @@
1
- import { runTickFrame } from './chunk-DQTV6QVS.js';
1
+ import { useTranslate, useRenderI18n, runTickFrame } from './chunk-4HC5HRHB.js';
2
2
  import { ALL_SLOTS } from './chunk-VHTJRS2N.js';
3
- import { UISlotRenderer } from './chunk-HUG25TT3.js';
4
- import { Box } from './chunk-7LM6I3NA.js';
5
- import { Typography } from './chunk-HB4C27KU.js';
3
+ import { LoadingState, ErrorState, UISlotRenderer } from './chunk-U2FGMHQP.js';
4
+ import { Box } from './chunk-Z5IYJU44.js';
5
+ import { Typography } from './chunk-4UP6BZ4R.js';
6
6
  import { beginPending, endPending } from './chunk-JRW33U35.js';
7
7
  import { useEventBus } from './chunk-6EV3OEBQ.js';
8
- import { isNotificationSlot } from './chunk-PEST66PN.js';
9
8
  import { registerTrait, unregisterTrait, perfTimeAsync } from './chunk-KQXXO42S.js';
10
9
  import { bindTraitStateGetter, registerTraitSnapshot, recordTransition, recordingTransport, recordServerResponse } from './chunk-O7OLVVBR.js';
10
+ import { isNotificationSlot } from './chunk-PEST66PN.js';
11
11
  import React, { useState, useMemo, useEffect, useRef, useCallback, useSyncExternalStore } from 'react';
12
- import { schemaToIR, getPage, clearSchemaCache as clearSchemaCache$1, applyListenPayloadMapping, buildResolvedTraitConfigs, collectCallsiteCaptureChildren, walkSExpr, isRenderBindingMarker, containsEntityBinding, isSExpr, isEventPayloadValue, RENDER_BINDING_MARKER } from '@almadar/core';
12
+ import { schemaToIR, getPage, clearSchemaCache as clearSchemaCache$1, traitsEmbeddedByEvent, traitReferencesCallsitePayload, configReferencesCallsitePayload, TRAIT_MOUNT_ERROR_TESTID, traitsEmbeddedByEffects, applyListenPayloadMapping, buildResolvedTraitConfigs, collectCallsiteCaptureChildren, orbitalInlineEntities, storesRowsInBrowser, walkSExpr, isRenderBindingMarker, containsEntityBinding, isSExpr, isEventPayloadValue, RENDER_BINDING_MARKER } from '@almadar/core';
13
13
  import { createLogger } from '@almadar/logger';
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';
14
+ import { collectListenerTargets, LIFECYCLE_EVENTS, TraitMountError, InMemoryPersistence, loadLazyPage, createInProcessTransport, buildTraitIndex, createMemoryCircuitStore, createLocalStoreTransport, createResidenceTransport, createClientKernel, createTickScheduler, isValidCronExpression, parseDurationString, UNMOUNT_EVENT, createClientEffectHandlers, EffectExecutor, isSExpression, collectDeclaredConfigDefaults, createContextFromBindings, openBrowserStore, browserStoreName, normalizeCallSiteConfigToValues } from '@almadar/runtime';
15
15
  import { useUser, useArbitraryClassStyles, getAllPages, matchPathAmong, CurrentPagePathProvider, NavStackProvider, OrbitalProvider, useNavStack, VerificationProvider, EntitySchemaProvider, OrbitalThemeProvider, ServerBridgeProvider, useServerBridge, EntityBindingContext, AwaitingSkeletonContext } from '@almadar/ui/providers';
16
16
  import { evaluateListenPayloadExpr, evaluate, createMinimalContext, evaluateGuard, executeEffects } from '@almadar/evaluator';
17
17
  import { getPatternDefinition } from '@almadar/core/patterns';
@@ -20,9 +20,10 @@ import { prepareSchemaForPreview, collectTraitRefsFromResolvedTrait, buildOrbita
20
20
  export { adjustSchemaForMockData, buildMockData, collectEmbeddedTraits, prepareSchemaForPreview } from '@almadar/runtime/ui';
21
21
  import { useInRouterContext, useHref } from 'react-router-dom';
22
22
  import { UISlotProvider, useUISlots } from '@almadar/ui/context';
23
- import { useTranslate } from '@almadar/ui/hooks';
23
+ import { useTranslate as useTranslate$1, createTranslate, I18nProvider } from '@almadar/ui/hooks';
24
24
  import { jsx, jsxs } from 'react/jsx-runtime';
25
25
  import { OrbitalServerRuntime } from '@almadar/runtime/OrbitalServerRuntime';
26
+ import { localeDirection } from '@almadar/core/i18n';
26
27
 
27
28
  var resolvedSchemaLog = createLogger("almadar:ui:resolved-schema");
28
29
  function useResolvedSchema(schema, pageName) {
@@ -172,9 +173,9 @@ function getTabClientId() {
172
173
  return tabClientId;
173
174
  }
174
175
  var log = createLogger("almadar:ui:circuit-kernel");
175
- function postUnmounts(transport, traits) {
176
+ function postUnmounts(transport, traits, locale) {
176
177
  for (const [traitName, orbitalName] of traits) {
177
- transport.send(orbitalName, { event: UNMOUNT_EVENT, targetTrait: traitName, clientId: getTabClientId() }).catch((err) => log.warn("unmount-post-failed", { trait: traitName, orbital: orbitalName, error: String(err) }));
178
+ transport.send(orbitalName, { event: UNMOUNT_EVENT, targetTrait: traitName, clientId: getTabClientId(), locale }).catch((err) => log.warn("unmount-post-failed", { trait: traitName, orbital: orbitalName, error: String(err) }));
178
179
  }
179
180
  }
180
181
  function restrictTraitIndex(full, activeNames) {
@@ -195,6 +196,10 @@ function useCircuitKernel(traitBindings, options) {
195
196
  [activeTraitKey, fullTraitIndex]
196
197
  );
197
198
  const mountedRef = useRef(/* @__PURE__ */ new Map());
199
+ const { locale } = useTranslate();
200
+ const i18n = useRenderI18n();
201
+ const localeRef = useRef(locale);
202
+ localeRef.current = locale;
198
203
  const transport = options.transport;
199
204
  const topologyPending = options.awaitTopology === true;
200
205
  useEffect(() => {
@@ -203,12 +208,12 @@ function useCircuitKernel(traitBindings, options) {
203
208
  const dropped = [...mounted].filter(([name]) => !traitIndex.byName.has(name));
204
209
  mounted.clear();
205
210
  for (const [name, entry] of traitIndex.byName) mounted.set(name, entry.orbitalName);
206
- postUnmounts(transport, dropped);
211
+ postUnmounts(transport, dropped, localeRef.current);
207
212
  }, [traitIndex, transport, topologyPending]);
208
213
  useEffect(() => {
209
214
  if (transport === void 0) return;
210
215
  const mounted = mountedRef.current;
211
- return () => postUnmounts(transport, [...mounted]);
216
+ return () => postUnmounts(transport, [...mounted], localeRef.current);
212
217
  }, [transport]);
213
218
  const store = useMemo(() => {
214
219
  const traitDefs = Array.from(traitIndex.byName.values(), (entry) => entry.traitDef);
@@ -219,42 +224,43 @@ function useCircuitKernel(traitBindings, options) {
219
224
  };
220
225
  return createMemoryCircuitStore(traitDefs, config, options.observer);
221
226
  }, [traitIndex, options.guardMode, options.strictBindings, options.contextExtensions, options.observer]);
222
- const offlineTransport = useMemo(() => {
223
- if (options.transport !== void 0 || options.persistence === void 0) return void 0;
224
- const persistence = options.persistence;
225
- return createInProcessTransport(
226
- async (_orbitalName, request) => {
227
- const runEffects = createIndexStageRunner({
228
- traitIndex,
229
- persistence,
230
- frames: store.frames,
231
- manager: store.manager,
232
- ...options.callService !== void 0 ? { extraEffectHandlers: { callService: options.callService } } : {},
233
- ...options.debug !== void 0 ? { debug: options.debug } : {}
234
- });
235
- return evaluateOrbitalEvent(
236
- {
237
- traitIndex,
238
- manager: store.manager,
239
- persistence,
240
- frames: store.frames,
241
- runEffects,
242
- ...options.user !== void 0 ? { user: options.user } : {},
243
- ...options.guardMode !== void 0 ? { guardMode: options.guardMode } : {},
244
- ...options.strictBindings !== void 0 ? { strictBindings: options.strictBindings } : {},
245
- ...options.contextExtensions !== void 0 ? { contextExtensions: options.contextExtensions } : {},
246
- ...options.debug !== void 0 ? { debug: options.debug } : {},
247
- ...options.logContext !== void 0 ? { logContext: options.logContext } : {}
248
- },
249
- request
250
- );
251
- },
252
- { carriesCircuitState: false }
253
- );
227
+ const localTransportOptions = {
228
+ traitIndex,
229
+ store,
230
+ ...options.callService !== void 0 ? { callService: options.callService } : {},
231
+ ...options.user !== void 0 ? { user: options.user } : {},
232
+ ...options.guardMode !== void 0 ? { guardMode: options.guardMode } : {},
233
+ ...options.strictBindings !== void 0 ? { strictBindings: options.strictBindings } : {},
234
+ ...options.contextExtensions !== void 0 ? { contextExtensions: options.contextExtensions } : {},
235
+ ...options.debug !== void 0 ? { debug: options.debug } : {},
236
+ ...options.logContext !== void 0 ? { logContext: options.logContext } : {}
237
+ };
238
+ const offlineTransport = useMemo(
239
+ () => options.transport !== void 0 || options.persistence === void 0 ? void 0 : createLocalStoreTransport({ ...localTransportOptions, persistence: options.persistence }),
240
+ [
241
+ options.transport,
242
+ options.persistence,
243
+ traitIndex,
244
+ store,
245
+ options.callService,
246
+ options.user,
247
+ options.guardMode,
248
+ options.strictBindings,
249
+ options.contextExtensions,
250
+ options.debug,
251
+ options.logContext
252
+ ]
253
+ );
254
+ const routedTransport = useMemo(() => {
255
+ if (options.browserStore === void 0) return void 0;
256
+ const local = createLocalStoreTransport({ ...localTransportOptions, traitIndex: fullTraitIndex, persistence: options.browserStore, clientRelays: true });
257
+ const remote = options.transport ?? offlineTransport;
258
+ return createResidenceTransport({ local, ...remote !== void 0 ? { remote } : {}, traitIndex: fullTraitIndex });
254
259
  }, [
260
+ options.browserStore,
255
261
  options.transport,
256
- options.persistence,
257
- traitIndex,
262
+ offlineTransport,
263
+ fullTraitIndex,
258
264
  store,
259
265
  options.callService,
260
266
  options.user,
@@ -264,7 +270,7 @@ function useCircuitKernel(traitBindings, options) {
264
270
  options.debug,
265
271
  options.logContext
266
272
  ]);
267
- const baseTransport = options.transport ?? offlineTransport;
273
+ const baseTransport = routedTransport ?? options.transport ?? offlineTransport;
268
274
  const effectiveTransport = useMemo(
269
275
  () => baseTransport === void 0 ? void 0 : recordingTransport(baseTransport),
270
276
  [baseTransport]
@@ -289,6 +295,8 @@ function useCircuitKernel(traitBindings, options) {
289
295
  store,
290
296
  ...options.persistence !== void 0 ? { persistence: options.persistence } : {},
291
297
  ...options.user !== void 0 ? { user: options.user } : {},
298
+ locale,
299
+ ...i18n !== void 0 ? { messages: { [i18n.locale]: i18n.messages } } : {},
292
300
  ...options.guardMode !== void 0 ? { guardMode: options.guardMode } : {},
293
301
  ...options.strictBindings !== void 0 ? { strictBindings: options.strictBindings } : {},
294
302
  ...options.contextExtensions !== void 0 ? { contextExtensions: options.contextExtensions } : {},
@@ -304,6 +312,8 @@ function useCircuitKernel(traitBindings, options) {
304
312
  store,
305
313
  options.persistence,
306
314
  options.user,
315
+ locale,
316
+ i18n,
307
317
  options.guardMode,
308
318
  options.strictBindings,
309
319
  options.contextExtensions,
@@ -312,12 +322,19 @@ function useCircuitKernel(traitBindings, options) {
312
322
  topology,
313
323
  effectiveTransport
314
324
  ]);
315
- const kernel = useMemo(() => ({
316
- store: rawKernel.store,
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() })
320
- }), [rawKernel]);
325
+ const kernel = useMemo(() => {
326
+ const stamp = (request) => ({
327
+ ...request,
328
+ clientId: request.clientId ?? getTabClientId(),
329
+ locale: request.locale ?? locale
330
+ });
331
+ return {
332
+ store: rawKernel.store,
333
+ dispatch: (request, hooks) => rawKernel.dispatch(stamp(request), hooks),
334
+ dispatchMount: (seeds, hooks, base = {}) => rawKernel.dispatchMount(seeds, hooks, stamp(base)),
335
+ dispatchProgress: (request) => rawKernel.dispatchProgress(stamp(request))
336
+ };
337
+ }, [rawKernel, locale]);
321
338
  return { kernel, store, traitIndex, transport: effectiveTransport };
322
339
  }
323
340
  var log2 = createLogger("almadar:ui:circuit:bus-ingress");
@@ -498,7 +515,7 @@ function resolveLambdaBindings(body, params, item, index) {
498
515
  return body;
499
516
  }
500
517
  var LazySlotContentRenderer = React.lazy(
501
- () => import('./UISlotRenderer-P7A4SZSK.js').then((m) => ({ default: m.SlotContentRenderer }))
518
+ () => import('./UISlotRenderer-QUEG6WFM.js').then((m) => ({ default: m.SlotContentRenderer }))
502
519
  );
503
520
  function deferLambdaEntityExprs(value) {
504
521
  if (typeof value === "string") {
@@ -795,11 +812,12 @@ async function runCircuitEffects(params) {
795
812
  // hooks/circuit/useCallsiteCapture.ts
796
813
  var log4 = createLogger("almadar:ui:circuit:callsite-capture");
797
814
  function useCallsiteCapture(traitBindings, store, traitIndex, slotFlush, options) {
798
- return useCallback(async function reRender(traitName, callsitePayload, entityByTrait, visited = /* @__PURE__ */ new Set(), serverComposed = /* @__PURE__ */ new Set(), keepComposed = false) {
815
+ return useCallback(async function reRender(traitName, callsitePayload, entityByTrait, visited = /* @__PURE__ */ new Set(), serverComposed = /* @__PURE__ */ new Set(), keepComposed = false, composedBy) {
799
816
  const children = options.callsiteCaptureChildrenByTrait?.get(traitName);
800
817
  if (!children || children.size === 0) return;
801
818
  const bindingMap = new Map(traitBindings.map((b) => [b.trait.name, b]));
802
819
  for (const childName of children) {
820
+ if (composedBy !== void 0 && !composedBy.has(childName)) continue;
803
821
  if (visited.has(childName)) continue;
804
822
  visited.add(childName);
805
823
  const childBinding = bindingMap.get(childName);
@@ -853,7 +871,7 @@ function useCallsiteCapture(traitBindings, store, traitIndex, slotFlush, options
853
871
  { event: lifecycleEvent, state: entry.result.previousState, entity: childBinding.linkedEntity }
854
872
  );
855
873
  }
856
- await reRender(childName, composedWith, entityByTrait, visited, serverComposed, keepComposed);
874
+ await reRender(childName, composedWith, entityByTrait, visited, serverComposed, keepComposed, traitsEmbeddedByEffects(indexed.irTrait, entry.result.effects));
857
875
  }
858
876
  }, [traitBindings, store, traitIndex, slotFlush, options.callsiteCaptureChildrenByTrait, options.eventBus, options.navigate, options.navigateBack, options.user]);
859
877
  }
@@ -1131,6 +1149,7 @@ function useAwaitingSkeletonSource(store, traitIndex, embeddedTraits) {
1131
1149
  }
1132
1150
 
1133
1151
  // hooks/useTraitStateMachine.ts
1152
+ var MOUNT_ERROR_SOURCE = "$mount";
1134
1153
  var stateLog = createLogger("almadar:ui:state-transitions");
1135
1154
  function diffDroppedTraitNames(prev, next) {
1136
1155
  const dropped = [];
@@ -1145,6 +1164,7 @@ function normalizeEventKey(eventKey) {
1145
1164
  function useTraitStateMachine(traitBindings, uiSlots, options) {
1146
1165
  const eventBus = useEventBus();
1147
1166
  const { user: contextViewer } = useUser();
1167
+ const { t } = useTranslate();
1148
1168
  const userContext = options.user ?? contextViewer ?? void 0;
1149
1169
  const observer = useMemo(() => createCircuitVerificationObserver(), []);
1150
1170
  const { kernel, store, traitIndex, transport } = useCircuitKernel(traitBindings, {
@@ -1154,6 +1174,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
1154
1174
  ...options.carriesCircuitState !== void 0 ? { carriesCircuitState: options.carriesCircuitState } : {},
1155
1175
  ...options.awaitTopology !== void 0 ? { awaitTopology: options.awaitTopology } : {},
1156
1176
  ...options.persistence !== void 0 ? { persistence: options.persistence } : {},
1177
+ ...options.browserStore !== void 0 ? { browserStore: options.browserStore } : {},
1157
1178
  ...options.callService !== void 0 ? { callService: options.callService } : {},
1158
1179
  ...userContext !== void 0 ? { user: userContext } : {},
1159
1180
  ...options.debug !== void 0 ? { debug: options.debug } : {},
@@ -1192,11 +1213,11 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
1192
1213
  name: trait.name,
1193
1214
  currentState: state?.currentState ?? trait.states[0]?.name ?? "unknown",
1194
1215
  states: trait.states.map((s) => s.name),
1195
- transitions: trait.transitions.flatMap((t) => {
1196
- const froms = Array.isArray(t.from) ? t.from : [t.from];
1197
- return froms.map((f) => ({ from: f, to: t.to, event: t.event, guard: t.guard ? String(t.guard) : void 0 }));
1216
+ transitions: trait.transitions.flatMap((t2) => {
1217
+ const froms = Array.isArray(t2.from) ? t2.from : [t2.from];
1218
+ return froms.map((f) => ({ from: f, to: t2.to, event: t2.event, guard: t2.guard ? String(t2.guard) : void 0 }));
1198
1219
  }),
1199
- guards: trait.transitions.filter((t) => t.guard).map((t) => ({ name: String(t.guard) })),
1220
+ guards: trait.transitions.filter((t2) => t2.guard).map((t2) => ({ name: String(t2.guard) })),
1200
1221
  transitionCount: 0
1201
1222
  };
1202
1223
  registerTrait(info);
@@ -1234,7 +1255,9 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
1234
1255
  }
1235
1256
  const repainted = new Set(repaints.map((e) => e.traitName));
1236
1257
  const serverComposed = new Set([...store.callsitePayloads].filter(([child, composed]) => composedBefore.get(child) !== composed).map(([child]) => child));
1237
- await reRenderCallsiteCaptureChildren(traitName, payload ?? {}, entityByTrait, repainted, serverComposed);
1258
+ const irTrait = traitIndex.byName.get(traitName)?.irTrait;
1259
+ const composedBy = irTrait !== void 0 ? traitsEmbeddedByEvent(irTrait, eventKey) : void 0;
1260
+ await reRenderCallsiteCaptureChildren(traitName, payload ?? {}, entityByTrait, repainted, serverComposed, false, composedBy);
1238
1261
  }
1239
1262
  options.onEventProcessed?.(eventKey, payload);
1240
1263
  }, [traitIndex, store, reRenderCallsiteCaptureChildren, options.onEventProcessed]);
@@ -1303,8 +1326,8 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
1303
1326
  useEffect(() => {
1304
1327
  if (!transport?.subscribe) return;
1305
1328
  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));
1329
+ for (const t2 of collectListenerTargets(traitIndex, emitted.source, emitted.event, emitted.payload)) {
1330
+ void (target === "origin" ? progressAndSettle(t2.listenerTrait, t2.triggers, t2.payload) : dispatchAndSettle(t2.listenerTrait, t2.triggers, t2.payload));
1308
1331
  }
1309
1332
  }, { clientId: getTabClientId() });
1310
1333
  }, [transport, traitIndex, progressAndSettle, dispatchAndSettle]);
@@ -1376,25 +1399,70 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
1376
1399
  for (const traitName of left) mount.initialized.delete(traitName);
1377
1400
  store.mount.unmounted(left);
1378
1401
  const entering = [];
1402
+ const embeddedChildren = new Set([...options.callsiteCaptureChildrenByTrait?.values() ?? []].flatMap((c) => [...c]));
1379
1403
  for (const binding of traitBindings) {
1380
1404
  const traitName = binding.trait.name;
1381
1405
  if (mount.initialized.has(traitName)) continue;
1382
1406
  mount.initialized.add(traitName);
1407
+ const indexed = traitIndex.byName.get(traitName);
1408
+ if (embeddedChildren.has(traitName) && indexed !== void 0 && (traitReferencesCallsitePayload(indexed.irTrait) || configReferencesCallsitePayload(indexed.config)) && store.manager.repaintLifecycleEvent(traitName) !== void 0 && !store.callsitePayloads.has(traitName)) {
1409
+ continue;
1410
+ }
1383
1411
  const lifecycleEvent = LIFECYCLE_EVENTS.find((evt) => store.manager.canHandleEvent(traitName, evt));
1384
1412
  if (lifecycleEvent !== void 0) entering.push({ trait: traitName, event: lifecycleEvent });
1385
1413
  }
1386
1414
  store.mount.mounting(entering.map((e) => e.trait));
1387
1415
  if (entering.length > 0) {
1416
+ uiSlots.clearBySource("main", MOUNT_ERROR_SOURCE);
1388
1417
  void mountAndSettle(entering, { ...options.initPayload ?? {} }).catch((err) => {
1389
- stateLog.warn("mount:failed", { traits: entering.map((e) => e.trait), error: String(err) });
1418
+ const traits = entering.map((e) => e.trait);
1419
+ const message = err instanceof Error ? err.message : String(err);
1420
+ const failed = err instanceof TraitMountError ? err.trait : traits.join(", ");
1421
+ const cause = err instanceof TraitMountError ? err.original : err;
1422
+ stateLog.warn("mount:failed", { traits, failed, error: message, stack: cause instanceof Error ? cause.stack : void 0 });
1423
+ uiSlots.render({
1424
+ target: "main",
1425
+ pattern: "error-state",
1426
+ props: { title: t("error.traitMountFailed", { trait: failed }), message, "data-testid": TRAIT_MOUNT_ERROR_TESTID },
1427
+ sourceTrait: MOUNT_ERROR_SOURCE
1428
+ });
1390
1429
  });
1391
1430
  }
1392
1431
  mountedRef.current = mount;
1393
- }, [traitBindings, store, mountAndSettle, mountKey]);
1432
+ }, [traitBindings, store, mountAndSettle, mountKey, uiSlots, traitIndex, options.callsiteCaptureChildrenByTrait, t]);
1394
1433
  useSyncExternalStore(store.subscribe, store.getVersion, store.getVersion);
1395
1434
  const traitStates = useMemo(() => store.manager.getAllStates(), [store, store.getVersion()]);
1396
1435
  return { traitStates, sendEvent, getTraitState, canHandleEvent, entityBindingSource, awaitingSkeletonSource };
1397
1436
  }
1437
+ function useBrowserStore(appName, orbitals, locale) {
1438
+ const entities = useMemo(() => orbitals.flatMap(orbitalInlineEntities).filter(storesRowsInBrowser), [orbitals]);
1439
+ const [state, setState] = useState(() => entities.length === 0 ? { status: "none" } : { status: "opening" });
1440
+ useEffect(() => {
1441
+ if (entities.length === 0) {
1442
+ setState({ status: "none" });
1443
+ return;
1444
+ }
1445
+ let cancelled = false;
1446
+ let opened;
1447
+ setState({ status: "opening" });
1448
+ const open = async () => {
1449
+ try {
1450
+ const store = await openBrowserStore(browserStoreName(appName, locale), orbitals, void 0, locale);
1451
+ if (store === null) return;
1452
+ opened = store;
1453
+ if (!cancelled) setState({ status: "ready", store });
1454
+ } catch (err) {
1455
+ if (!cancelled) setState({ status: "failed", error: err instanceof Error ? err : new Error(String(err)) });
1456
+ }
1457
+ };
1458
+ void open();
1459
+ return () => {
1460
+ cancelled = true;
1461
+ opened?.close();
1462
+ };
1463
+ }, [appName, locale, entities, orbitals]);
1464
+ return state;
1465
+ }
1398
1466
 
1399
1467
  // runtime/fitContent.ts
1400
1468
  var IDENTITY = { scale: 1, x: 0, y: 0 };
@@ -1454,7 +1522,7 @@ function appPathFromHref(href, hostHrefBase) {
1454
1522
  if (!href.startsWith(`${root}/`)) return null;
1455
1523
  return href.slice(root.length);
1456
1524
  }
1457
- function TraitInitializer({ traits, routeParams, mountKey, orbitals, onNavigate, onNavigateBack, onLocalFallback, localFallbackTimeoutMs, persistence, traitConfigsByName, embeddedTraits, callsiteCaptureChildrenByTrait, hasBridge, children }) {
1525
+ function TraitInitializer({ traits, routeParams, mountKey, orbitals, onNavigate, onNavigateBack, onLocalFallback, localFallbackTimeoutMs, persistence, browserStore, traitConfigsByName, embeddedTraits, callsiteCaptureChildrenByTrait, hasBridge, children }) {
1458
1526
  const bridge = useServerBridge();
1459
1527
  const uiSlots = useUISlots();
1460
1528
  useEffect(() => {
@@ -1473,7 +1541,8 @@ function TraitInitializer({ traits, routeParams, mountKey, orbitals, onNavigate,
1473
1541
  ...callsiteCaptureChildrenByTrait !== void 0 ? { callsiteCaptureChildrenByTrait } : {},
1474
1542
  initPayload: routeParams,
1475
1543
  ...mountKey !== void 0 ? { mountKey } : {},
1476
- ...hasBridge ? { transport: bridge.transport, carriesCircuitState: bridge.carriesCircuitState, awaitTopology: !bridge.topologyKnown } : { persistence }
1544
+ ...hasBridge ? { transport: bridge.transport, carriesCircuitState: bridge.carriesCircuitState, awaitTopology: !bridge.topologyKnown } : { persistence },
1545
+ ...browserStore !== void 0 ? { browserStore } : {}
1477
1546
  });
1478
1547
  return /* @__PURE__ */ jsx(EntityBindingContext.Provider, { value: entityBindingSource, children: /* @__PURE__ */ jsx(AwaitingSkeletonContext.Provider, { value: awaitingSkeletonSource, children }) });
1479
1548
  }
@@ -1659,6 +1728,8 @@ function SchemaRunner({ schema, serverUrl, transport, getAccessToken, mockData,
1659
1728
  return set;
1660
1729
  }, [schema, pageName]);
1661
1730
  const activeOrbitalTheme = useMemo(() => resolvePreviewTheme(schema, pageName), [schema, pageName]);
1731
+ const { locale } = useTranslate$1();
1732
+ const browserStore = useBrowserStore(schema.name ?? "app", schema.orbitals, locale);
1662
1733
  const inner = /* @__PURE__ */ jsx(VerificationProvider, { enabled: true, children: /* @__PURE__ */ jsx(
1663
1734
  EntitySchemaProvider,
1664
1735
  {
@@ -1681,11 +1752,16 @@ function SchemaRunner({ schema, serverUrl, transport, getAccessToken, mockData,
1681
1752
  onLocalFallback,
1682
1753
  localFallbackTimeoutMs,
1683
1754
  persistence,
1755
+ ...browserStore.status === "ready" ? { browserStore: browserStore.store } : {},
1684
1756
  children: /* @__PURE__ */ jsx(OrbitalThemeProvider, { theme: activeOrbitalTheme, override: themeOverride, children: /* @__PURE__ */ jsx(Box, { className: "h-full min-h-full overflow-auto p-4", children: /* @__PURE__ */ jsx(UISlotRenderer, { includeHud: true, hudMode: "inline", includeFloating: true, pageKey: pageName }) }) })
1685
1757
  }
1686
1758
  )
1687
1759
  }
1688
1760
  ) });
1761
+ if (browserStore.status === "opening") return /* @__PURE__ */ jsx(LoadingState, {});
1762
+ if (browserStore.status === "failed") {
1763
+ return /* @__PURE__ */ jsx(ErrorState, { "data-testid": "browser-store-error", message: browserStore.error.message });
1764
+ }
1689
1765
  if (serverUrl || transport) {
1690
1766
  return /* @__PURE__ */ jsx(ServerBridgeProvider, { schema, serverUrl, transport, getAccessToken, children: inner });
1691
1767
  }
@@ -1718,12 +1794,15 @@ function OrbPreview({
1718
1794
  onPageChange,
1719
1795
  user = null,
1720
1796
  localFallbackTimeoutMs,
1721
- themeOverride
1797
+ themeOverride,
1798
+ lazyLoader,
1799
+ schemaPath,
1800
+ onUnmatchedNavigate
1722
1801
  }) {
1723
1802
  if (serverUrl && transport) {
1724
1803
  throw new Error("OrbPreview accepts serverUrl OR transport, not both");
1725
1804
  }
1726
- const { t } = useTranslate();
1805
+ const { t } = useTranslate$1();
1727
1806
  const [localFallback, setLocalFallback] = useState(false);
1728
1807
  const eventBus = useEventBus();
1729
1808
  const inHostRouter = useInRouterContext();
@@ -1767,12 +1846,44 @@ function OrbPreview({
1767
1846
  return [];
1768
1847
  }
1769
1848
  }, [parsedSchema]);
1849
+ const lazyPages = useMemo(() => parsedSchema?.lazyPages ?? [], [parsedSchema]);
1850
+ const matchRoute = useCallback((path) => {
1851
+ const candidates = [
1852
+ ...pages.map((entry) => ({ kind: "page", entry, path: entry.page.path })),
1853
+ ...lazyPages.map((page) => ({ kind: "lazy", page, path: page.path }))
1854
+ ];
1855
+ const hit = matchPathAmong(candidates, path, (c) => c.path);
1856
+ if (!hit) return null;
1857
+ return hit.candidate.kind === "page" ? { kind: "page", entry: hit.candidate.entry, params: hit.params } : { kind: "lazy", page: hit.candidate.page, params: hit.params };
1858
+ }, [pages, lazyPages]);
1859
+ const initialRoute = useMemo(
1860
+ () => initialPagePath ? matchRoute(initialPagePath) : null,
1861
+ [matchRoute, initialPagePath]
1862
+ );
1770
1863
  const initialPageMatch = useMemo(() => {
1771
- if (!initialPagePath) return void 0;
1772
- const hit = matchPathAmong(pages, initialPagePath, (entry) => entry.page.path);
1773
- if (!hit) return void 0;
1774
- return { name: hit.candidate.page.name, params: hit.params };
1775
- }, [pages, initialPagePath]);
1864
+ if (initialRoute?.kind !== "page" || !initialRoute.entry.page.name) return void 0;
1865
+ return { name: initialRoute.entry.page.name, params: initialRoute.params };
1866
+ }, [initialRoute]);
1867
+ const [lazyRoute, setLazyRoute] = useState(
1868
+ initialRoute?.kind === "lazy" && initialPagePath ? { page: initialRoute.page, path: initialPagePath } : null
1869
+ );
1870
+ const [lazyLoad, setLazyLoad] = useState({ status: "loading" });
1871
+ useEffect(() => {
1872
+ if (!lazyRoute) return;
1873
+ if (!lazyLoader) {
1874
+ setLazyLoad({ status: "error", error: `No loader for lazy page ${lazyRoute.page.path} (${lazyRoute.page.orbRef})` });
1875
+ return;
1876
+ }
1877
+ let cancelled = false;
1878
+ setLazyLoad({ status: "loading" });
1879
+ void loadLazyPage(lazyLoader, lazyRoute.page, schemaPath).then((result) => {
1880
+ if (cancelled) return;
1881
+ setLazyLoad(result.success ? { status: "ready", schema: result.data } : { status: "error", error: result.error });
1882
+ });
1883
+ return () => {
1884
+ cancelled = true;
1885
+ };
1886
+ }, [lazyRoute?.page, lazyLoader, schemaPath]);
1776
1887
  const initialPageName = initialPageMatch?.name;
1777
1888
  const [currentPage, setCurrentPage] = useState(initialPageName);
1778
1889
  const [routeParams, setRouteParams] = useState(initialPageMatch?.params ?? {});
@@ -1782,8 +1893,9 @@ function OrbPreview({
1782
1893
  prevInitialPagePathRef.current = initialPagePath;
1783
1894
  setCurrentPage(initialPageName);
1784
1895
  setRouteParams(initialPageMatch?.params ?? {});
1896
+ setLazyRoute(initialRoute?.kind === "lazy" && initialPagePath ? { page: initialRoute.page, path: initialPagePath } : null);
1785
1897
  }
1786
- }, [initialPagePath, initialPageName, initialPageMatch]);
1898
+ }, [initialPagePath, initialPageName, initialPageMatch, initialRoute]);
1787
1899
  const currentPagePath = useMemo(() => {
1788
1900
  const activePageName = currentPage ?? pages[0]?.page.name;
1789
1901
  const resolved = pages.find((p) => p.page.name === activePageName)?.page.path;
@@ -1798,10 +1910,30 @@ function OrbPreview({
1798
1910
  return pattern.replace(/:([A-Za-z0-9_]+)/g, (whole, key) => routeParams[key] ?? whole);
1799
1911
  }, [currentPagePath, routeParams]);
1800
1912
  const navStackRef = useRef(null);
1913
+ const announcePage = useCallback((path) => {
1914
+ if (onPageChange) {
1915
+ onPageChange(path);
1916
+ } else if (!isolated && typeof window !== "undefined") {
1917
+ const url = new URL(window.location.href);
1918
+ url.searchParams.set("page", path);
1919
+ window.history.pushState({}, "", url.toString());
1920
+ window.dispatchEvent(new PopStateEvent("popstate"));
1921
+ }
1922
+ }, [isolated, onPageChange]);
1801
1923
  const handleNavigate = useCallback((path, navState) => {
1802
- const hit = matchPathAmong(pages, path, (entry) => entry.page.path);
1803
- const match = hit?.candidate;
1804
- const params = { ...hit?.params ?? {}, ...navState ?? {} };
1924
+ const route = matchRoute(path);
1925
+ if (!route) {
1926
+ onUnmatchedNavigate?.(path);
1927
+ return;
1928
+ }
1929
+ if (route.kind === "lazy") {
1930
+ setLazyRoute({ page: route.page, path });
1931
+ announcePage(path);
1932
+ return;
1933
+ }
1934
+ setLazyRoute(null);
1935
+ const match = route.entry;
1936
+ const params = { ...route.params, ...navState ?? {} };
1805
1937
  navLog.debug("handleNavigate", () => ({
1806
1938
  path,
1807
1939
  matched: match?.page.name ?? null,
@@ -1809,19 +1941,12 @@ function OrbPreview({
1809
1941
  navState: navState ? JSON.stringify(navState) : void 0,
1810
1942
  availablePaths: pages.map((p) => p.page.path)
1811
1943
  }));
1812
- if (match?.page.name) {
1944
+ if (match.page.name) {
1813
1945
  setRouteParams(params);
1814
1946
  setCurrentPage(match.page.name);
1815
- if (onPageChange) {
1816
- onPageChange(path);
1817
- } else if (!isolated && typeof window !== "undefined") {
1818
- const url = new URL(window.location.href);
1819
- url.searchParams.set("page", path);
1820
- window.history.pushState({}, "", url.toString());
1821
- window.dispatchEvent(new PopStateEvent("popstate"));
1822
- }
1947
+ announcePage(path);
1823
1948
  }
1824
- }, [pages, isolated, onPageChange]);
1949
+ }, [pages, matchRoute, announcePage, onUnmatchedNavigate]);
1825
1950
  const handleNavigateEffect = useCallback(
1826
1951
  (path, params, crumb) => {
1827
1952
  navStackRef.current?.beginNavigate(path, crumb);
@@ -1886,6 +2011,33 @@ function OrbPreview({
1886
2011
  navLog.info("interceptor:installed", { pageCount: pages.length, paths: pages.map((p) => p.page.path) });
1887
2012
  return () => el.removeEventListener("click", handler, true);
1888
2013
  }, [pages, handleNavigate, isolated, hostHrefBase]);
2014
+ if (lazyRoute) {
2015
+ return /* @__PURE__ */ jsxs(Box, { ref: containerRef, className: `overflow-auto ${className ?? ""}`, style: { height }, children: [
2016
+ lazyLoad.status === "loading" && /* @__PURE__ */ jsx(LoadingState, {}),
2017
+ lazyLoad.status === "error" && /* @__PURE__ */ jsx(ErrorState, { "data-testid": "lazy-page-error", message: lazyLoad.error }),
2018
+ lazyLoad.status === "ready" && /* @__PURE__ */ jsx(
2019
+ OrbPreview,
2020
+ {
2021
+ schema: lazyLoad.schema,
2022
+ autoMock,
2023
+ height: "100%",
2024
+ className: "border-0",
2025
+ serverUrl,
2026
+ transport,
2027
+ getAccessToken,
2028
+ initialPagePath: lazyRoute.path,
2029
+ user,
2030
+ isolated,
2031
+ fit,
2032
+ onPageChange: announcePage,
2033
+ themeOverride,
2034
+ lazyLoader,
2035
+ onUnmatchedNavigate: handleNavigate
2036
+ },
2037
+ lazyRoute.page.orbRef
2038
+ )
2039
+ ] });
2040
+ }
1889
2041
  return /* @__PURE__ */ jsxs(
1890
2042
  Box,
1891
2043
  {
@@ -1957,7 +2109,9 @@ function BrowserPlayground({
1957
2109
  paused,
1958
2110
  fit,
1959
2111
  onPageChange,
1960
- viewer
2112
+ viewer,
2113
+ messages,
2114
+ locale
1961
2115
  }) {
1962
2116
  const [runtime] = useState(
1963
2117
  () => new OrbitalServerRuntime({ mode, debug: false, ...viewer !== void 0 ? { defaultUser: viewer } : {} })
@@ -1973,10 +2127,10 @@ function BrowserPlayground({
1973
2127
  const registrationReady = useMemo(() => {
1974
2128
  const orbitalNames = schema.orbitals.map((o) => o.name);
1975
2129
  playgroundLog.debug("register:start", { schema: schema.name, orbitalNames });
1976
- return runtime.register(schema).then(() => {
2130
+ return runtime.register(schema, messages !== void 0 ? { messages } : {}).then(() => {
1977
2131
  playgroundLog.debug("register:done", { schema: schema.name, orbitalNames });
1978
2132
  });
1979
- }, [runtime, schema]);
2133
+ }, [runtime, schema, messages]);
1980
2134
  const teardownTimerRef = useRef(null);
1981
2135
  useEffect(() => {
1982
2136
  if (teardownTimerRef.current !== null) {
@@ -2006,7 +2160,13 @@ function BrowserPlayground({
2006
2160
  ),
2007
2161
  [runtime, registrationReady]
2008
2162
  );
2009
- return /* @__PURE__ */ jsx(
2163
+ const viewerLocale = locale ?? schema.locales?.[0];
2164
+ const i18n = useMemo(() => {
2165
+ if (viewerLocale === void 0 || messages === void 0) return void 0;
2166
+ const catalog = messages[viewerLocale] ?? {};
2167
+ return { locale: viewerLocale, direction: localeDirection(viewerLocale), t: createTranslate(catalog), messages: catalog };
2168
+ }, [viewerLocale, messages]);
2169
+ const preview = /* @__PURE__ */ jsx(
2010
2170
  OrbPreview,
2011
2171
  {
2012
2172
  schema,
@@ -2020,6 +2180,7 @@ function BrowserPlayground({
2020
2180
  isolated: true
2021
2181
  }
2022
2182
  );
2183
+ return i18n !== void 0 ? /* @__PURE__ */ jsx(I18nProvider, { value: i18n, children: preview }) : preview;
2023
2184
  }
2024
2185
 
2025
2186
  export { BrowserPlayground, OrbPreview, clearSchemaCache, useResolvedSchema, useTraitStateMachine };
@@ -306,6 +306,7 @@ var OPERATOR_CATEGORY_COLORS = {
306
306
  "std-json": avlBlend("var(--color-success)", 60, "var(--color-foreground)"),
307
307
  "std-time": avlBlend("var(--color-info)", 50, "var(--color-success)"),
308
308
  "std-format": avlBlend("var(--color-success)", 60, "var(--color-background)"),
309
+ "std-i18n": avlBlend("var(--color-info)", 60, "var(--color-background)"),
309
310
  "std-async": avlBlend("var(--color-accent)", 50, "var(--color-error)"),
310
311
  "std-nn": avlBlend("var(--color-primary)", 60, "var(--color-accent)"),
311
312
  "std-tensor": avlBlend("var(--color-primary)", 60, "var(--color-info)"),
@@ -1,5 +1,5 @@
1
- import { avlBlend, AVL_INK, EFFECT_CATEGORY_COLORS, OPERATOR_CATEGORY_COLORS, avlTint, Box, VStack, effectCategoryOf } from './chunk-7LM6I3NA.js';
2
- import { Typography } from './chunk-HB4C27KU.js';
1
+ import { avlBlend, AVL_INK, EFFECT_CATEGORY_COLORS, OPERATOR_CATEGORY_COLORS, avlTint, Box, VStack, effectCategoryOf } from './chunk-Z5IYJU44.js';
2
+ import { Typography } from './chunk-4UP6BZ4R.js';
3
3
  import { Vector3, QuadraticBezierCurve3, MathUtils, Quaternion } from 'three';
4
4
  import { EntityPersistenceSchema } from '@almadar/core';
5
5
  import { getStdOperatorMeta } from '@almadar/std/registry';