@almadar/ui 2.11.6 → 2.11.9
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.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useTheme, useUISlots } from './chunk-DKQN5FVU.js';
|
|
2
|
+
import { cn, debugGroup, debug, debugGroupEnd, updateAssetStatus, bindCanvasCapture, getNestedValue, isDebugEnabled } from './chunk-WCTZ7WZX.js';
|
|
2
3
|
import { useTranslate, useInfiniteScroll, useQuerySingleton, useLongPress, useSwipeGesture, useDragReorder, usePullToRefresh } from './chunk-WGJIL4YR.js';
|
|
3
4
|
import { useEventBus } from './chunk-YXZM3WCF.js';
|
|
4
|
-
import { cn, debugGroup, debug, debugGroupEnd, updateAssetStatus, bindCanvasCapture, getNestedValue, isDebugEnabled } from './chunk-WCTZ7WZX.js';
|
|
5
5
|
import { isPortalSlot } from './chunk-K2D5D3WK.js';
|
|
6
6
|
import { __publicField } from './chunk-PKBMQBKP.js';
|
|
7
7
|
import * as LucideIcons from 'lucide-react';
|
|
@@ -9614,17 +9614,17 @@ function InventoryPanel({
|
|
|
9614
9614
|
onMouseEnter: (e) => handleMouseEnter(e, index),
|
|
9615
9615
|
onMouseLeave: handleMouseLeave,
|
|
9616
9616
|
tabIndex: 0,
|
|
9617
|
-
"aria-label": item ? `${item.name || item.type}, quantity: ${item.quantity}` : `Empty slot ${index + 1}`,
|
|
9617
|
+
"aria-label": item ? `${item.name || item.type || "Item"}, quantity: ${item.quantity}` : `Empty slot ${index + 1}`,
|
|
9618
9618
|
children: item && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
9619
9619
|
item.sprite ? /* @__PURE__ */ jsx(
|
|
9620
9620
|
"img",
|
|
9621
9621
|
{
|
|
9622
9622
|
src: item.sprite,
|
|
9623
|
-
alt: item.name || item.type,
|
|
9623
|
+
alt: item.name || item.type || "Item",
|
|
9624
9624
|
className: "w-8 h-8 object-contain",
|
|
9625
9625
|
style: { imageRendering: "pixelated" }
|
|
9626
9626
|
}
|
|
9627
|
-
) : /* @__PURE__ */ jsx("div", { className: "w-8 h-8 bg-gray-600 rounded flex items-center justify-center text-xs text-gray-300", children: item.type.charAt(0).toUpperCase() }),
|
|
9627
|
+
) : /* @__PURE__ */ jsx("div", { className: "w-8 h-8 bg-gray-600 rounded flex items-center justify-center text-xs text-gray-300", children: (item.type ?? item.name ?? "I").charAt(0).toUpperCase() }),
|
|
9628
9628
|
item.quantity > 1 && /* @__PURE__ */ jsx("span", { className: "absolute bottom-0 right-0 bg-black bg-opacity-70 text-white text-xs px-1 rounded-tl", children: item.quantity })
|
|
9629
9629
|
] })
|
|
9630
9630
|
},
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { SuspenseConfigProvider } from './chunk-
|
|
1
|
+
import { SuspenseConfigProvider } from './chunk-7FVLOH5L.js';
|
|
2
2
|
import { ThemeProvider } from './chunk-DKQN5FVU.js';
|
|
3
|
+
import { recordTransition, registerCheck, bindEventBus, bindTraitStateGetter } from './chunk-WCTZ7WZX.js';
|
|
3
4
|
import { SelectionProvider, EntityDataProvider } from './chunk-WGJIL4YR.js';
|
|
4
5
|
import { useEventBus, EventBusProvider } from './chunk-YXZM3WCF.js';
|
|
5
|
-
import { recordTransition, registerCheck, bindEventBus, bindTraitStateGetter } from './chunk-WCTZ7WZX.js';
|
|
6
6
|
import { useOfflineExecutor } from './chunk-K2D5D3WK.js';
|
|
7
7
|
import { createContext, useState, useCallback, useMemo, useContext, useRef, useEffect } from 'react';
|
|
8
8
|
import { jsx, Fragment } from 'react/jsx-runtime';
|
package/dist/components/index.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { DEFAULT_CONFIG, renderStateMachineToDomData, parseContentSegments, isDebugEnabled, onDebugToggle, subscribeToTickChanges, subscribeToGuardChanges, subscribeToDebugEvents, getEntitySnapshot, getDebugEvents, getGuardHistory, getAllTicks } from '../chunk-4ZBSL37D.js';
|
|
2
|
+
import { subscribeToTraitChanges, getAllTraits } from '../chunk-42YQ6JVR.js';
|
|
2
3
|
import { useAuthContext } from '../chunk-GTIAVPI5.js';
|
|
3
4
|
export { ENTITY_EVENTS, useAgentChat, useAuthContext, useCompile, useConnectGitHub, useCreateEntity, useDeepAgentGeneration, useDeleteEntity, useDisconnectGitHub, useEntities, useEntitiesByType, useEntity as useEntityById, useEntityMutations, useExtensions, useFileEditor, useFileSystem, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useInput, useOrbitalHistory, useOrbitalMutations, usePhysics, usePinchZoom, usePlayer, usePreview, useResolvedEntity, useSelectedEntity, useSendOrbitalEvent, useSingletonEntity, useUIEvents, useUpdateEntity, useValidation } from '../chunk-GTIAVPI5.js';
|
|
4
5
|
export { clearEntities, getAllEntities, getByType, getEntity, getSingleton, removeEntity, spawnEntity, updateEntity, updateSingleton } from '../chunk-N7MVUW4R.js';
|
|
5
|
-
import { subscribeToTraitChanges, getAllTraits } from '../chunk-42YQ6JVR.js';
|
|
6
6
|
import '../chunk-3HJHHULT.js';
|
|
7
|
-
import { VStack, HStack, Typography, Button, Icon, Box, Card, Avatar, Badge, SearchInput, Checkbox, Menu as Menu$1, Pagination, LoadingState, EmptyState, Modal, ErrorState, QuizBlock, CodeBlock, ScaledDiagram, MarkdownContent, Divider, ProgressBar, isoToScreen, IsometricCanvas_default, Stack, Select, Drawer, Toast, Tabs, Input, ThemeToggle, TILE_WIDTH, EntityDisplayEvents, StateIndicator, Accordion, ButtonGroup, Container } from '../chunk-
|
|
8
|
-
export { ALL_PRESETS, Accordion, ActionButton, ActionButtons, Card2 as ActionCard, Alert, AnimatedCounter, Avatar, Badge, Box, Breadcrumb, Button, ButtonGroup, CalendarGrid, CanvasEffect, Card, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, Center, Chart, ChartLegend, Checkbox, ChoiceButton, CodeBlock, CombatLog, ComboCounter, ConditionalWrapper, ConfettiEffect, Container, ControlButton, CraftingRecipe, DIAMOND_TOP_Y, DPad, DamageNumber, DataGrid, DataList, DataTable, DateRangeSelector, DayCell, DetailPanel, DialogueBox, DialogueBubble, Divider, Drawer, EmptyState, EnemyPlate, EntityDisplayEvents, ErrorBoundary, ErrorState, FEATURE_COLORS, FLOOR_HEIGHT, FilterGroup, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormField, FormSectionHeader, GameCanvas2D, GameHud, GameMenu, GameOverScreen, GraphView, Grid, HStack, Heading, HealthBar, HealthPanel, Icon, InfiniteScrollSentinel, Input, InputGroup, InventoryGrid, InventoryPanel, IsometricCanvas, ItemSlot, Label, LawReferenceTooltip, Lightbox, LineChart, LoadingState, MapView, MarkdownContent, MasterDetail, Menu, Meter, MiniMap, Modal, NumberStepper, Overlay, PageHeader, Pagination, PlatformerCanvas, Popover, PowerupSlots, ProgressBar, ProgressDots, PullToRefresh, QuestTracker, QuizBlock, Radio, RangeSlider, RelationSelect, RepeatableFormSection, ResourceBar, ResourceCounter, ScaledDiagram, ScoreBoard, ScoreDisplay, SearchInput, Select, SidePanel, SimpleGrid, SimulationCanvas, SimulationControls, SimulationGraph, Skeleton, SlotContentRenderer, SortableList, Spacer, Spinner, Sprite, Stack, StarRating, StatBadge, StatCard, StatDisplay, StateIndicator, StatusDot, StatusEffect, SwipeableRow, Switch, TILE_HEIGHT, TILE_WIDTH, Tabs, Text, TextHighlight, Textarea, ThemeSelector, ThemeToggle, TimeSlotCell, TimerDisplay, Toast, Tooltip, TrendIndicator, TurnIndicator, TurnPanel, TypewriterText, Typography, UISlotComponent, UISlotRenderer, UnitCommandBar, UploadDropZone, VStack, ViolationAlert, WaypointMarker, WizardNavigation, WizardProgress, XPBar, drawSprite, isoToScreen, pendulum, projectileMotion, screenToIso, springOscillator, useCamera, useImageCache } from '../chunk-
|
|
7
|
+
import { VStack, HStack, Typography, Button, Icon, Box, Card, Avatar, Badge, SearchInput, Checkbox, Menu as Menu$1, Pagination, LoadingState, EmptyState, Modal, ErrorState, QuizBlock, CodeBlock, ScaledDiagram, MarkdownContent, Divider, ProgressBar, isoToScreen, IsometricCanvas_default, Stack, Select, Drawer, Toast, Tabs, Input, ThemeToggle, TILE_WIDTH, EntityDisplayEvents, StateIndicator, Accordion, ButtonGroup, Container } from '../chunk-7FVLOH5L.js';
|
|
8
|
+
export { ALL_PRESETS, Accordion, ActionButton, ActionButtons, Card2 as ActionCard, Alert, AnimatedCounter, Avatar, Badge, Box, Breadcrumb, Button, ButtonGroup, CalendarGrid, CanvasEffect, Card, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, Center, Chart, ChartLegend, Checkbox, ChoiceButton, CodeBlock, CombatLog, ComboCounter, ConditionalWrapper, ConfettiEffect, Container, ControlButton, CraftingRecipe, DIAMOND_TOP_Y, DPad, DamageNumber, DataGrid, DataList, DataTable, DateRangeSelector, DayCell, DetailPanel, DialogueBox, DialogueBubble, Divider, Drawer, EmptyState, EnemyPlate, EntityDisplayEvents, ErrorBoundary, ErrorState, FEATURE_COLORS, FLOOR_HEIGHT, FilterGroup, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormField, FormSectionHeader, GameCanvas2D, GameHud, GameMenu, GameOverScreen, GraphView, Grid, HStack, Heading, HealthBar, HealthPanel, Icon, InfiniteScrollSentinel, Input, InputGroup, InventoryGrid, InventoryPanel, IsometricCanvas, ItemSlot, Label, LawReferenceTooltip, Lightbox, LineChart, LoadingState, MapView, MarkdownContent, MasterDetail, Menu, Meter, MiniMap, Modal, NumberStepper, Overlay, PageHeader, Pagination, PlatformerCanvas, Popover, PowerupSlots, ProgressBar, ProgressDots, PullToRefresh, QuestTracker, QuizBlock, Radio, RangeSlider, RelationSelect, RepeatableFormSection, ResourceBar, ResourceCounter, ScaledDiagram, ScoreBoard, ScoreDisplay, SearchInput, Select, SidePanel, SimpleGrid, SimulationCanvas, SimulationControls, SimulationGraph, Skeleton, SlotContentRenderer, SortableList, Spacer, Spinner, Sprite, Stack, StarRating, StatBadge, StatCard, StatDisplay, StateIndicator, StatusDot, StatusEffect, SwipeableRow, Switch, TILE_HEIGHT, TILE_WIDTH, Tabs, Text, TextHighlight, Textarea, ThemeSelector, ThemeToggle, TimeSlotCell, TimerDisplay, Toast, Tooltip, TrendIndicator, TurnIndicator, TurnPanel, TypewriterText, Typography, UISlotComponent, UISlotRenderer, UnitCommandBar, UploadDropZone, VStack, ViolationAlert, WaypointMarker, WizardNavigation, WizardProgress, XPBar, drawSprite, isoToScreen, pendulum, projectileMotion, screenToIso, springOscillator, useCamera, useImageCache } from '../chunk-7FVLOH5L.js';
|
|
9
9
|
import '../chunk-DKQN5FVU.js';
|
|
10
|
+
import { cn, getNestedValue, subscribeToVerification, getSummary, getBridgeHealth, getTransitions, getAllChecks } from '../chunk-WCTZ7WZX.js';
|
|
11
|
+
export { cn } from '../chunk-WCTZ7WZX.js';
|
|
10
12
|
import { useTranslate } from '../chunk-WGJIL4YR.js';
|
|
11
13
|
export { EntityDataProvider, I18nProvider, createTranslate, entityDataKeys, parseQueryBinding, useDragReorder, useEntity, useEntityDataAdapter, useEntityDetail, useEntityList, useEntityListSuspense, useEntitySuspense, useInfiniteScroll, useLongPress, usePullToRefresh, useQuerySingleton, useSwipeGesture, useTranslate } from '../chunk-WGJIL4YR.js';
|
|
12
14
|
import { useEventBus, useEventListener } from '../chunk-YXZM3WCF.js';
|
|
13
15
|
export { useEmitEvent, useEventBus, useEventListener } from '../chunk-YXZM3WCF.js';
|
|
14
16
|
export { DEFAULT_SLOTS, useUISlotManager } from '../chunk-3JGAROCW.js';
|
|
15
17
|
import '../chunk-TSETXL2E.js';
|
|
16
|
-
import { cn, getNestedValue, subscribeToVerification, getSummary, getBridgeHealth, getTransitions, getAllChecks } from '../chunk-WCTZ7WZX.js';
|
|
17
|
-
export { cn } from '../chunk-WCTZ7WZX.js';
|
|
18
18
|
import '../chunk-K2D5D3WK.js';
|
|
19
19
|
import { __publicField } from '../chunk-PKBMQBKP.js';
|
|
20
20
|
import * as React44 from 'react';
|
package/dist/providers/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export { FetchedDataContext, FetchedDataProvider, OfflineModeProvider, OrbitalProvider, VerificationProvider, useFetchedData, useFetchedDataContext, useFetchedEntity, useOfflineMode, useOptionalOfflineMode } from '../chunk-
|
|
2
|
-
import '../chunk-
|
|
1
|
+
export { FetchedDataContext, FetchedDataProvider, OfflineModeProvider, OrbitalProvider, VerificationProvider, useFetchedData, useFetchedDataContext, useFetchedEntity, useOfflineMode, useOptionalOfflineMode } from '../chunk-XWAVGJKL.js';
|
|
2
|
+
import '../chunk-7FVLOH5L.js';
|
|
3
3
|
import '../chunk-DKQN5FVU.js';
|
|
4
|
+
import '../chunk-WCTZ7WZX.js';
|
|
4
5
|
export { SelectionContext, SelectionProvider, useSelection, useSelectionOptional } from '../chunk-WGJIL4YR.js';
|
|
5
6
|
export { EventBusContext, EventBusProvider } from '../chunk-YXZM3WCF.js';
|
|
6
7
|
import '../chunk-3JGAROCW.js';
|
|
7
8
|
import '../chunk-TSETXL2E.js';
|
|
8
|
-
import '../chunk-WCTZ7WZX.js';
|
|
9
9
|
import '../chunk-K2D5D3WK.js';
|
|
10
10
|
import '../chunk-PKBMQBKP.js';
|
package/dist/runtime/index.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
+
import { registerTrait, unregisterTrait, updateTraitState } from '../chunk-42YQ6JVR.js';
|
|
1
2
|
import '../chunk-GTIAVPI5.js';
|
|
2
3
|
import '../chunk-N7MVUW4R.js';
|
|
3
|
-
import { registerTrait, unregisterTrait, updateTraitState } from '../chunk-42YQ6JVR.js';
|
|
4
4
|
import '../chunk-3HJHHULT.js';
|
|
5
|
-
import { useFetchedDataContext } from '../chunk-
|
|
6
|
-
import '../chunk-
|
|
5
|
+
import { useFetchedDataContext } from '../chunk-XWAVGJKL.js';
|
|
6
|
+
import '../chunk-7FVLOH5L.js';
|
|
7
7
|
import '../chunk-DKQN5FVU.js';
|
|
8
|
+
import { recordTransition } from '../chunk-WCTZ7WZX.js';
|
|
8
9
|
import '../chunk-WGJIL4YR.js';
|
|
9
10
|
import { useEventBus } from '../chunk-YXZM3WCF.js';
|
|
10
11
|
import '../chunk-3JGAROCW.js';
|
|
11
12
|
import '../chunk-TSETXL2E.js';
|
|
12
|
-
import { recordTransition } from '../chunk-WCTZ7WZX.js';
|
|
13
13
|
import '../chunk-K2D5D3WK.js';
|
|
14
14
|
import '../chunk-PKBMQBKP.js';
|
|
15
15
|
import { createContext, useMemo, useContext, useState, useRef, useEffect, useCallback } from 'react';
|
|
16
16
|
import { isCircuitEvent, schemaToIR, getPage, clearSchemaCache as clearSchemaCache$1 } from '@almadar/core';
|
|
17
|
-
import { StateMachineManager, EffectExecutor } from '@almadar/runtime';
|
|
17
|
+
import { StateMachineManager, createContextFromBindings, interpolateValue, EffectExecutor } from '@almadar/runtime';
|
|
18
18
|
import { isEntityAwarePattern } from '@almadar/patterns';
|
|
19
19
|
import { jsx } from 'react/jsx-runtime';
|
|
20
20
|
|
|
@@ -124,6 +124,14 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
|
|
|
124
124
|
useEffect(() => {
|
|
125
125
|
optionsRef.current = options;
|
|
126
126
|
}, [options]);
|
|
127
|
+
const traitStatesRef = useRef(traitStates);
|
|
128
|
+
const fetchedDataContextRef = useRef(fetchedDataContext);
|
|
129
|
+
useEffect(() => {
|
|
130
|
+
traitStatesRef.current = traitStates;
|
|
131
|
+
}, [traitStates]);
|
|
132
|
+
useEffect(() => {
|
|
133
|
+
fetchedDataContextRef.current = fetchedDataContext;
|
|
134
|
+
}, [fetchedDataContext]);
|
|
127
135
|
useEffect(() => {
|
|
128
136
|
const mgr = managerRef.current;
|
|
129
137
|
const bindings = traitBindingsRef.current;
|
|
@@ -166,6 +174,143 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
|
|
|
166
174
|
Array.from(newManager.getAllStates().keys()).join(", ")
|
|
167
175
|
);
|
|
168
176
|
}, [traitBindings]);
|
|
177
|
+
const runTickEffects = useCallback((tick, binding) => {
|
|
178
|
+
const fdc = fetchedDataContextRef.current;
|
|
179
|
+
const actions = slotsActionsRef.current;
|
|
180
|
+
const linkedEntity = binding.linkedEntity ?? "";
|
|
181
|
+
const currentState = traitStatesRef.current.get(binding.trait.name)?.currentState ?? "";
|
|
182
|
+
if (tick.appliesTo.length > 0 && !tick.appliesTo.includes(currentState)) return;
|
|
183
|
+
const records = linkedEntity && fdc ? fdc.getData(linkedEntity) : [];
|
|
184
|
+
const entityData = records.length > 0 ? Object.assign([...records], records[0]) : {};
|
|
185
|
+
const bindingCtx = { entity: entityData, payload: {}, state: currentState };
|
|
186
|
+
const evalCtx = createContextFromBindings(bindingCtx);
|
|
187
|
+
if (tick.guard !== void 0) {
|
|
188
|
+
const passed = interpolateValue(tick.guard, evalCtx);
|
|
189
|
+
if (!passed) return;
|
|
190
|
+
}
|
|
191
|
+
const entityMutations = /* @__PURE__ */ new Map();
|
|
192
|
+
const pendingSlots = /* @__PURE__ */ new Map();
|
|
193
|
+
const slotSource = {
|
|
194
|
+
trait: binding.trait.name,
|
|
195
|
+
state: currentState,
|
|
196
|
+
transition: `${currentState}->tick:${tick.name}`,
|
|
197
|
+
effects: tick.effects,
|
|
198
|
+
traitDefinition: binding.trait
|
|
199
|
+
};
|
|
200
|
+
const enrichTickNode = (node) => {
|
|
201
|
+
if (!node || typeof node !== "object") return node;
|
|
202
|
+
const rec = node;
|
|
203
|
+
const nodeType = rec.type;
|
|
204
|
+
let enriched = rec;
|
|
205
|
+
if (Array.isArray(rec.children)) {
|
|
206
|
+
enriched = { ...rec, children: rec.children.map(enrichTickNode) };
|
|
207
|
+
}
|
|
208
|
+
if (nodeType && isEntityAwarePattern(nodeType) && fdc) {
|
|
209
|
+
let injected = false;
|
|
210
|
+
if (typeof enriched.entity === "string") {
|
|
211
|
+
const entityRecords = fdc.getData(enriched.entity);
|
|
212
|
+
if (entityRecords.length > 0) {
|
|
213
|
+
enriched = { ...enriched, entity: entityRecords };
|
|
214
|
+
injected = true;
|
|
215
|
+
}
|
|
216
|
+
} else if (!enriched.entity && linkedEntity) {
|
|
217
|
+
const entityRecords = fdc.getData(linkedEntity);
|
|
218
|
+
if (entityRecords.length > 0) {
|
|
219
|
+
enriched = { ...enriched, entity: entityRecords };
|
|
220
|
+
injected = true;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if (injected && !enriched.fields && !enriched.columns) {
|
|
224
|
+
const sample = enriched.entity[0];
|
|
225
|
+
if (sample && typeof sample === "object") {
|
|
226
|
+
const keys = Object.keys(sample).filter((k) => k !== "id" && k !== "_id");
|
|
227
|
+
enriched = { ...enriched, fields: keys.map((k, i) => ({ name: k, variant: i === 0 ? "h4" : "body" })), children: void 0 };
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return enriched;
|
|
232
|
+
};
|
|
233
|
+
for (const effect of tick.effects) {
|
|
234
|
+
if (!Array.isArray(effect)) continue;
|
|
235
|
+
const op = effect[0];
|
|
236
|
+
if (op === "set") {
|
|
237
|
+
const path = effect[1];
|
|
238
|
+
if (typeof path !== "string" || !path.startsWith("@entity.")) continue;
|
|
239
|
+
const field = path.slice("@entity.".length);
|
|
240
|
+
const updatedCtx = createContextFromBindings(bindingCtx);
|
|
241
|
+
const value = interpolateValue(effect[2], updatedCtx);
|
|
242
|
+
bindingCtx.entity[field] = value;
|
|
243
|
+
entityMutations.set(field, value);
|
|
244
|
+
} else if (op === "render-ui" || op === "render") {
|
|
245
|
+
const slot = effect[1];
|
|
246
|
+
const rawPattern = effect[2];
|
|
247
|
+
if (rawPattern === null || rawPattern === void 0) {
|
|
248
|
+
pendingSlots.set(slot, []);
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
const updatedCtx = createContextFromBindings(bindingCtx);
|
|
252
|
+
const resolved = interpolateValue(rawPattern, updatedCtx);
|
|
253
|
+
const enriched = enrichTickNode(resolved);
|
|
254
|
+
const existing = pendingSlots.get(slot) ?? [];
|
|
255
|
+
existing.push({ pattern: enriched, props: {} });
|
|
256
|
+
pendingSlots.set(slot, existing);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
for (const [slot, patterns] of pendingSlots) {
|
|
260
|
+
if (patterns.length === 0) {
|
|
261
|
+
actions.clearSlot(slot);
|
|
262
|
+
} else {
|
|
263
|
+
actions.setSlotPatterns(slot, patterns, slotSource);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
if (linkedEntity && entityMutations.size > 0 && fdc) {
|
|
267
|
+
const latestRecords = fdc.getData(linkedEntity);
|
|
268
|
+
if (latestRecords.length > 0) {
|
|
269
|
+
const updated = latestRecords.map(
|
|
270
|
+
(r, i) => i === 0 ? { ...r, ...Object.fromEntries(entityMutations) } : r
|
|
271
|
+
);
|
|
272
|
+
fdc.setData({ [linkedEntity]: updated });
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}, []);
|
|
276
|
+
useEffect(() => {
|
|
277
|
+
const hasFrameTicks = traitBindingsRef.current.some(
|
|
278
|
+
(b) => b.trait.ticks?.some((t) => t.interval === "frame")
|
|
279
|
+
);
|
|
280
|
+
if (!hasFrameTicks) return;
|
|
281
|
+
let running = true;
|
|
282
|
+
let rafId = 0;
|
|
283
|
+
const frame = () => {
|
|
284
|
+
if (!running) return;
|
|
285
|
+
for (const binding of traitBindingsRef.current) {
|
|
286
|
+
for (const tick of binding.trait.ticks ?? []) {
|
|
287
|
+
if (tick.interval !== "frame") continue;
|
|
288
|
+
runTickEffects(tick, binding);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
rafId = requestAnimationFrame(frame);
|
|
292
|
+
};
|
|
293
|
+
rafId = requestAnimationFrame(frame);
|
|
294
|
+
return () => {
|
|
295
|
+
running = false;
|
|
296
|
+
cancelAnimationFrame(rafId);
|
|
297
|
+
};
|
|
298
|
+
}, [traitBindings, runTickEffects]);
|
|
299
|
+
useEffect(() => {
|
|
300
|
+
const intervals = [];
|
|
301
|
+
for (const binding of traitBindings) {
|
|
302
|
+
for (const tick of binding.trait.ticks ?? []) {
|
|
303
|
+
if (tick.interval === "frame") continue;
|
|
304
|
+
const ms = tick.interval;
|
|
305
|
+
intervals.push(setInterval(() => {
|
|
306
|
+
runTickEffects(tick, binding);
|
|
307
|
+
}, ms));
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return () => {
|
|
311
|
+
for (const id of intervals) clearInterval(id);
|
|
312
|
+
};
|
|
313
|
+
}, [traitBindings, runTickEffects]);
|
|
169
314
|
const processEvent = useCallback((eventKey, payload) => {
|
|
170
315
|
const normalizedEvent = normalizeEventKey(eventKey);
|
|
171
316
|
const bindings = traitBindingsRef.current;
|
|
@@ -277,6 +422,19 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
|
|
|
277
422
|
payload: payload || {},
|
|
278
423
|
state: result.previousState
|
|
279
424
|
};
|
|
425
|
+
const entityMutations = /* @__PURE__ */ new Map();
|
|
426
|
+
for (const effect of result.effects) {
|
|
427
|
+
if (!Array.isArray(effect) || effect[0] !== "set") continue;
|
|
428
|
+
const path = effect[1];
|
|
429
|
+
if (typeof path !== "string" || !path.startsWith("@entity.")) continue;
|
|
430
|
+
const field = path.slice("@entity.".length);
|
|
431
|
+
const evalCtx = createContextFromBindings(bindingCtx);
|
|
432
|
+
const value = interpolateValue(effect[2], evalCtx);
|
|
433
|
+
if (bindingCtx.entity !== null && typeof bindingCtx.entity === "object") {
|
|
434
|
+
bindingCtx.entity[field] = value;
|
|
435
|
+
}
|
|
436
|
+
entityMutations.set(field, value);
|
|
437
|
+
}
|
|
280
438
|
const effectContext = {
|
|
281
439
|
traitName: binding.trait.name,
|
|
282
440
|
state: result.previousState,
|
|
@@ -297,6 +455,15 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
|
|
|
297
455
|
actions.setSlotPatterns(slot, patterns, slotSource);
|
|
298
456
|
}
|
|
299
457
|
}
|
|
458
|
+
if (linkedEntity && entityMutations.size > 0 && fetchedDataContext) {
|
|
459
|
+
const records = fetchedDataContext.getData(linkedEntity);
|
|
460
|
+
if (records.length > 0) {
|
|
461
|
+
const updated = records.map(
|
|
462
|
+
(r, i) => i === 0 ? { ...r, ...Object.fromEntries(entityMutations) } : r
|
|
463
|
+
);
|
|
464
|
+
fetchedDataContext.setData({ [linkedEntity]: updated });
|
|
465
|
+
}
|
|
466
|
+
}
|
|
300
467
|
}).catch((error) => {
|
|
301
468
|
console.error(
|
|
302
469
|
"[TraitStateMachine] Effect execution error:",
|