@almadar/ui 4.6.14 → 4.8.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.
@@ -5374,13 +5374,23 @@ function SlotsProvider({ children }) {
5374
5374
  const setSlotPatterns = React127.useCallback((slot, patterns, source) => {
5375
5375
  const sourceKey = source?.trait ?? DEFAULT_SOURCE_KEY2;
5376
5376
  const entityProp = patterns[0]?.pattern && typeof patterns[0].pattern === "object" ? patterns[0].pattern.entity : void 0;
5377
+ const firstPatternType = patterns[0]?.pattern && typeof patterns[0].pattern === "object" ? patterns[0].pattern.type : void 0;
5377
5378
  slotLog.debug("setSlotPatterns", {
5378
5379
  slot,
5379
5380
  sourceKey,
5380
5381
  patternCount: patterns.length,
5381
- firstPatternType: patterns[0]?.pattern && typeof patterns[0].pattern === "object" ? patterns[0].pattern.type : void 0,
5382
+ firstPatternType,
5382
5383
  entityRefId: refId(entityProp)
5383
5384
  });
5385
+ if (source?.trait) {
5386
+ xOrbitalLog.info("slot-set", {
5387
+ slot,
5388
+ sourceTrait: source.trait,
5389
+ patternCount: patterns.length,
5390
+ firstPatternType,
5391
+ state: source.state
5392
+ });
5393
+ }
5384
5394
  setSlots((prev) => {
5385
5395
  const prevSlot = prev[slot] ?? {};
5386
5396
  return {
@@ -5402,6 +5412,7 @@ function SlotsProvider({ children }) {
5402
5412
  });
5403
5413
  }, []);
5404
5414
  const clearSlotForSource = React127.useCallback((slot, sourceTrait) => {
5415
+ xOrbitalLog.info("slot-clear-source", { slot, sourceTrait });
5405
5416
  setSlots((prev) => {
5406
5417
  const existing = prev[slot];
5407
5418
  if (!existing || !(sourceTrait in existing)) return prev;
@@ -5438,11 +5449,12 @@ function useSlotsActions() {
5438
5449
  }
5439
5450
  return actions;
5440
5451
  }
5441
- var slotLog, refIds, nextRefId, DEFAULT_SOURCE_KEY2, SlotsStateContext, SlotsActionsContext;
5452
+ var slotLog, xOrbitalLog, refIds, nextRefId, DEFAULT_SOURCE_KEY2, SlotsStateContext, SlotsActionsContext;
5442
5453
  var init_SlotsContext = __esm({
5443
5454
  "runtime/ui/SlotsContext.tsx"() {
5444
5455
  init_logger();
5445
5456
  slotLog = createLogger("almadar:ui:slot-render");
5457
+ xOrbitalLog = createLogger("almadar:runtime:cross-orbital");
5446
5458
  refIds = /* @__PURE__ */ new WeakMap();
5447
5459
  nextRefId = 1;
5448
5460
  DEFAULT_SOURCE_KEY2 = "__default__";
@@ -11178,7 +11190,7 @@ var init_MapView = __esm({
11178
11190
  shadowSize: [41, 41]
11179
11191
  });
11180
11192
  L.Marker.prototype.options.icon = defaultIcon;
11181
- const { useEffect: useEffect87, useRef: useRef87, useCallback: useCallback125, useState: useState125 } = React127__namespace.default;
11193
+ const { useEffect: useEffect87, useRef: useRef87, useCallback: useCallback125, useState: useState124 } = React127__namespace.default;
11182
11194
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
11183
11195
  const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
11184
11196
  function MapUpdater({ centerLat, centerLng, zoom }) {
@@ -11222,7 +11234,7 @@ var init_MapView = __esm({
11222
11234
  showAttribution = true
11223
11235
  }) {
11224
11236
  const eventBus = useEventBus3();
11225
- const [clickedPosition, setClickedPosition] = useState125(null);
11237
+ const [clickedPosition, setClickedPosition] = useState124(null);
11226
11238
  const handleMapClick = useCallback125((lat, lng) => {
11227
11239
  if (showClickedPin) {
11228
11240
  setClickedPosition({ lat, lng });
@@ -12323,9 +12335,9 @@ function bindEventBus(eventBus) {
12323
12335
  log2.info("bindEventBus", { hasOnAny: !!eventBus.onAny });
12324
12336
  exposeOnWindow();
12325
12337
  if (window.__orbitalVerification) {
12326
- window.__orbitalVerification.sendEvent = (event, payload) => {
12327
- const prefixed = event.startsWith("UI:") ? event : `UI:${event}`;
12328
- log2.debug("sendEvent", { event: prefixed, payloadKeys: payload ? Object.keys(payload) : [] });
12338
+ window.__orbitalVerification.sendEvent = (event, payload, traitScope) => {
12339
+ const prefixed = event.startsWith("UI:") ? event : traitScope ? `UI:${traitScope}.${event}` : `UI:${event}`;
12340
+ log2.debug("sendEvent", { event: prefixed, traitScope, payloadKeys: payload ? Object.keys(payload) : [] });
12329
12341
  eventBus.emit(prefixed, payload);
12330
12342
  };
12331
12343
  const eventLog = [];
@@ -21930,8 +21942,7 @@ function formatValue(value, format) {
21930
21942
  }
21931
21943
  function DataGrid({
21932
21944
  entity,
21933
- fields: fieldsProp,
21934
- columns: columnsProp,
21945
+ fields,
21935
21946
  itemActions,
21936
21947
  cols,
21937
21948
  gap = "md",
@@ -21952,7 +21963,6 @@ function DataGrid({
21952
21963
  const { t } = useTranslate();
21953
21964
  const [selectedIds, setSelectedIds] = React127.useState(/* @__PURE__ */ new Set());
21954
21965
  const [visibleCount, setVisibleCount] = React127.useState(pageSize || Infinity);
21955
- const fields = fieldsProp ?? columnsProp ?? [];
21956
21966
  const allData = Array.isArray(entity) ? entity : entity ? [entity] : [];
21957
21967
  const data = pageSize > 0 ? allData.slice(0, visibleCount) : allData;
21958
21968
  const hasMoreLocal = pageSize > 0 && visibleCount < allData.length;
@@ -22295,8 +22305,7 @@ function groupData(items, field) {
22295
22305
  }
22296
22306
  function DataList({
22297
22307
  entity,
22298
- fields: fieldsProp,
22299
- columns: columnsProp,
22308
+ fields,
22300
22309
  itemActions,
22301
22310
  gap = "none",
22302
22311
  variant = "default",
@@ -22325,7 +22334,6 @@ function DataList({
22325
22334
  const eventBus = useEventBus();
22326
22335
  const { t } = useTranslate();
22327
22336
  const [visibleCount, setVisibleCount] = React127__namespace.default.useState(pageSize || Infinity);
22328
- const fields = fieldsProp ?? columnsProp ?? [];
22329
22337
  const allData = Array.isArray(entity) ? entity : entity ? [entity] : [];
22330
22338
  const data = pageSize > 0 ? allData.slice(0, visibleCount) : allData;
22331
22339
  const hasMoreLocal = pageSize > 0 && visibleCount < allData.length;
@@ -51500,6 +51508,7 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
51500
51508
  const eventBus = useEventBus();
51501
51509
  const { entities } = useEntitySchema();
51502
51510
  const traitConfigsByName = options?.traitConfigsByName;
51511
+ const orbitalsByTrait = options?.orbitalsByTrait;
51503
51512
  const manager = React127.useMemo(() => {
51504
51513
  const traitDefs = traitBindings.map(toTraitDefinition);
51505
51514
  const m = new runtime.StateMachineManager(traitDefs);
@@ -51948,7 +51957,10 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
51948
51957
  if (!LIFECYCLE_EVENTS.has(normalizedEvent)) {
51949
51958
  for (const { traitName, result } of results) {
51950
51959
  if (!result.executed) continue;
51951
- eventBus.emit(normalizedEvent, payload, {
51960
+ const orbitalName = orbitalsByTrait?.[traitName];
51961
+ if (!orbitalName) continue;
51962
+ eventBus.emit(`UI:${orbitalName}.${traitName}.${normalizedEvent}`, payload, {
51963
+ orbital: orbitalName,
51952
51964
  trait: traitName,
51953
51965
  fromBridge: true
51954
51966
  });
@@ -51959,7 +51971,13 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
51959
51971
  }
51960
51972
  const onEventProcessed = optionsRef.current?.onEventProcessed;
51961
51973
  if (onEventProcessed) {
51962
- await onEventProcessed(normalizedEvent, payload);
51974
+ const dispatchedOrbitals = /* @__PURE__ */ new Set();
51975
+ for (const { traitName, result } of results) {
51976
+ if (!result.executed) continue;
51977
+ const orbital = orbitalsByTrait?.[traitName];
51978
+ if (orbital) dispatchedOrbitals.add(orbital);
51979
+ }
51980
+ await onEventProcessed(normalizedEvent, payload, dispatchedOrbitals);
51963
51981
  }
51964
51982
  }, [entities, eventBus]);
51965
51983
  const drainEventQueue = React127.useCallback(async () => {
@@ -52003,26 +52021,34 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
52003
52021
  }
52004
52022
  console.log("[TraitStateMachine] Subscribing to events:", Array.from(allEvents));
52005
52023
  const unsubscribes = [];
52006
- for (const eventKey of allEvents) {
52007
- if (eventKey === "INIT" || eventKey === "LOAD" || eventKey === "$MOUNT") {
52008
- continue;
52024
+ for (const binding of traitBindings) {
52025
+ const traitName = binding.trait.name;
52026
+ const orbitalName = orbitalsByTrait?.[traitName];
52027
+ if (!orbitalName) continue;
52028
+ for (const transition of binding.trait.transitions) {
52029
+ const eventKey = transition.event;
52030
+ if (eventKey === "INIT" || eventKey === "LOAD" || eventKey === "$MOUNT") {
52031
+ continue;
52032
+ }
52033
+ const unsub = eventBus.on(`UI:${orbitalName}.${traitName}.${eventKey}`, (event) => {
52034
+ if (event.source && event.source.fromBridge) {
52035
+ return;
52036
+ }
52037
+ enqueueAndDrain(eventKey, event.payload);
52038
+ });
52039
+ unsubscribes.push(unsub);
52009
52040
  }
52010
- const unsub = eventBus.on(`UI:${eventKey}`, (event) => {
52011
- console.log("[TraitStateMachine] Received event:", `UI:${eventKey}`, event);
52012
- enqueueAndDrain(eventKey, event.payload);
52013
- });
52014
- unsubscribes.push(unsub);
52015
52041
  }
52016
52042
  for (const binding of traitBindings) {
52043
+ const ownOrbital = orbitalsByTrait?.[binding.trait.name];
52017
52044
  const listens = binding.trait.listens ?? [];
52018
52045
  for (const listen of listens) {
52019
- const expectedTrait = listen.source?.trait;
52020
- const unsub = eventBus.on(listen.event, (event) => {
52021
- if (expectedTrait) {
52022
- const emitTrait = event.source?.trait;
52023
- if (emitTrait !== expectedTrait) return;
52024
- }
52025
- console.log("[TraitStateMachine] listens", binding.trait.name, listen.event, "\u2192", listen.triggers, "from", event.source?.trait);
52046
+ const sourceTrait = listen.source?.trait;
52047
+ if (!sourceTrait) continue;
52048
+ const sourceOrbital = listen.source?.orbital ?? ownOrbital;
52049
+ if (!sourceOrbital) continue;
52050
+ const busKey = `UI:${sourceOrbital}.${sourceTrait}.${listen.event}`;
52051
+ const unsub = eventBus.on(busKey, (event) => {
52026
52052
  enqueueAndDrain(listen.triggers, event.payload);
52027
52053
  });
52028
52054
  unsubscribes.push(unsub);
@@ -52048,6 +52074,8 @@ init_EntitySchemaContext();
52048
52074
 
52049
52075
  // runtime/ServerBridge.tsx
52050
52076
  init_useEventBus();
52077
+ init_logger();
52078
+ var xOrbitalLog2 = createLogger("almadar:runtime:cross-orbital");
52051
52079
  var ServerBridgeContext = React127.createContext(null);
52052
52080
  function useServerBridge() {
52053
52081
  const ctx = React127.useContext(ServerBridgeContext);
@@ -52125,8 +52153,22 @@ function ServerBridgeProvider({
52125
52153
  }
52126
52154
  if (result.emittedEvents) {
52127
52155
  for (const emitted of result.emittedEvents) {
52128
- eventBus.emit(`UI:${emitted.event}`, emitted.payload);
52129
- eventBus.emit(emitted.event, emitted.payload);
52156
+ const evTrait = emitted.source?.trait;
52157
+ if (!evTrait) {
52158
+ xOrbitalLog2.warn("emit:dropped-no-source", {
52159
+ event: emitted.event,
52160
+ dispatchOrbital: orbitalName
52161
+ });
52162
+ continue;
52163
+ }
52164
+ const key = emitted.source?.orbital ? `UI:${emitted.source.orbital}.${evTrait}.${emitted.event}` : `UI:${evTrait}.${emitted.event}`;
52165
+ xOrbitalLog2.info("emit:rebroadcast", {
52166
+ busKey: key,
52167
+ sourceOrbital: emitted.source?.orbital,
52168
+ sourceTrait: evTrait,
52169
+ dispatchOrbital: orbitalName
52170
+ });
52171
+ eventBus.emit(key, emitted.payload);
52130
52172
  }
52131
52173
  }
52132
52174
  } else if (result.error) {
@@ -52247,6 +52289,10 @@ function prepareSchemaForPreview(input) {
52247
52289
  const schema = adjustSchemaForMockData(parsed, mockData);
52248
52290
  return { schema, mockData };
52249
52291
  }
52292
+
52293
+ // runtime/OrbPreview.tsx
52294
+ init_logger();
52295
+ var xOrbitalLog3 = createLogger("almadar:runtime:cross-orbital");
52250
52296
  function normalizeChild(child) {
52251
52297
  if (typeof child === "string") return child;
52252
52298
  if (child === null || typeof child !== "object" || Array.isArray(child)) {
@@ -52326,6 +52372,11 @@ function applyServerEffects(effects, uiSlots, onNavigate) {
52326
52372
  const patternRecord = eff.pattern;
52327
52373
  const { type: patternType, children, ...inlineProps } = patternRecord;
52328
52374
  const normalizedChildren = Array.isArray(children) ? children.map((c) => normalizeChild(c)) : children;
52375
+ xOrbitalLog3.info("slot-write", {
52376
+ slot: eff.slot,
52377
+ sourceTrait: eff.traitName ?? "server",
52378
+ patternType: typeof patternType === "string" ? patternType : void 0
52379
+ });
52329
52380
  uiSlots.render({
52330
52381
  target: eff.slot,
52331
52382
  pattern: patternType,
@@ -52340,19 +52391,26 @@ function applyServerEffects(effects, uiSlots, onNavigate) {
52340
52391
  }
52341
52392
  }
52342
52393
  }
52343
- function TraitInitializer({ traits: traits2, orbitalNames, onNavigate, onLocalFallback, persistence, traitConfigsByName }) {
52394
+ function TraitInitializer({ traits: traits2, orbitalNames, onNavigate, onLocalFallback, persistence, traitConfigsByName, orbitalsByTrait }) {
52344
52395
  const slotsActions = useSlotsActions();
52345
52396
  const bridge = useServerBridge();
52346
52397
  const uiSlots = useUISlots();
52347
- const onEventProcessed = React127.useCallback(async (event, payload) => {
52398
+ const onEventProcessed = React127.useCallback(async (event, payload, dispatchedOrbitals) => {
52348
52399
  if (!bridge.connected || !orbitalNames?.length) return;
52349
- for (const name of orbitalNames) {
52400
+ const targets = dispatchedOrbitals && dispatchedOrbitals.size > 0 ? orbitalNames.filter((n) => dispatchedOrbitals.has(n)) : orbitalNames;
52401
+ xOrbitalLog3.info("TraitInitializer:fanout", {
52402
+ event,
52403
+ sentTo: targets,
52404
+ skipped: orbitalNames.filter((n) => !targets.includes(n)),
52405
+ dispatchedOrbitalsSize: dispatchedOrbitals?.size ?? 0
52406
+ });
52407
+ for (const name of targets) {
52350
52408
  const { effects, meta } = await bridge.sendEvent(name, event, payload);
52351
52409
  recordServerResponse(name, event, meta);
52352
52410
  applyServerEffects(effects, uiSlots, onNavigate);
52353
52411
  }
52354
52412
  }, [bridge.connected, bridge.sendEvent, orbitalNames, uiSlots, onNavigate]);
52355
- const opts = orbitalNames ? { onEventProcessed, navigate: onNavigate, traitConfigsByName } : { navigate: onNavigate, persistence, traitConfigsByName };
52413
+ const opts = orbitalNames ? { onEventProcessed, navigate: onNavigate, traitConfigsByName, orbitalsByTrait } : { navigate: onNavigate, persistence, traitConfigsByName, orbitalsByTrait };
52356
52414
  const { sendEvent } = useTraitStateMachine(traits2, slotsActions, opts);
52357
52415
  const initSentRef = React127.useRef(false);
52358
52416
  React127.useEffect(() => {
@@ -52402,27 +52460,68 @@ function SchemaRunner({ schema, serverUrl, mockData, pageName, onNavigate, onLoc
52402
52460
  const allPageTraits = React127.useMemo(() => {
52403
52461
  if (pageName && traits2.length > 0) return traits2;
52404
52462
  if (!ir?.pages || ir.pages.size <= 1) return traits2;
52405
- const combined = [];
52463
+ const firstPage = ir.pages.values().next().value;
52464
+ if (!firstPage) return traits2;
52465
+ const firstPageTraits = [];
52406
52466
  const seen = /* @__PURE__ */ new Set();
52407
- for (const page of ir.pages.values()) {
52408
- for (const t of page.traits) {
52409
- const binding = t;
52410
- const traitObj = binding.trait;
52411
- const name = traitObj?.name ?? binding.name ?? "";
52412
- if (name && !seen.has(name)) {
52413
- seen.add(name);
52414
- combined.push(t);
52415
- }
52467
+ for (const binding of firstPage.traits) {
52468
+ const name = binding.trait.name;
52469
+ if (name && !seen.has(name)) {
52470
+ seen.add(name);
52471
+ firstPageTraits.push(binding);
52416
52472
  }
52417
52473
  }
52418
- return combined.length > 0 ? combined : traits2;
52474
+ return firstPageTraits.length > 0 ? firstPageTraits : traits2;
52419
52475
  }, [ir, traits2, pageName]);
52420
- const orbitalNames = React127.useMemo(() => {
52476
+ React127.useMemo(() => {
52421
52477
  const parsed = schema;
52422
52478
  const orbitals = parsed?.orbitals;
52423
52479
  if (!orbitals) return [];
52424
52480
  return orbitals.filter((o) => typeof o.name === "string").map((o) => o.name);
52425
52481
  }, [schema]);
52482
+ const orbitalsByTrait = React127.useMemo(() => {
52483
+ const map = {};
52484
+ const parsed = schema;
52485
+ if (!parsed?.orbitals) return map;
52486
+ for (const orb of parsed.orbitals) {
52487
+ for (const traitRef of orb.traits) {
52488
+ let traitName;
52489
+ if (typeof traitRef === "string") {
52490
+ const parts = traitRef.split(".");
52491
+ traitName = parts[parts.length - 1];
52492
+ } else if ("ref" in traitRef && typeof traitRef.ref === "string") {
52493
+ const parts = traitRef.ref.split(".");
52494
+ traitName = traitRef.name ?? parts[parts.length - 1];
52495
+ } else if ("name" in traitRef && typeof traitRef.name === "string") {
52496
+ traitName = traitRef.name;
52497
+ }
52498
+ if (traitName) map[traitName] = orb.name;
52499
+ }
52500
+ }
52501
+ return map;
52502
+ }, [schema]);
52503
+ const pageOrbitalNames = React127.useMemo(() => {
52504
+ const set = /* @__PURE__ */ new Set();
52505
+ for (const binding of allPageTraits) {
52506
+ const orb = orbitalsByTrait[binding.trait.name];
52507
+ if (orb) set.add(orb);
52508
+ }
52509
+ return Array.from(set);
52510
+ }, [allPageTraits, orbitalsByTrait]);
52511
+ React127.useEffect(() => {
52512
+ const traitNames = allPageTraits.map((b) => b.trait.name);
52513
+ const orbitalsByTraitForPage = {};
52514
+ for (const name of traitNames) {
52515
+ const orb = orbitalsByTrait[name];
52516
+ if (orb) orbitalsByTraitForPage[name] = orb;
52517
+ }
52518
+ xOrbitalLog3.info("SchemaRunner:mount", {
52519
+ pageName,
52520
+ traitNames,
52521
+ orbitalsByTraitForPage,
52522
+ pageOrbitalNames: pageOrbitalNames.join(",")
52523
+ });
52524
+ }, [pageName, allPageTraits, orbitalsByTrait, pageOrbitalNames]);
52426
52525
  const traitConfigsByName = React127.useMemo(() => {
52427
52526
  const map = {};
52428
52527
  const parsed = schema;
@@ -52463,8 +52562,9 @@ function SchemaRunner({ schema, serverUrl, mockData, pageName, onNavigate, onLoc
52463
52562
  TraitInitializer,
52464
52563
  {
52465
52564
  traits: allPageTraits,
52466
- orbitalNames: serverUrl ? orbitalNames : void 0,
52565
+ orbitalNames: serverUrl ? pageOrbitalNames : void 0,
52467
52566
  traitConfigsByName,
52567
+ orbitalsByTrait,
52468
52568
  onNavigate,
52469
52569
  onLocalFallback,
52470
52570
  persistence
@@ -52486,7 +52586,8 @@ function OrbPreview({
52486
52586
  autoMock = false,
52487
52587
  height = "400px",
52488
52588
  className,
52489
- serverUrl
52589
+ serverUrl,
52590
+ initialPagePath
52490
52591
  }) {
52491
52592
  const [localFallback, setLocalFallback] = React127.useState(false);
52492
52593
  const eventBus = useEventBus();
@@ -52532,7 +52633,17 @@ function OrbPreview({
52532
52633
  return [];
52533
52634
  }
52534
52635
  }, [parsedSchema]);
52535
- const [currentPage, setCurrentPage] = React127.useState(void 0);
52636
+ const initialPageName = React127.useMemo(() => {
52637
+ if (!initialPagePath) return void 0;
52638
+ const match = pages.find(({ page }) => page.path === initialPagePath);
52639
+ return match?.page.name;
52640
+ }, [pages, initialPagePath]);
52641
+ const [currentPage, setCurrentPage] = React127.useState(initialPageName);
52642
+ React127.useEffect(() => {
52643
+ if (initialPageName && initialPageName !== currentPage) {
52644
+ setCurrentPage(initialPageName);
52645
+ }
52646
+ }, [initialPageName, currentPage]);
52536
52647
  const handleNavigate = React127.useCallback((path) => {
52537
52648
  const match = pages.find(({ page }) => page.path === path);
52538
52649
  if (match) {