@almadar/ui 4.6.13 → 4.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/avl/index.js CHANGED
@@ -5328,13 +5328,23 @@ function SlotsProvider({ children }) {
5328
5328
  const setSlotPatterns = useCallback((slot, patterns, source) => {
5329
5329
  const sourceKey = source?.trait ?? DEFAULT_SOURCE_KEY2;
5330
5330
  const entityProp = patterns[0]?.pattern && typeof patterns[0].pattern === "object" ? patterns[0].pattern.entity : void 0;
5331
+ const firstPatternType = patterns[0]?.pattern && typeof patterns[0].pattern === "object" ? patterns[0].pattern.type : void 0;
5331
5332
  slotLog.debug("setSlotPatterns", {
5332
5333
  slot,
5333
5334
  sourceKey,
5334
5335
  patternCount: patterns.length,
5335
- firstPatternType: patterns[0]?.pattern && typeof patterns[0].pattern === "object" ? patterns[0].pattern.type : void 0,
5336
+ firstPatternType,
5336
5337
  entityRefId: refId(entityProp)
5337
5338
  });
5339
+ if (source?.trait) {
5340
+ xOrbitalLog.info("slot-set", {
5341
+ slot,
5342
+ sourceTrait: source.trait,
5343
+ patternCount: patterns.length,
5344
+ firstPatternType,
5345
+ state: source.state
5346
+ });
5347
+ }
5338
5348
  setSlots((prev) => {
5339
5349
  const prevSlot = prev[slot] ?? {};
5340
5350
  return {
@@ -5356,6 +5366,7 @@ function SlotsProvider({ children }) {
5356
5366
  });
5357
5367
  }, []);
5358
5368
  const clearSlotForSource = useCallback((slot, sourceTrait) => {
5369
+ xOrbitalLog.info("slot-clear-source", { slot, sourceTrait });
5359
5370
  setSlots((prev) => {
5360
5371
  const existing = prev[slot];
5361
5372
  if (!existing || !(sourceTrait in existing)) return prev;
@@ -5392,11 +5403,12 @@ function useSlotsActions() {
5392
5403
  }
5393
5404
  return actions;
5394
5405
  }
5395
- var slotLog, refIds, nextRefId, DEFAULT_SOURCE_KEY2, SlotsStateContext, SlotsActionsContext;
5406
+ var slotLog, xOrbitalLog, refIds, nextRefId, DEFAULT_SOURCE_KEY2, SlotsStateContext, SlotsActionsContext;
5396
5407
  var init_SlotsContext = __esm({
5397
5408
  "runtime/ui/SlotsContext.tsx"() {
5398
5409
  init_logger();
5399
5410
  slotLog = createLogger("almadar:ui:slot-render");
5411
+ xOrbitalLog = createLogger("almadar:runtime:cross-orbital");
5400
5412
  refIds = /* @__PURE__ */ new WeakMap();
5401
5413
  nextRefId = 1;
5402
5414
  DEFAULT_SOURCE_KEY2 = "__default__";
@@ -11132,7 +11144,7 @@ var init_MapView = __esm({
11132
11144
  shadowSize: [41, 41]
11133
11145
  });
11134
11146
  L.Marker.prototype.options.icon = defaultIcon;
11135
- const { useEffect: useEffect87, useRef: useRef87, useCallback: useCallback125, useState: useState125 } = React127__default;
11147
+ const { useEffect: useEffect87, useRef: useRef87, useCallback: useCallback125, useState: useState124 } = React127__default;
11136
11148
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
11137
11149
  const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
11138
11150
  function MapUpdater({ centerLat, centerLng, zoom }) {
@@ -11176,7 +11188,7 @@ var init_MapView = __esm({
11176
11188
  showAttribution = true
11177
11189
  }) {
11178
11190
  const eventBus = useEventBus3();
11179
- const [clickedPosition, setClickedPosition] = useState125(null);
11191
+ const [clickedPosition, setClickedPosition] = useState124(null);
11180
11192
  const handleMapClick = useCallback125((lat, lng) => {
11181
11193
  if (showClickedPin) {
11182
11194
  setClickedPosition({ lat, lng });
@@ -12277,9 +12289,9 @@ function bindEventBus(eventBus) {
12277
12289
  log2.info("bindEventBus", { hasOnAny: !!eventBus.onAny });
12278
12290
  exposeOnWindow();
12279
12291
  if (window.__orbitalVerification) {
12280
- window.__orbitalVerification.sendEvent = (event, payload) => {
12281
- const prefixed = event.startsWith("UI:") ? event : `UI:${event}`;
12282
- log2.debug("sendEvent", { event: prefixed, payloadKeys: payload ? Object.keys(payload) : [] });
12292
+ window.__orbitalVerification.sendEvent = (event, payload, traitScope) => {
12293
+ const prefixed = event.startsWith("UI:") ? event : traitScope ? `UI:${traitScope}.${event}` : `UI:${event}`;
12294
+ log2.debug("sendEvent", { event: prefixed, traitScope, payloadKeys: payload ? Object.keys(payload) : [] });
12283
12295
  eventBus.emit(prefixed, payload);
12284
12296
  };
12285
12297
  const eventLog = [];
@@ -51454,6 +51466,7 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
51454
51466
  const eventBus = useEventBus();
51455
51467
  const { entities } = useEntitySchema();
51456
51468
  const traitConfigsByName = options?.traitConfigsByName;
51469
+ const orbitalsByTrait = options?.orbitalsByTrait;
51457
51470
  const manager = useMemo(() => {
51458
51471
  const traitDefs = traitBindings.map(toTraitDefinition);
51459
51472
  const m = new StateMachineManager(traitDefs);
@@ -51666,24 +51679,7 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
51666
51679
  const actions = slotsActionsRef.current;
51667
51680
  console.log("[TraitStateMachine] Processing event:", normalizedEvent, "payload:", payload);
51668
51681
  const bindingMap = new Map(bindings.map((b) => [b.trait.name, b]));
51669
- for (const traitName of bindingMap.keys()) {
51670
- const traitState = currentManager.getState(traitName);
51671
- eventBus.emit(`${traitName}:DISPATCH`, {
51672
- event: normalizedEvent,
51673
- payload,
51674
- currentState: traitState?.currentState
51675
- });
51676
- }
51677
51682
  const results = currentManager.sendEvent(normalizedEvent, payload);
51678
- for (const { traitName, result } of results) {
51679
- const suffix = result.executed ? "SUCCESS" : "ERROR";
51680
- eventBus.emit(`${traitName}:${normalizedEvent}:${suffix}`, {
51681
- event: normalizedEvent,
51682
- payload,
51683
- newState: result.newState,
51684
- currentState: result.previousState
51685
- });
51686
- }
51687
51683
  const emittedByTrait = /* @__PURE__ */ new Map();
51688
51684
  for (const { traitName, result } of results) {
51689
51685
  const binding = bindingMap.get(traitName);
@@ -51919,7 +51915,10 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
51919
51915
  if (!LIFECYCLE_EVENTS.has(normalizedEvent)) {
51920
51916
  for (const { traitName, result } of results) {
51921
51917
  if (!result.executed) continue;
51922
- eventBus.emit(normalizedEvent, payload, {
51918
+ const orbitalName = orbitalsByTrait?.[traitName];
51919
+ if (!orbitalName) continue;
51920
+ eventBus.emit(`UI:${orbitalName}.${traitName}.${normalizedEvent}`, payload, {
51921
+ orbital: orbitalName,
51923
51922
  trait: traitName,
51924
51923
  fromBridge: true
51925
51924
  });
@@ -51930,7 +51929,13 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
51930
51929
  }
51931
51930
  const onEventProcessed = optionsRef.current?.onEventProcessed;
51932
51931
  if (onEventProcessed) {
51933
- await onEventProcessed(normalizedEvent, payload);
51932
+ const dispatchedOrbitals = /* @__PURE__ */ new Set();
51933
+ for (const { traitName, result } of results) {
51934
+ if (!result.executed) continue;
51935
+ const orbital = orbitalsByTrait?.[traitName];
51936
+ if (orbital) dispatchedOrbitals.add(orbital);
51937
+ }
51938
+ await onEventProcessed(normalizedEvent, payload, dispatchedOrbitals);
51934
51939
  }
51935
51940
  }, [entities, eventBus]);
51936
51941
  const drainEventQueue = useCallback(async () => {
@@ -51974,26 +51979,34 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
51974
51979
  }
51975
51980
  console.log("[TraitStateMachine] Subscribing to events:", Array.from(allEvents));
51976
51981
  const unsubscribes = [];
51977
- for (const eventKey of allEvents) {
51978
- if (eventKey === "INIT" || eventKey === "LOAD" || eventKey === "$MOUNT") {
51979
- continue;
51982
+ for (const binding of traitBindings) {
51983
+ const traitName = binding.trait.name;
51984
+ const orbitalName = orbitalsByTrait?.[traitName];
51985
+ if (!orbitalName) continue;
51986
+ for (const transition of binding.trait.transitions) {
51987
+ const eventKey = transition.event;
51988
+ if (eventKey === "INIT" || eventKey === "LOAD" || eventKey === "$MOUNT") {
51989
+ continue;
51990
+ }
51991
+ const unsub = eventBus.on(`UI:${orbitalName}.${traitName}.${eventKey}`, (event) => {
51992
+ if (event.source && event.source.fromBridge) {
51993
+ return;
51994
+ }
51995
+ enqueueAndDrain(eventKey, event.payload);
51996
+ });
51997
+ unsubscribes.push(unsub);
51980
51998
  }
51981
- const unsub = eventBus.on(`UI:${eventKey}`, (event) => {
51982
- console.log("[TraitStateMachine] Received event:", `UI:${eventKey}`, event);
51983
- enqueueAndDrain(eventKey, event.payload);
51984
- });
51985
- unsubscribes.push(unsub);
51986
51999
  }
51987
52000
  for (const binding of traitBindings) {
52001
+ const ownOrbital = orbitalsByTrait?.[binding.trait.name];
51988
52002
  const listens = binding.trait.listens ?? [];
51989
52003
  for (const listen of listens) {
51990
- const expectedTrait = listen.source?.trait;
51991
- const unsub = eventBus.on(listen.event, (event) => {
51992
- if (expectedTrait) {
51993
- const emitTrait = event.source?.trait;
51994
- if (emitTrait !== expectedTrait) return;
51995
- }
51996
- console.log("[TraitStateMachine] listens", binding.trait.name, listen.event, "\u2192", listen.triggers, "from", event.source?.trait);
52004
+ const sourceTrait = listen.source?.trait;
52005
+ if (!sourceTrait) continue;
52006
+ const sourceOrbital = listen.source?.orbital ?? ownOrbital;
52007
+ if (!sourceOrbital) continue;
52008
+ const busKey = `UI:${sourceOrbital}.${sourceTrait}.${listen.event}`;
52009
+ const unsub = eventBus.on(busKey, (event) => {
51997
52010
  enqueueAndDrain(listen.triggers, event.payload);
51998
52011
  });
51999
52012
  unsubscribes.push(unsub);
@@ -52019,6 +52032,8 @@ init_EntitySchemaContext();
52019
52032
 
52020
52033
  // runtime/ServerBridge.tsx
52021
52034
  init_useEventBus();
52035
+ init_logger();
52036
+ var xOrbitalLog2 = createLogger("almadar:runtime:cross-orbital");
52022
52037
  var ServerBridgeContext = createContext(null);
52023
52038
  function useServerBridge() {
52024
52039
  const ctx = useContext(ServerBridgeContext);
@@ -52096,8 +52111,22 @@ function ServerBridgeProvider({
52096
52111
  }
52097
52112
  if (result.emittedEvents) {
52098
52113
  for (const emitted of result.emittedEvents) {
52099
- eventBus.emit(`UI:${emitted.event}`, emitted.payload);
52100
- eventBus.emit(emitted.event, emitted.payload);
52114
+ const evTrait = emitted.source?.trait;
52115
+ if (!evTrait) {
52116
+ xOrbitalLog2.warn("emit:dropped-no-source", {
52117
+ event: emitted.event,
52118
+ dispatchOrbital: orbitalName
52119
+ });
52120
+ continue;
52121
+ }
52122
+ const key = emitted.source?.orbital ? `UI:${emitted.source.orbital}.${evTrait}.${emitted.event}` : `UI:${evTrait}.${emitted.event}`;
52123
+ xOrbitalLog2.info("emit:rebroadcast", {
52124
+ busKey: key,
52125
+ sourceOrbital: emitted.source?.orbital,
52126
+ sourceTrait: evTrait,
52127
+ dispatchOrbital: orbitalName
52128
+ });
52129
+ eventBus.emit(key, emitted.payload);
52101
52130
  }
52102
52131
  }
52103
52132
  } else if (result.error) {
@@ -52218,6 +52247,10 @@ function prepareSchemaForPreview(input) {
52218
52247
  const schema = adjustSchemaForMockData(parsed, mockData);
52219
52248
  return { schema, mockData };
52220
52249
  }
52250
+
52251
+ // runtime/OrbPreview.tsx
52252
+ init_logger();
52253
+ var xOrbitalLog3 = createLogger("almadar:runtime:cross-orbital");
52221
52254
  function normalizeChild(child) {
52222
52255
  if (typeof child === "string") return child;
52223
52256
  if (child === null || typeof child !== "object" || Array.isArray(child)) {
@@ -52297,6 +52330,11 @@ function applyServerEffects(effects, uiSlots, onNavigate) {
52297
52330
  const patternRecord = eff.pattern;
52298
52331
  const { type: patternType, children, ...inlineProps } = patternRecord;
52299
52332
  const normalizedChildren = Array.isArray(children) ? children.map((c) => normalizeChild(c)) : children;
52333
+ xOrbitalLog3.info("slot-write", {
52334
+ slot: eff.slot,
52335
+ sourceTrait: eff.traitName ?? "server",
52336
+ patternType: typeof patternType === "string" ? patternType : void 0
52337
+ });
52300
52338
  uiSlots.render({
52301
52339
  target: eff.slot,
52302
52340
  pattern: patternType,
@@ -52311,19 +52349,26 @@ function applyServerEffects(effects, uiSlots, onNavigate) {
52311
52349
  }
52312
52350
  }
52313
52351
  }
52314
- function TraitInitializer({ traits: traits2, orbitalNames, onNavigate, onLocalFallback, persistence, traitConfigsByName }) {
52352
+ function TraitInitializer({ traits: traits2, orbitalNames, onNavigate, onLocalFallback, persistence, traitConfigsByName, orbitalsByTrait }) {
52315
52353
  const slotsActions = useSlotsActions();
52316
52354
  const bridge = useServerBridge();
52317
52355
  const uiSlots = useUISlots();
52318
- const onEventProcessed = useCallback(async (event, payload) => {
52356
+ const onEventProcessed = useCallback(async (event, payload, dispatchedOrbitals) => {
52319
52357
  if (!bridge.connected || !orbitalNames?.length) return;
52320
- for (const name of orbitalNames) {
52358
+ const targets = dispatchedOrbitals && dispatchedOrbitals.size > 0 ? orbitalNames.filter((n) => dispatchedOrbitals.has(n)) : orbitalNames;
52359
+ xOrbitalLog3.info("TraitInitializer:fanout", {
52360
+ event,
52361
+ sentTo: targets,
52362
+ skipped: orbitalNames.filter((n) => !targets.includes(n)),
52363
+ dispatchedOrbitalsSize: dispatchedOrbitals?.size ?? 0
52364
+ });
52365
+ for (const name of targets) {
52321
52366
  const { effects, meta } = await bridge.sendEvent(name, event, payload);
52322
52367
  recordServerResponse(name, event, meta);
52323
52368
  applyServerEffects(effects, uiSlots, onNavigate);
52324
52369
  }
52325
52370
  }, [bridge.connected, bridge.sendEvent, orbitalNames, uiSlots, onNavigate]);
52326
- const opts = orbitalNames ? { onEventProcessed, navigate: onNavigate, traitConfigsByName } : { navigate: onNavigate, persistence, traitConfigsByName };
52371
+ const opts = orbitalNames ? { onEventProcessed, navigate: onNavigate, traitConfigsByName, orbitalsByTrait } : { navigate: onNavigate, persistence, traitConfigsByName, orbitalsByTrait };
52327
52372
  const { sendEvent } = useTraitStateMachine(traits2, slotsActions, opts);
52328
52373
  const initSentRef = useRef(false);
52329
52374
  useEffect(() => {
@@ -52373,27 +52418,68 @@ function SchemaRunner({ schema, serverUrl, mockData, pageName, onNavigate, onLoc
52373
52418
  const allPageTraits = useMemo(() => {
52374
52419
  if (pageName && traits2.length > 0) return traits2;
52375
52420
  if (!ir?.pages || ir.pages.size <= 1) return traits2;
52376
- const combined = [];
52421
+ const firstPage = ir.pages.values().next().value;
52422
+ if (!firstPage) return traits2;
52423
+ const firstPageTraits = [];
52377
52424
  const seen = /* @__PURE__ */ new Set();
52378
- for (const page of ir.pages.values()) {
52379
- for (const t of page.traits) {
52380
- const binding = t;
52381
- const traitObj = binding.trait;
52382
- const name = traitObj?.name ?? binding.name ?? "";
52383
- if (name && !seen.has(name)) {
52384
- seen.add(name);
52385
- combined.push(t);
52386
- }
52425
+ for (const binding of firstPage.traits) {
52426
+ const name = binding.trait.name;
52427
+ if (name && !seen.has(name)) {
52428
+ seen.add(name);
52429
+ firstPageTraits.push(binding);
52387
52430
  }
52388
52431
  }
52389
- return combined.length > 0 ? combined : traits2;
52432
+ return firstPageTraits.length > 0 ? firstPageTraits : traits2;
52390
52433
  }, [ir, traits2, pageName]);
52391
- const orbitalNames = useMemo(() => {
52434
+ useMemo(() => {
52392
52435
  const parsed = schema;
52393
52436
  const orbitals = parsed?.orbitals;
52394
52437
  if (!orbitals) return [];
52395
52438
  return orbitals.filter((o) => typeof o.name === "string").map((o) => o.name);
52396
52439
  }, [schema]);
52440
+ const orbitalsByTrait = useMemo(() => {
52441
+ const map = {};
52442
+ const parsed = schema;
52443
+ if (!parsed?.orbitals) return map;
52444
+ for (const orb of parsed.orbitals) {
52445
+ for (const traitRef of orb.traits) {
52446
+ let traitName;
52447
+ if (typeof traitRef === "string") {
52448
+ const parts = traitRef.split(".");
52449
+ traitName = parts[parts.length - 1];
52450
+ } else if ("ref" in traitRef && typeof traitRef.ref === "string") {
52451
+ const parts = traitRef.ref.split(".");
52452
+ traitName = traitRef.name ?? parts[parts.length - 1];
52453
+ } else if ("name" in traitRef && typeof traitRef.name === "string") {
52454
+ traitName = traitRef.name;
52455
+ }
52456
+ if (traitName) map[traitName] = orb.name;
52457
+ }
52458
+ }
52459
+ return map;
52460
+ }, [schema]);
52461
+ const pageOrbitalNames = useMemo(() => {
52462
+ const set = /* @__PURE__ */ new Set();
52463
+ for (const binding of allPageTraits) {
52464
+ const orb = orbitalsByTrait[binding.trait.name];
52465
+ if (orb) set.add(orb);
52466
+ }
52467
+ return Array.from(set);
52468
+ }, [allPageTraits, orbitalsByTrait]);
52469
+ useEffect(() => {
52470
+ const traitNames = allPageTraits.map((b) => b.trait.name);
52471
+ const orbitalsByTraitForPage = {};
52472
+ for (const name of traitNames) {
52473
+ const orb = orbitalsByTrait[name];
52474
+ if (orb) orbitalsByTraitForPage[name] = orb;
52475
+ }
52476
+ xOrbitalLog3.info("SchemaRunner:mount", {
52477
+ pageName,
52478
+ traitNames,
52479
+ orbitalsByTraitForPage,
52480
+ pageOrbitalNames: pageOrbitalNames.join(",")
52481
+ });
52482
+ }, [pageName, allPageTraits, orbitalsByTrait, pageOrbitalNames]);
52397
52483
  const traitConfigsByName = useMemo(() => {
52398
52484
  const map = {};
52399
52485
  const parsed = schema;
@@ -52434,8 +52520,9 @@ function SchemaRunner({ schema, serverUrl, mockData, pageName, onNavigate, onLoc
52434
52520
  TraitInitializer,
52435
52521
  {
52436
52522
  traits: allPageTraits,
52437
- orbitalNames: serverUrl ? orbitalNames : void 0,
52523
+ orbitalNames: serverUrl ? pageOrbitalNames : void 0,
52438
52524
  traitConfigsByName,
52525
+ orbitalsByTrait,
52439
52526
  onNavigate,
52440
52527
  onLocalFallback,
52441
52528
  persistence
@@ -52457,7 +52544,8 @@ function OrbPreview({
52457
52544
  autoMock = false,
52458
52545
  height = "400px",
52459
52546
  className,
52460
- serverUrl
52547
+ serverUrl,
52548
+ initialPagePath
52461
52549
  }) {
52462
52550
  const [localFallback, setLocalFallback] = useState(false);
52463
52551
  const eventBus = useEventBus();
@@ -52503,7 +52591,17 @@ function OrbPreview({
52503
52591
  return [];
52504
52592
  }
52505
52593
  }, [parsedSchema]);
52506
- const [currentPage, setCurrentPage] = useState(void 0);
52594
+ const initialPageName = useMemo(() => {
52595
+ if (!initialPagePath) return void 0;
52596
+ const match = pages.find(({ page }) => page.path === initialPagePath);
52597
+ return match?.page.name;
52598
+ }, [pages, initialPagePath]);
52599
+ const [currentPage, setCurrentPage] = useState(initialPageName);
52600
+ useEffect(() => {
52601
+ if (initialPageName && initialPageName !== currentPage) {
52602
+ setCurrentPage(initialPageName);
52603
+ }
52604
+ }, [initialPageName, currentPage]);
52507
52605
  const handleNavigate = useCallback((path) => {
52508
52606
  const match = pages.find(({ page }) => page.path === path);
52509
52607
  if (match) {
@@ -9,6 +9,8 @@ export interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
9
9
  subtitle?: string;
10
10
  /** Shadow size override */
11
11
  shadow?: CardShadow;
12
+ /** Card content */
13
+ children?: React.ReactNode;
12
14
  }
13
15
  export declare const Card: React.ForwardRefExoticComponent<CardProps & React.RefAttributes<HTMLDivElement>>;
14
16
  export declare const CardHeader: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
@@ -4897,6 +4897,7 @@ var init_SlotsContext = __esm({
4897
4897
  "runtime/ui/SlotsContext.tsx"() {
4898
4898
  init_logger();
4899
4899
  slotLog = createLogger("almadar:ui:slot-render");
4900
+ createLogger("almadar:runtime:cross-orbital");
4900
4901
  refIds = /* @__PURE__ */ new WeakMap();
4901
4902
  nextRefId = 1;
4902
4903
  React111.createContext({});
@@ -6311,7 +6312,7 @@ var init_MapView = __esm({
6311
6312
  shadowSize: [41, 41]
6312
6313
  });
6313
6314
  L.Marker.prototype.options.icon = defaultIcon;
6314
- const { useEffect: useEffect66, useRef: useRef65, useCallback: useCallback115, useState: useState100 } = React111__namespace.default;
6315
+ const { useEffect: useEffect66, useRef: useRef65, useCallback: useCallback115, useState: useState99 } = React111__namespace.default;
6315
6316
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
6316
6317
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
6317
6318
  function MapUpdater({ centerLat, centerLng, zoom }) {
@@ -6355,7 +6356,7 @@ var init_MapView = __esm({
6355
6356
  showAttribution = true
6356
6357
  }) {
6357
6358
  const eventBus = useEventBus2();
6358
- const [clickedPosition, setClickedPosition] = useState100(null);
6359
+ const [clickedPosition, setClickedPosition] = useState99(null);
6359
6360
  const handleMapClick = useCallback115((lat, lng) => {
6360
6361
  if (showClickedPin) {
6361
6362
  setClickedPosition({ lat, lng });
@@ -41123,87 +41124,58 @@ function useUISlotManager() {
41123
41124
  // hooks/useUIEvents.ts
41124
41125
  init_useEventBus();
41125
41126
  var UI_PREFIX = "UI:";
41126
- function useUIEvents(dispatch, validEvents, eventBusInstance) {
41127
+ function useUIEvents(dispatch, traitName, validEvents, eventBusInstance) {
41127
41128
  const defaultEventBus = useEventBus();
41128
41129
  const eventBus = eventBusInstance ?? defaultEventBus;
41129
- const validEventsKey = validEvents ? validEvents.slice().sort().join(",") : "";
41130
+ const validEventsKey = validEvents.slice().sort().join(",");
41130
41131
  const stableValidEvents = React111.useMemo(
41131
41132
  () => validEvents,
41132
41133
  [validEventsKey]
41133
- // intentional — validEventsKey is the stable dep, not validEvents array ref
41134
+ // intentional — validEventsKey is the stable dep
41134
41135
  );
41135
41136
  React111.useEffect(() => {
41136
41137
  const unsubscribes = [];
41137
- if (stableValidEvents) {
41138
- for (const smEvent of stableValidEvents) {
41139
- const prefixedHandler = (event) => {
41140
- dispatch(smEvent, event.payload);
41141
- };
41142
- unsubscribes.push(eventBus.on(`${UI_PREFIX}${smEvent}`, prefixedHandler));
41143
- const directHandler = (event) => {
41144
- if (event.source && event.source.fromBridge) {
41145
- return;
41146
- }
41147
- dispatch(smEvent, event.payload);
41148
- };
41149
- unsubscribes.push(eventBus.on(smEvent, directHandler));
41150
- }
41151
- }
41152
- const genericHandler = (event) => {
41153
- const eventName = event.payload?.event;
41154
- if (eventName) {
41155
- const smEvent = eventName;
41156
- if (!stableValidEvents || stableValidEvents.includes(smEvent)) {
41157
- dispatch(smEvent, event.payload);
41138
+ for (const smEvent of stableValidEvents) {
41139
+ const handler = (event) => {
41140
+ if (event.source && event.source.fromBridge) {
41141
+ return;
41158
41142
  }
41159
- }
41160
- };
41161
- unsubscribes.push(eventBus.on(`${UI_PREFIX}DISPATCH`, genericHandler));
41143
+ dispatch(smEvent, event.payload);
41144
+ };
41145
+ unsubscribes.push(
41146
+ eventBus.on(`${UI_PREFIX}${traitName}.${smEvent}`, handler)
41147
+ );
41148
+ }
41162
41149
  return () => {
41163
41150
  for (const unsub of unsubscribes) {
41164
41151
  if (typeof unsub === "function") unsub();
41165
41152
  }
41166
41153
  };
41167
- }, [eventBus, dispatch, stableValidEvents]);
41154
+ }, [eventBus, dispatch, traitName, stableValidEvents]);
41168
41155
  }
41169
- function useSelectedEntity(eventBusInstance) {
41156
+ function useTraitListens(dispatch, listens, eventBusInstance) {
41170
41157
  const defaultEventBus = useEventBus();
41171
41158
  const eventBus = eventBusInstance ?? defaultEventBus;
41172
- const selectionContext = useSelectionContext();
41173
- const [localSelected, setLocalSelected] = React111.useState(null);
41174
- const usingContext = selectionContext !== null;
41159
+ const stableKey = listens.map((l) => `${l.sourceKey}->${l.trigger}`).sort().join("|");
41160
+ const stableListens = React111.useMemo(
41161
+ () => listens,
41162
+ [stableKey]
41163
+ // intentional
41164
+ );
41175
41165
  React111.useEffect(() => {
41176
- if (usingContext) return;
41177
- const handleSelect = (event) => {
41178
- const row = event.payload?.row;
41179
- if (row) {
41180
- setLocalSelected(row);
41181
- }
41182
- };
41183
- const handleDeselect = () => {
41184
- setLocalSelected(null);
41185
- };
41186
- const unsubSelect = eventBus.on("UI:SELECT", handleSelect);
41187
- const unsubView = eventBus.on("UI:VIEW", handleSelect);
41188
- const unsubDeselect = eventBus.on("UI:DESELECT", handleDeselect);
41189
- const unsubClose = eventBus.on("UI:CLOSE", handleDeselect);
41190
- const unsubCancel = eventBus.on("UI:CANCEL", handleDeselect);
41166
+ const unsubscribes = [];
41167
+ for (const spec of stableListens) {
41168
+ const handler = (event) => {
41169
+ dispatch(spec.trigger, event.payload);
41170
+ };
41171
+ unsubscribes.push(eventBus.on(`${UI_PREFIX}${spec.sourceKey}`, handler));
41172
+ }
41191
41173
  return () => {
41192
- [unsubSelect, unsubView, unsubDeselect, unsubClose, unsubCancel].forEach(
41193
- (unsub) => {
41194
- if (typeof unsub === "function") unsub();
41195
- }
41196
- );
41174
+ for (const unsub of unsubscribes) {
41175
+ if (typeof unsub === "function") unsub();
41176
+ }
41197
41177
  };
41198
- }, [eventBus, usingContext]);
41199
- if (selectionContext) {
41200
- return [selectionContext.selected, selectionContext.setSelected];
41201
- }
41202
- return [localSelected, setLocalSelected];
41203
- }
41204
- function useSelectionContext() {
41205
- const context = React111.useContext(providers.SelectionContext);
41206
- return context;
41178
+ }, [eventBus, dispatch, stableListens]);
41207
41179
  }
41208
41180
 
41209
41181
  // hooks/index.ts
@@ -41738,10 +41710,10 @@ exports.usePlayer = usePlayer;
41738
41710
  exports.usePreview = usePreview;
41739
41711
  exports.usePullToRefresh = usePullToRefresh;
41740
41712
  exports.useQuerySingleton = useQuerySingleton;
41741
- exports.useSelectedEntity = useSelectedEntity;
41742
41713
  exports.useSingletonEntity = useSingletonEntity;
41743
41714
  exports.useSpriteAnimations = useSpriteAnimations;
41744
41715
  exports.useSwipeGesture = useSwipeGesture;
41716
+ exports.useTraitListens = useTraitListens;
41745
41717
  exports.useTranslate = useTranslate;
41746
41718
  exports.useUIEvents = useUIEvents;
41747
41719
  exports.useUISlotManager = useUISlotManager;