@almadar/ui 5.121.2 → 5.121.4

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.
@@ -952,9 +952,9 @@ var fallbackEventBus = {
952
952
  function useEventBus() {
953
953
  const context = react.useContext(providers.EventBusContext);
954
954
  const baseBus = context ?? getGlobalEventBus() ?? fallbackEventBus;
955
- const scope = providers.useTraitScope();
955
+ const chain = providers.useTraitScopeChain();
956
956
  return react.useMemo(() => {
957
- if (!scope) {
957
+ if (chain.length === 0) {
958
958
  return {
959
959
  ...baseBus,
960
960
  emit: (type, payload, source) => {
@@ -970,22 +970,31 @@ function useEventBus() {
970
970
  emit: (type, payload, source) => {
971
971
  if (typeof type === "string" && type.startsWith("UI:")) {
972
972
  const tail = type.slice(3);
973
- const qualified = tail.includes(".") ? type : `UI:${scope.orbital}.${scope.trait}.${tail}`;
974
- if (qualified !== type) {
975
- scopeLog.info("emit:qualified", {
973
+ const isQualified = tail.includes(".");
974
+ const event = isQualified ? tail.split(".").slice(2).join(".") : tail;
975
+ if (!event) {
976
+ baseBus.emit(type, payload, source);
977
+ return;
978
+ }
979
+ const keys = /* @__PURE__ */ new Set();
980
+ if (isQualified) keys.add(type);
981
+ for (const sc of chain) {
982
+ keys.add(`UI:${sc.orbital}.${sc.trait}.${event}`);
983
+ }
984
+ if (keys.size > 1) {
985
+ scopeLog.info("emit:fan-out", {
976
986
  from: type,
977
- to: qualified,
978
- scopeOrbital: scope.orbital,
979
- scopeTrait: scope.trait
987
+ keys: Array.from(keys),
988
+ chainDepth: chain.length
980
989
  });
981
990
  }
982
- baseBus.emit(qualified, payload, source);
991
+ for (const key of keys) baseBus.emit(key, payload, source);
983
992
  return;
984
993
  }
985
994
  baseBus.emit(type, payload, source);
986
995
  }
987
996
  };
988
- }, [baseBus, scope]);
997
+ }, [baseBus, chain]);
989
998
  }
990
999
  function useEventListener(event, handler) {
991
1000
  const eventBus = useEventBus();
@@ -1457,6 +1466,16 @@ function useSharedEntityStore() {
1457
1466
  }
1458
1467
  return storeRef.current;
1459
1468
  }
1469
+ var SharedEntityStoreContext = react.createContext(null);
1470
+ function useSharedEntityStoreContext() {
1471
+ const store = react.useContext(SharedEntityStoreContext);
1472
+ if (!store) {
1473
+ throw new Error(
1474
+ "useSharedEntityStoreContext: no SharedEntityStoreContext.Provider found in the component tree"
1475
+ );
1476
+ }
1477
+ return store;
1478
+ }
1460
1479
  function useSharedEntitySnapshot(store, entityId) {
1461
1480
  return react.useSyncExternalStore(
1462
1481
  (onStoreChange) => store.subscribe(entityId, onStoreChange),
@@ -2807,6 +2826,7 @@ function useGitHubBranches(owner, repo, enabled = true) {
2807
2826
  exports.ALMADAR_DND_MIME = ALMADAR_DND_MIME;
2808
2827
  exports.DEFAULT_SLOTS = DEFAULT_SLOTS;
2809
2828
  exports.I18nProvider = I18nProvider;
2829
+ exports.SharedEntityStoreContext = SharedEntityStoreContext;
2810
2830
  exports.createSharedEntityStore = createSharedEntityStore;
2811
2831
  exports.createTranslate = createTranslate;
2812
2832
  exports.parseQueryBinding = parseQueryBinding;
@@ -2840,6 +2860,7 @@ exports.useQuerySingleton = useQuerySingleton;
2840
2860
  exports.useRenderInterpolation = useRenderInterpolation;
2841
2861
  exports.useSharedEntitySnapshot = useSharedEntitySnapshot;
2842
2862
  exports.useSharedEntityStore = useSharedEntityStore;
2863
+ exports.useSharedEntityStoreContext = useSharedEntityStoreContext;
2843
2864
  exports.useSwipeGesture = useSwipeGesture;
2844
2865
  exports.useTapReveal = useTapReveal;
2845
2866
  exports.useTraitListens = useTraitListens;
@@ -509,6 +509,22 @@ declare function createSharedEntityStore(): SharedEntityStore;
509
509
  * `useSharedEntitySnapshot`.
510
510
  */
511
511
  declare function useSharedEntityStore(): SharedEntityStore;
512
+ /**
513
+ * Cross-component access to ONE `SharedEntityStore` instance. `useSharedEntityStore`
514
+ * is `useRef`-scoped to its own call site — correct for a single owner (the JS
515
+ * runtime path's `useTraitStateMachine` interprets a whole orbital in one hook
516
+ * call), but the compiled path (`orbital-rust`'s TS-shell codegen) generates one
517
+ * hook + component PER TRAIT, so several independent trait hooks bound to the
518
+ * SAME `[shared]` entity need the SAME store instance. A page-level owner calls
519
+ * `useSharedEntityStore()` once and provides it here; every trait hook on that
520
+ * page reads it back via `useSharedEntityStoreContext()` instead of creating its
521
+ * own disconnected store. Not used by the JS runtime path today — purely
522
+ * additive, zero effect on `useSharedEntityStore`'s existing single-caller
523
+ * behavior.
524
+ */
525
+ declare const SharedEntityStoreContext: React$1.Context<SharedEntityStore | null>;
526
+ /** Read the page-level `SharedEntityStore` provided by `SharedEntityStoreContext`. */
527
+ declare function useSharedEntityStoreContext(): SharedEntityStore;
512
528
  /**
513
529
  * Bridge one entity's snapshot into React via `useSyncExternalStore` (the
514
530
  * codebase's established store->React bridge, see `lib/perf.ts`). The render
@@ -992,4 +1008,4 @@ declare function useGitHubBranches(owner: string, repo: string, enabled?: boolea
992
1008
  branches: string[];
993
1009
  }>, Error>;
994
1010
 
995
- export { ALMADAR_DND_MIME, type AuthContextValue, type AuthUser, type CanvasGestureCallbacks, type CanvasGestureHandlers, type CompileResult, type CompileStage, type DragReorderResult, type DraggablePayload, type Extension, type ExtensionManifest, type FileSystemFile, type FileSystemStatus, type GitHubRepo, type GitHubStatus, type HistoryChangeSummary, type HistoryTimelineItem, type I18nContextValue, I18nProvider, type InfiniteScrollOptions, type InfiniteScrollResult, type LongPressHandlers, type LongPressOptions, type OpenFile, type Positioned, type PullToRefreshOptions, type PullToRefreshResult, type QuerySingletonEntity, type QuerySingletonResult, type QuerySingletonState, type QueryState, type RenderInterpolationHandle, type RenderInterpolationOptions, type RevertResult, type SelectedFile, type SharedEntityStore, type SharedEntitySubscriber, type SharedEntityWriter, type SwipeGestureOptions, type SwipeGestureResult, type SwipeHandlers, type TapRevealOptions, type TapRevealResult, type TraitListenSpec, type TranslateFunction, type UseCanvasGesturesOptions, type UseCompileResult, type UseDraggableOptions, type UseDraggableResult, type UseDropZoneOptions, type UseDropZoneResult, type UseExtensionsOptions, type UseExtensionsResult, type UseFileEditorOptions, type UseFileEditorResult, type UseFileSystemResult, type UseOrbitalHistoryOptions, type UseOrbitalHistoryResult, createSharedEntityStore, createTranslate, parseQueryBinding, runTickFrame, useAgentChat, useAuthContext, useCanvasGestures, useCompile, useConnectGitHub, useDeepAgentGeneration, useDisconnectGitHub, useDragReorder, useDraggable, useDropZone, useEventBus, useExtensions, useFileEditor, useFileSystem, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useInfiniteScroll, useLongPress, useOrbitalHistory, usePreview, usePullToRefresh, useQuerySingleton, useRenderInterpolation, useSharedEntitySnapshot, useSharedEntityStore, useSwipeGesture, useTapReveal, useTraitListens, useTranslate, useUIEvents, useValidation };
1011
+ export { ALMADAR_DND_MIME, type AuthContextValue, type AuthUser, type CanvasGestureCallbacks, type CanvasGestureHandlers, type CompileResult, type CompileStage, type DragReorderResult, type DraggablePayload, type Extension, type ExtensionManifest, type FileSystemFile, type FileSystemStatus, type GitHubRepo, type GitHubStatus, type HistoryChangeSummary, type HistoryTimelineItem, type I18nContextValue, I18nProvider, type InfiniteScrollOptions, type InfiniteScrollResult, type LongPressHandlers, type LongPressOptions, type OpenFile, type Positioned, type PullToRefreshOptions, type PullToRefreshResult, type QuerySingletonEntity, type QuerySingletonResult, type QuerySingletonState, type QueryState, type RenderInterpolationHandle, type RenderInterpolationOptions, type RevertResult, type SelectedFile, type SharedEntityStore, SharedEntityStoreContext, type SharedEntitySubscriber, type SharedEntityWriter, type SwipeGestureOptions, type SwipeGestureResult, type SwipeHandlers, type TapRevealOptions, type TapRevealResult, type TraitListenSpec, type TranslateFunction, type UseCanvasGesturesOptions, type UseCompileResult, type UseDraggableOptions, type UseDraggableResult, type UseDropZoneOptions, type UseDropZoneResult, type UseExtensionsOptions, type UseExtensionsResult, type UseFileEditorOptions, type UseFileEditorResult, type UseFileSystemResult, type UseOrbitalHistoryOptions, type UseOrbitalHistoryResult, createSharedEntityStore, createTranslate, parseQueryBinding, runTickFrame, useAgentChat, useAuthContext, useCanvasGestures, useCompile, useConnectGitHub, useDeepAgentGeneration, useDisconnectGitHub, useDragReorder, useDraggable, useDropZone, useEventBus, useExtensions, useFileEditor, useFileSystem, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useInfiniteScroll, useLongPress, useOrbitalHistory, usePreview, usePullToRefresh, useQuerySingleton, useRenderInterpolation, useSharedEntitySnapshot, useSharedEntityStore, useSharedEntityStoreContext, useSwipeGesture, useTapReveal, useTraitListens, useTranslate, useUIEvents, useValidation };
@@ -509,6 +509,22 @@ declare function createSharedEntityStore(): SharedEntityStore;
509
509
  * `useSharedEntitySnapshot`.
510
510
  */
511
511
  declare function useSharedEntityStore(): SharedEntityStore;
512
+ /**
513
+ * Cross-component access to ONE `SharedEntityStore` instance. `useSharedEntityStore`
514
+ * is `useRef`-scoped to its own call site — correct for a single owner (the JS
515
+ * runtime path's `useTraitStateMachine` interprets a whole orbital in one hook
516
+ * call), but the compiled path (`orbital-rust`'s TS-shell codegen) generates one
517
+ * hook + component PER TRAIT, so several independent trait hooks bound to the
518
+ * SAME `[shared]` entity need the SAME store instance. A page-level owner calls
519
+ * `useSharedEntityStore()` once and provides it here; every trait hook on that
520
+ * page reads it back via `useSharedEntityStoreContext()` instead of creating its
521
+ * own disconnected store. Not used by the JS runtime path today — purely
522
+ * additive, zero effect on `useSharedEntityStore`'s existing single-caller
523
+ * behavior.
524
+ */
525
+ declare const SharedEntityStoreContext: React$1.Context<SharedEntityStore | null>;
526
+ /** Read the page-level `SharedEntityStore` provided by `SharedEntityStoreContext`. */
527
+ declare function useSharedEntityStoreContext(): SharedEntityStore;
512
528
  /**
513
529
  * Bridge one entity's snapshot into React via `useSyncExternalStore` (the
514
530
  * codebase's established store->React bridge, see `lib/perf.ts`). The render
@@ -992,4 +1008,4 @@ declare function useGitHubBranches(owner: string, repo: string, enabled?: boolea
992
1008
  branches: string[];
993
1009
  }>, Error>;
994
1010
 
995
- export { ALMADAR_DND_MIME, type AuthContextValue, type AuthUser, type CanvasGestureCallbacks, type CanvasGestureHandlers, type CompileResult, type CompileStage, type DragReorderResult, type DraggablePayload, type Extension, type ExtensionManifest, type FileSystemFile, type FileSystemStatus, type GitHubRepo, type GitHubStatus, type HistoryChangeSummary, type HistoryTimelineItem, type I18nContextValue, I18nProvider, type InfiniteScrollOptions, type InfiniteScrollResult, type LongPressHandlers, type LongPressOptions, type OpenFile, type Positioned, type PullToRefreshOptions, type PullToRefreshResult, type QuerySingletonEntity, type QuerySingletonResult, type QuerySingletonState, type QueryState, type RenderInterpolationHandle, type RenderInterpolationOptions, type RevertResult, type SelectedFile, type SharedEntityStore, type SharedEntitySubscriber, type SharedEntityWriter, type SwipeGestureOptions, type SwipeGestureResult, type SwipeHandlers, type TapRevealOptions, type TapRevealResult, type TraitListenSpec, type TranslateFunction, type UseCanvasGesturesOptions, type UseCompileResult, type UseDraggableOptions, type UseDraggableResult, type UseDropZoneOptions, type UseDropZoneResult, type UseExtensionsOptions, type UseExtensionsResult, type UseFileEditorOptions, type UseFileEditorResult, type UseFileSystemResult, type UseOrbitalHistoryOptions, type UseOrbitalHistoryResult, createSharedEntityStore, createTranslate, parseQueryBinding, runTickFrame, useAgentChat, useAuthContext, useCanvasGestures, useCompile, useConnectGitHub, useDeepAgentGeneration, useDisconnectGitHub, useDragReorder, useDraggable, useDropZone, useEventBus, useExtensions, useFileEditor, useFileSystem, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useInfiniteScroll, useLongPress, useOrbitalHistory, usePreview, usePullToRefresh, useQuerySingleton, useRenderInterpolation, useSharedEntitySnapshot, useSharedEntityStore, useSwipeGesture, useTapReveal, useTraitListens, useTranslate, useUIEvents, useValidation };
1011
+ export { ALMADAR_DND_MIME, type AuthContextValue, type AuthUser, type CanvasGestureCallbacks, type CanvasGestureHandlers, type CompileResult, type CompileStage, type DragReorderResult, type DraggablePayload, type Extension, type ExtensionManifest, type FileSystemFile, type FileSystemStatus, type GitHubRepo, type GitHubStatus, type HistoryChangeSummary, type HistoryTimelineItem, type I18nContextValue, I18nProvider, type InfiniteScrollOptions, type InfiniteScrollResult, type LongPressHandlers, type LongPressOptions, type OpenFile, type Positioned, type PullToRefreshOptions, type PullToRefreshResult, type QuerySingletonEntity, type QuerySingletonResult, type QuerySingletonState, type QueryState, type RenderInterpolationHandle, type RenderInterpolationOptions, type RevertResult, type SelectedFile, type SharedEntityStore, SharedEntityStoreContext, type SharedEntitySubscriber, type SharedEntityWriter, type SwipeGestureOptions, type SwipeGestureResult, type SwipeHandlers, type TapRevealOptions, type TapRevealResult, type TraitListenSpec, type TranslateFunction, type UseCanvasGesturesOptions, type UseCompileResult, type UseDraggableOptions, type UseDraggableResult, type UseDropZoneOptions, type UseDropZoneResult, type UseExtensionsOptions, type UseExtensionsResult, type UseFileEditorOptions, type UseFileEditorResult, type UseFileSystemResult, type UseOrbitalHistoryOptions, type UseOrbitalHistoryResult, createSharedEntityStore, createTranslate, parseQueryBinding, runTickFrame, useAgentChat, useAuthContext, useCanvasGestures, useCompile, useConnectGitHub, useDeepAgentGeneration, useDisconnectGitHub, useDragReorder, useDraggable, useDropZone, useEventBus, useExtensions, useFileEditor, useFileSystem, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useInfiniteScroll, useLongPress, useOrbitalHistory, usePreview, usePullToRefresh, useQuerySingleton, useRenderInterpolation, useSharedEntitySnapshot, useSharedEntityStore, useSharedEntityStoreContext, useSwipeGesture, useTapReveal, useTraitListens, useTranslate, useUIEvents, useValidation };
@@ -1,6 +1,6 @@
1
1
  import { createContext, useCallback, useState, useEffect, useMemo, useContext, useRef, useSyncExternalStore } from 'react';
2
2
  import { createLogger } from '@almadar/logger';
3
- import { EventBusContext, useTraitScope } from '@almadar/ui/providers';
3
+ import { EventBusContext, useTraitScopeChain } from '@almadar/ui/providers';
4
4
  import { mergeEntityFrame } from '@almadar/core';
5
5
  import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query';
6
6
 
@@ -950,9 +950,9 @@ var fallbackEventBus = {
950
950
  function useEventBus() {
951
951
  const context = useContext(EventBusContext);
952
952
  const baseBus = context ?? getGlobalEventBus() ?? fallbackEventBus;
953
- const scope = useTraitScope();
953
+ const chain = useTraitScopeChain();
954
954
  return useMemo(() => {
955
- if (!scope) {
955
+ if (chain.length === 0) {
956
956
  return {
957
957
  ...baseBus,
958
958
  emit: (type, payload, source) => {
@@ -968,22 +968,31 @@ function useEventBus() {
968
968
  emit: (type, payload, source) => {
969
969
  if (typeof type === "string" && type.startsWith("UI:")) {
970
970
  const tail = type.slice(3);
971
- const qualified = tail.includes(".") ? type : `UI:${scope.orbital}.${scope.trait}.${tail}`;
972
- if (qualified !== type) {
973
- scopeLog.info("emit:qualified", {
971
+ const isQualified = tail.includes(".");
972
+ const event = isQualified ? tail.split(".").slice(2).join(".") : tail;
973
+ if (!event) {
974
+ baseBus.emit(type, payload, source);
975
+ return;
976
+ }
977
+ const keys = /* @__PURE__ */ new Set();
978
+ if (isQualified) keys.add(type);
979
+ for (const sc of chain) {
980
+ keys.add(`UI:${sc.orbital}.${sc.trait}.${event}`);
981
+ }
982
+ if (keys.size > 1) {
983
+ scopeLog.info("emit:fan-out", {
974
984
  from: type,
975
- to: qualified,
976
- scopeOrbital: scope.orbital,
977
- scopeTrait: scope.trait
985
+ keys: Array.from(keys),
986
+ chainDepth: chain.length
978
987
  });
979
988
  }
980
- baseBus.emit(qualified, payload, source);
989
+ for (const key of keys) baseBus.emit(key, payload, source);
981
990
  return;
982
991
  }
983
992
  baseBus.emit(type, payload, source);
984
993
  }
985
994
  };
986
- }, [baseBus, scope]);
995
+ }, [baseBus, chain]);
987
996
  }
988
997
  function useEventListener(event, handler) {
989
998
  const eventBus = useEventBus();
@@ -1455,6 +1464,16 @@ function useSharedEntityStore() {
1455
1464
  }
1456
1465
  return storeRef.current;
1457
1466
  }
1467
+ var SharedEntityStoreContext = createContext(null);
1468
+ function useSharedEntityStoreContext() {
1469
+ const store = useContext(SharedEntityStoreContext);
1470
+ if (!store) {
1471
+ throw new Error(
1472
+ "useSharedEntityStoreContext: no SharedEntityStoreContext.Provider found in the component tree"
1473
+ );
1474
+ }
1475
+ return store;
1476
+ }
1458
1477
  function useSharedEntitySnapshot(store, entityId) {
1459
1478
  return useSyncExternalStore(
1460
1479
  (onStoreChange) => store.subscribe(entityId, onStoreChange),
@@ -2802,4 +2821,4 @@ function useGitHubBranches(owner, repo, enabled = true) {
2802
2821
  });
2803
2822
  }
2804
2823
 
2805
- export { ALMADAR_DND_MIME, DEFAULT_SLOTS, I18nProvider, createSharedEntityStore, createTranslate, parseQueryBinding, runTickFrame, useAgentChat, useAuthContext, useCanvasGestures, useCompile, useConnectGitHub, useDeepAgentGeneration, useDisconnectGitHub, useDragReorder, useDraggable, useDropZone, useEmitEvent, useEventBus, useEventListener, useExtensions, useFileEditor, useFileSystem, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useInfiniteScroll, useLongPress, useOrbitalHistory, usePreview, usePullToRefresh, useQuerySingleton, useRenderInterpolation, useSharedEntitySnapshot, useSharedEntityStore, useSwipeGesture, useTapReveal, useTraitListens, useTranslate, useUIEvents, useUISlotManager, useValidation };
2824
+ export { ALMADAR_DND_MIME, DEFAULT_SLOTS, I18nProvider, SharedEntityStoreContext, createSharedEntityStore, createTranslate, parseQueryBinding, runTickFrame, useAgentChat, useAuthContext, useCanvasGestures, useCompile, useConnectGitHub, useDeepAgentGeneration, useDisconnectGitHub, useDragReorder, useDraggable, useDropZone, useEmitEvent, useEventBus, useEventListener, useExtensions, useFileEditor, useFileSystem, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useInfiniteScroll, useLongPress, useOrbitalHistory, usePreview, usePullToRefresh, useQuerySingleton, useRenderInterpolation, useSharedEntitySnapshot, useSharedEntityStore, useSharedEntityStoreContext, useSwipeGesture, useTapReveal, useTraitListens, useTranslate, useUIEvents, useUISlotManager, useValidation };
@@ -119,9 +119,9 @@ var fallbackEventBus = {
119
119
  function useEventBus() {
120
120
  const context = React3.useContext(providers.EventBusContext);
121
121
  const baseBus = context ?? getGlobalEventBus() ?? fallbackEventBus;
122
- const scope = providers.useTraitScope();
122
+ const chain = providers.useTraitScopeChain();
123
123
  return React3.useMemo(() => {
124
- if (!scope) {
124
+ if (chain.length === 0) {
125
125
  return {
126
126
  ...baseBus,
127
127
  emit: (type, payload, source) => {
@@ -137,22 +137,31 @@ function useEventBus() {
137
137
  emit: (type, payload, source) => {
138
138
  if (typeof type === "string" && type.startsWith("UI:")) {
139
139
  const tail = type.slice(3);
140
- const qualified = tail.includes(".") ? type : `UI:${scope.orbital}.${scope.trait}.${tail}`;
141
- if (qualified !== type) {
142
- scopeLog.info("emit:qualified", {
140
+ const isQualified = tail.includes(".");
141
+ const event = isQualified ? tail.split(".").slice(2).join(".") : tail;
142
+ if (!event) {
143
+ baseBus.emit(type, payload, source);
144
+ return;
145
+ }
146
+ const keys = /* @__PURE__ */ new Set();
147
+ if (isQualified) keys.add(type);
148
+ for (const sc of chain) {
149
+ keys.add(`UI:${sc.orbital}.${sc.trait}.${event}`);
150
+ }
151
+ if (keys.size > 1) {
152
+ scopeLog.info("emit:fan-out", {
143
153
  from: type,
144
- to: qualified,
145
- scopeOrbital: scope.orbital,
146
- scopeTrait: scope.trait
154
+ keys: Array.from(keys),
155
+ chainDepth: chain.length
147
156
  });
148
157
  }
149
- baseBus.emit(qualified, payload, source);
158
+ for (const key of keys) baseBus.emit(key, payload, source);
150
159
  return;
151
160
  }
152
161
  baseBus.emit(type, payload, source);
153
162
  }
154
163
  };
155
- }, [baseBus, scope]);
164
+ }, [baseBus, chain]);
156
165
  }
157
166
  function useEmitEvent() {
158
167
  const eventBus = useEventBus();
@@ -1,5 +1,5 @@
1
1
  import React3, { forwardRef, useRef, useState, useEffect, useMemo, useImperativeHandle, useCallback, createContext, useContext, Component, useReducer } from 'react';
2
- import { EventBusContext, useTraitScope } from '@almadar/ui/providers';
2
+ import { EventBusContext, useTraitScopeChain } from '@almadar/ui/providers';
3
3
  import { createLogger } from '@almadar/logger';
4
4
  import { Canvas, useThree, useFrame } from '@react-three/fiber';
5
5
  import * as THREE9 from 'three';
@@ -95,9 +95,9 @@ var fallbackEventBus = {
95
95
  function useEventBus() {
96
96
  const context = useContext(EventBusContext);
97
97
  const baseBus = context ?? getGlobalEventBus() ?? fallbackEventBus;
98
- const scope = useTraitScope();
98
+ const chain = useTraitScopeChain();
99
99
  return useMemo(() => {
100
- if (!scope) {
100
+ if (chain.length === 0) {
101
101
  return {
102
102
  ...baseBus,
103
103
  emit: (type, payload, source) => {
@@ -113,22 +113,31 @@ function useEventBus() {
113
113
  emit: (type, payload, source) => {
114
114
  if (typeof type === "string" && type.startsWith("UI:")) {
115
115
  const tail = type.slice(3);
116
- const qualified = tail.includes(".") ? type : `UI:${scope.orbital}.${scope.trait}.${tail}`;
117
- if (qualified !== type) {
118
- scopeLog.info("emit:qualified", {
116
+ const isQualified = tail.includes(".");
117
+ const event = isQualified ? tail.split(".").slice(2).join(".") : tail;
118
+ if (!event) {
119
+ baseBus.emit(type, payload, source);
120
+ return;
121
+ }
122
+ const keys = /* @__PURE__ */ new Set();
123
+ if (isQualified) keys.add(type);
124
+ for (const sc of chain) {
125
+ keys.add(`UI:${sc.orbital}.${sc.trait}.${event}`);
126
+ }
127
+ if (keys.size > 1) {
128
+ scopeLog.info("emit:fan-out", {
119
129
  from: type,
120
- to: qualified,
121
- scopeOrbital: scope.orbital,
122
- scopeTrait: scope.trait
130
+ keys: Array.from(keys),
131
+ chainDepth: chain.length
123
132
  });
124
133
  }
125
- baseBus.emit(qualified, payload, source);
134
+ for (const key of keys) baseBus.emit(key, payload, source);
126
135
  return;
127
136
  }
128
137
  baseBus.emit(type, payload, source);
129
138
  }
130
139
  };
131
- }, [baseBus, scope]);
140
+ }, [baseBus, chain]);
132
141
  }
133
142
  function useEmitEvent() {
134
143
  const eventBus = useEventBus();
@@ -514,14 +514,29 @@ function recordTransition(trace) {
514
514
  "pass"
515
515
  );
516
516
  } else {
517
- const hasRenderUI = entry.effects.some((e) => e.type === "render-ui");
518
- if (hasRenderUI) {
519
- registerCheck(
520
- checkId,
521
- `INIT transition for "${entry.traitName}" missing fetch effect`,
522
- "fail",
523
- "Entity-bound render-ui without a fetch effect will show empty data"
517
+ const rendersEntityData = entry.effects.some(
518
+ (e) => e.type === "render-ui" && JSON.stringify(e.args).includes("@entity.")
519
+ );
520
+ if (rendersEntityData) {
521
+ const siblingSeeds = getState().transitions.some(
522
+ (t) => t.event === "INIT" && t.effects.some(
523
+ (e) => e.type === "fetch" || e.type === "set" && typeof e.args[0] === "string" && e.args[0].startsWith("@entity.")
524
+ )
524
525
  );
526
+ if (siblingSeeds) {
527
+ registerCheck(
528
+ checkId,
529
+ `INIT transition for "${entry.traitName}" has sibling entity-seed (shared entity)`,
530
+ "pass"
531
+ );
532
+ } else {
533
+ registerCheck(
534
+ checkId,
535
+ `INIT transition for "${entry.traitName}" missing fetch effect`,
536
+ "fail",
537
+ "Entity-bound render-ui without a fetch effect will show empty data"
538
+ );
539
+ }
525
540
  }
526
541
  }
527
542
  }
@@ -687,19 +702,32 @@ function bindEventBus(eventBus) {
687
702
  log2.debug("sendEvent", { event: prefixed, traitScope, payloadKeys: payload ? Object.keys(payload) : [] });
688
703
  eventBus.emit(prefixed, payload);
689
704
  };
705
+ const MAX_EVENT_LOG = 5e3;
690
706
  const eventLog = [];
707
+ let eventLogDropped = 0;
708
+ const bumpEpoch = () => {
709
+ window.__orbitalVerification.eventLogEpoch = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
710
+ };
691
711
  window.__orbitalVerification.eventLog = eventLog;
712
+ window.__orbitalVerification.eventLogDropped = 0;
713
+ bumpEpoch();
692
714
  window.__orbitalVerification.clearEventLog = () => {
693
715
  eventLog.length = 0;
716
+ eventLogDropped = 0;
717
+ window.__orbitalVerification.eventLogDropped = 0;
718
+ bumpEpoch();
694
719
  };
695
720
  if (eventBus.onAny) {
696
721
  const verificationRegistryEventLogger = (event) => {
697
- if (eventLog.length < 200) {
698
- eventLog.push({
699
- type: event.type,
700
- payload: event.payload,
701
- timestamp: Date.now()
702
- });
722
+ eventLog.push({
723
+ type: event.type,
724
+ payload: event.payload,
725
+ timestamp: Date.now()
726
+ });
727
+ if (eventLog.length > MAX_EVENT_LOG) {
728
+ eventLog.shift();
729
+ eventLogDropped += 1;
730
+ window.__orbitalVerification.eventLogDropped = eventLogDropped;
703
731
  }
704
732
  };
705
733
  Object.defineProperty(verificationRegistryEventLogger, "name", {
package/dist/lib/index.js CHANGED
@@ -512,14 +512,29 @@ function recordTransition(trace) {
512
512
  "pass"
513
513
  );
514
514
  } else {
515
- const hasRenderUI = entry.effects.some((e) => e.type === "render-ui");
516
- if (hasRenderUI) {
517
- registerCheck(
518
- checkId,
519
- `INIT transition for "${entry.traitName}" missing fetch effect`,
520
- "fail",
521
- "Entity-bound render-ui without a fetch effect will show empty data"
515
+ const rendersEntityData = entry.effects.some(
516
+ (e) => e.type === "render-ui" && JSON.stringify(e.args).includes("@entity.")
517
+ );
518
+ if (rendersEntityData) {
519
+ const siblingSeeds = getState().transitions.some(
520
+ (t) => t.event === "INIT" && t.effects.some(
521
+ (e) => e.type === "fetch" || e.type === "set" && typeof e.args[0] === "string" && e.args[0].startsWith("@entity.")
522
+ )
522
523
  );
524
+ if (siblingSeeds) {
525
+ registerCheck(
526
+ checkId,
527
+ `INIT transition for "${entry.traitName}" has sibling entity-seed (shared entity)`,
528
+ "pass"
529
+ );
530
+ } else {
531
+ registerCheck(
532
+ checkId,
533
+ `INIT transition for "${entry.traitName}" missing fetch effect`,
534
+ "fail",
535
+ "Entity-bound render-ui without a fetch effect will show empty data"
536
+ );
537
+ }
523
538
  }
524
539
  }
525
540
  }
@@ -685,19 +700,32 @@ function bindEventBus(eventBus) {
685
700
  log2.debug("sendEvent", { event: prefixed, traitScope, payloadKeys: payload ? Object.keys(payload) : [] });
686
701
  eventBus.emit(prefixed, payload);
687
702
  };
703
+ const MAX_EVENT_LOG = 5e3;
688
704
  const eventLog = [];
705
+ let eventLogDropped = 0;
706
+ const bumpEpoch = () => {
707
+ window.__orbitalVerification.eventLogEpoch = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
708
+ };
689
709
  window.__orbitalVerification.eventLog = eventLog;
710
+ window.__orbitalVerification.eventLogDropped = 0;
711
+ bumpEpoch();
690
712
  window.__orbitalVerification.clearEventLog = () => {
691
713
  eventLog.length = 0;
714
+ eventLogDropped = 0;
715
+ window.__orbitalVerification.eventLogDropped = 0;
716
+ bumpEpoch();
692
717
  };
693
718
  if (eventBus.onAny) {
694
719
  const verificationRegistryEventLogger = (event) => {
695
- if (eventLog.length < 200) {
696
- eventLog.push({
697
- type: event.type,
698
- payload: event.payload,
699
- timestamp: Date.now()
700
- });
720
+ eventLog.push({
721
+ type: event.type,
722
+ payload: event.payload,
723
+ timestamp: Date.now()
724
+ });
725
+ if (eventLog.length > MAX_EVENT_LOG) {
726
+ eventLog.shift();
727
+ eventLogDropped += 1;
728
+ window.__orbitalVerification.eventLogDropped = eventLogDropped;
701
729
  }
702
730
  };
703
731
  Object.defineProperty(verificationRegistryEventLogger, "name", {
@@ -2508,9 +2508,11 @@ function cn(...inputs) {
2508
2508
  logger.createLogger("almadar:eventbus");
2509
2509
  logger.createLogger("almadar:eventbus:subscribe");
2510
2510
  var EventBusContext = React12.createContext(null);
2511
+ var EMPTY_CHAIN = Object.freeze([]);
2511
2512
  var TraitScopeContext = React12.createContext(null);
2512
- function useTraitScope() {
2513
- return React12.useContext(TraitScopeContext);
2513
+ function useTraitScopeChain() {
2514
+ const chain = React12.useContext(TraitScopeContext);
2515
+ return chain ?? EMPTY_CHAIN;
2514
2516
  }
2515
2517
  var log = logger.createLogger("almadar:eventbus");
2516
2518
  var subLog2 = logger.createLogger("almadar:eventbus:subscribe");
@@ -2588,9 +2590,9 @@ var fallbackEventBus = {
2588
2590
  function useEventBus() {
2589
2591
  const context = React12.useContext(EventBusContext);
2590
2592
  const baseBus = context ?? getGlobalEventBus() ?? fallbackEventBus;
2591
- const scope = useTraitScope();
2593
+ const chain = useTraitScopeChain();
2592
2594
  return React12.useMemo(() => {
2593
- if (!scope) {
2595
+ if (chain.length === 0) {
2594
2596
  return {
2595
2597
  ...baseBus,
2596
2598
  emit: (type, payload, source) => {
@@ -2606,22 +2608,31 @@ function useEventBus() {
2606
2608
  emit: (type, payload, source) => {
2607
2609
  if (typeof type === "string" && type.startsWith("UI:")) {
2608
2610
  const tail = type.slice(3);
2609
- const qualified = tail.includes(".") ? type : `UI:${scope.orbital}.${scope.trait}.${tail}`;
2610
- if (qualified !== type) {
2611
- scopeLog.info("emit:qualified", {
2611
+ const isQualified = tail.includes(".");
2612
+ const event = isQualified ? tail.split(".").slice(2).join(".") : tail;
2613
+ if (!event) {
2614
+ baseBus.emit(type, payload, source);
2615
+ return;
2616
+ }
2617
+ const keys = /* @__PURE__ */ new Set();
2618
+ if (isQualified) keys.add(type);
2619
+ for (const sc of chain) {
2620
+ keys.add(`UI:${sc.orbital}.${sc.trait}.${event}`);
2621
+ }
2622
+ if (keys.size > 1) {
2623
+ scopeLog.info("emit:fan-out", {
2612
2624
  from: type,
2613
- to: qualified,
2614
- scopeOrbital: scope.orbital,
2615
- scopeTrait: scope.trait
2625
+ keys: Array.from(keys),
2626
+ chainDepth: chain.length
2616
2627
  });
2617
2628
  }
2618
- baseBus.emit(qualified, payload, source);
2629
+ for (const key of keys) baseBus.emit(key, payload, source);
2619
2630
  return;
2620
2631
  }
2621
2632
  baseBus.emit(type, payload, source);
2622
2633
  }
2623
2634
  };
2624
- }, [baseBus, scope]);
2635
+ }, [baseBus, chain]);
2625
2636
  }
2626
2637
  function useTapReveal(options = {}) {
2627
2638
  const { onReveal, onDismiss, refs, enabled = true } = options;
@@ -3218,13 +3229,13 @@ var Icon = ({
3218
3229
  style
3219
3230
  }) => {
3220
3231
  const directIcon = typeof icon === "string" ? void 0 : icon;
3221
- const effectiveName = typeof icon === "string" ? icon : name;
3232
+ const effectiveName = typeof icon === "string" && icon !== "" ? icon : name;
3233
+ const effectiveStrokeWidth = strokeWidth != null && strokeWidth > 0 ? strokeWidth : void 0;
3222
3234
  const family = useIconFamily();
3223
3235
  const RenderedComponent = React12__namespace.default.useMemo(() => {
3224
3236
  if (directIcon) return null;
3225
3237
  return effectiveName ? resolveIconForFamily(effectiveName) : null;
3226
3238
  }, [directIcon, effectiveName, family]);
3227
- const effectiveStrokeWidth = strokeWidth ?? void 0;
3228
3239
  const inlineStyle = {
3229
3240
  ...effectiveStrokeWidth === void 0 ? { strokeWidth: "var(--icon-stroke-width, 2)" } : {},
3230
3241
  ...style
@@ -5099,6 +5110,10 @@ var AnimatedCounter = ({
5099
5110
  setDisplayValue(String(value));
5100
5111
  return;
5101
5112
  }
5113
+ if (window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) {
5114
+ setDisplayValue(String(value));
5115
+ return;
5116
+ }
5102
5117
  const startTime = performance.now();
5103
5118
  const tick = (now) => {
5104
5119
  const elapsed = now - startTime;