vehicle-path2 1.0.2 → 1.0.3

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.
@@ -6,6 +6,8 @@ export interface UseAnimationProps {
6
6
  vehicles: Vehicle[];
7
7
  lines: Line[];
8
8
  vehicleQueues: Map<string, GotoCommand[]>;
9
+ /** Get current queues immediately (bypasses React state timing) */
10
+ getVehicleQueues?: () => Map<string, GotoCommand[]>;
9
11
  wheelbase: number;
10
12
  tangentMode: TangentMode;
11
13
  curves: import('../../core/types/geometry').Curve[];
@@ -32,7 +34,7 @@ export interface UseAnimationProps {
32
34
  * }
33
35
  * ```
34
36
  */
35
- export declare function useAnimation({ vehicles, lines, vehicleQueues, wheelbase, tangentMode, curves, eventEmitter }: UseAnimationProps): {
37
+ export declare function useAnimation({ vehicles, lines, vehicleQueues, getVehicleQueues, wheelbase, tangentMode, curves, eventEmitter }: UseAnimationProps): {
36
38
  movingVehicles: Vehicle[];
37
39
  prepare: () => boolean;
38
40
  tick: (distance: number) => boolean;
@@ -9,6 +9,8 @@ export interface UseMovementQueueProps {
9
9
  export interface UseMovementQueueResult {
10
10
  /** Queue of commands per vehicle */
11
11
  vehicleQueues: Map<string, GotoCommand[]>;
12
+ /** Get current queues immediately (bypasses React state timing) */
13
+ getVehicleQueues: () => Map<string, GotoCommand[]>;
12
14
  /** Queue a movement command for a vehicle */
13
15
  queueMovement: (vehicleId: string, input: GotoCommandInput) => {
14
16
  success: boolean;
package/dist/react.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./useVehicleEvents-KZUx27Uj.cjs");exports.VehicleEventContext=e.VehicleEventContext;exports.VehicleEventProvider=e.VehicleEventProvider;exports.useAnimation=e.useAnimation;exports.useCreateVehicleEventEmitter=e.useCreateVehicleEventEmitter;exports.useInitialMovement=e.useInitialMovement;exports.useMovement=e.useMovementQueue;exports.useMovementQueue=e.useMovementQueue;exports.useMovementSequence=e.useMovementSequence;exports.useScene=e.useScene;exports.useSceneDefinition=e.useSceneDefinition;exports.useVehicleEvent=e.useVehicleEvent;exports.useVehicleEventEmitter=e.useVehicleEventEmitter;exports.useVehicleMovement=e.useAnimation;exports.useVehicleSimulation=e.useVehicleSimulation;exports.useVehicles=e.useVehicles;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./useVehicleEvents-GQ7zeGg6.cjs");exports.VehicleEventContext=e.VehicleEventContext;exports.VehicleEventProvider=e.VehicleEventProvider;exports.useAnimation=e.useAnimation;exports.useCreateVehicleEventEmitter=e.useCreateVehicleEventEmitter;exports.useInitialMovement=e.useInitialMovement;exports.useMovement=e.useMovementQueue;exports.useMovementQueue=e.useMovementQueue;exports.useMovementSequence=e.useMovementSequence;exports.useScene=e.useScene;exports.useSceneDefinition=e.useSceneDefinition;exports.useVehicleEvent=e.useVehicleEvent;exports.useVehicleEventEmitter=e.useVehicleEventEmitter;exports.useVehicleMovement=e.useAnimation;exports.useVehicleSimulation=e.useVehicleSimulation;exports.useVehicles=e.useVehicles;
package/dist/react.js CHANGED
@@ -1,4 +1,4 @@
1
- import { V as t, a as i, u as a, b as n, c as u, d as c, d as o, e as v, f as l, g as m, h, i as V, u as r, j as E, k as M } from "./useVehicleEvents-DaLwTAZI.js";
1
+ import { V as t, a as i, u as a, b as n, c as u, d as c, d as o, e as v, f as l, g as m, h, i as V, u as r, j as E, k as M } from "./useVehicleEvents-Lf_yySwI.js";
2
2
  export {
3
3
  t as VehicleEventContext,
4
4
  i as VehicleEventProvider,
@@ -0,0 +1,3 @@
1
+ "use strict";const n=require("react"),Q=require("./core.cjs"),T=require("./vehicle-helpers-82D2V4MI.cjs"),te=require("react/jsx-runtime");function F(s){return Array.isArray(s)?{x:s[0],y:s[1]}:s}function z(s){return{id:s.id,start:F(s.start),end:F(s.end)}}function j(s){const a=s.fromIsPercentage!==!1,I=s.toIsPercentage!==!1;return{fromLineId:s.from,toLineId:s.to,fromOffset:s.fromPosition,fromIsPercentage:s.fromPosition!==void 0?a:void 0,toOffset:s.toPosition,toIsPercentage:s.toPosition!==void 0?I:void 0}}function N(s){const a=s.position??0,I=s.isPercentage!==!1;return{vehicleId:s.id,lineId:s.lineId,offset:a,isPercentage:I}}function H(s){const a=s.isPercentage!==!1,I=s.targetPosition??1;return{vehicleId:s.vehicleId,targetLineId:s.targetLineId,targetOffset:I,isPercentage:a,awaitConfirmation:s.wait,payload:s.payload}}function se(s){const a=[],I=new Set;for(const r of s.lines)I.has(r.id)&&a.push(`Duplicate line ID: ${r.id}`),I.add(r.id);if(s.connections)for(const r of s.connections){I.has(r.from)||a.push(`Connection references non-existent line: ${r.from}`),I.has(r.to)||a.push(`Connection references non-existent line: ${r.to}`);const d=r.fromIsPercentage!==!1,t=r.toIsPercentage!==!1;!d&&r.fromPosition===void 0&&a.push("fromPosition is required when fromIsPercentage is false"),!t&&r.toPosition===void 0&&a.push("toPosition is required when toIsPercentage is false"),r.fromPosition!==void 0&&(d&&(r.fromPosition<0||r.fromPosition>1)?a.push(`Invalid fromPosition: ${r.fromPosition} (must be 0-1 for percentage)`):!d&&r.fromPosition<0&&a.push(`Invalid fromPosition: ${r.fromPosition} (must be >= 0 for absolute distance)`)),r.toPosition!==void 0&&(t&&(r.toPosition<0||r.toPosition>1)?a.push(`Invalid toPosition: ${r.toPosition} (must be 0-1 for percentage)`):!t&&r.toPosition<0&&a.push(`Invalid toPosition: ${r.toPosition} (must be >= 0 for absolute distance)`))}return{valid:a.length===0,errors:a}}function J(){const[s,a]=n.useState([]),[I,r]=n.useState([]),[d,t]=n.useState(null),m=n.useCallback((o,v)=>{a(o),r(v),t(null)},[]),C=n.useCallback(o=>{const v=se(o);if(!v.valid)return t(v.errors.join("; ")),{success:!1,errors:v.errors};const g=o.lines.map(z),h=o.connections?.map(j)||[];return m(g,h),{success:!0}},[m]),D=n.useCallback(o=>{if(s.some(g=>g.id===o.id)){const g=`Line with ID '${o.id}' already exists`;return t(g),{success:!1,error:g}}return a(g=>[...g,z(o)]),t(null),{success:!0}},[s]),k=n.useCallback((o,v)=>{if(s.findIndex(h=>h.id===o)===-1){const h=`Line with ID '${o}' not found`;return t(h),{success:!1,error:h}}return a(h=>h.map(S=>S.id!==o?S:{...S,start:v.start?F(v.start):S.start,end:v.end?F(v.end):S.end})),t(null),{success:!0}},[s]),E=n.useCallback(o=>{if(!s.some(g=>g.id===o)){const g=`Line with ID '${o}' not found`;return t(g),{success:!1,error:g}}return a(g=>g.filter(h=>h.id!==o)),r(g=>g.filter(h=>h.fromLineId!==o&&h.toLineId!==o)),t(null),{success:!0}},[s]),x=n.useCallback(o=>{const v=s.some(c=>c.id===o.from),g=s.some(c=>c.id===o.to);if(!v){const c=`Line '${o.from}' not found`;return t(c),{success:!1,error:c}}if(!g){const c=`Line '${o.to}' not found`;return t(c),{success:!1,error:c}}const h=o.fromIsPercentage!==!1,S=o.toIsPercentage!==!1;if(!h&&o.fromPosition===void 0){const c="fromPosition is required when fromIsPercentage is false";return t(c),{success:!1,error:c}}if(!S&&o.toPosition===void 0){const c="toPosition is required when toIsPercentage is false";return t(c),{success:!1,error:c}}if(I.some(c=>c.fromLineId===o.from&&c.toLineId===o.to)){const c=`Connection from '${o.from}' to '${o.to}' already exists`;return t(c),{success:!1,error:c}}return r(c=>[...c,j(o)]),t(null),{success:!0}},[s,I]),l=n.useCallback((o,v,g)=>{const h=I.findIndex(e=>e.fromLineId===o&&e.toLineId===v);if(h===-1){const e=`Connection from '${o}' to '${v}' not found`;return t(e),{success:!1,error:e}}const S=I[h],q=g.fromIsPercentage??S.fromIsPercentage,c=g.toIsPercentage??S.toIsPercentage;let M;g.fromOffset!==void 0?M=g.fromOffset:S.fromOffset!==void 0&&(M=S.fromOffset);let P;if(g.toOffset!==void 0?P=g.toOffset:S.toOffset!==void 0&&(P=S.toOffset),M!==void 0){if(q!==!1&&(M<0||M>1)){const e=`Invalid fromOffset: ${M} (must be 0-1 for percentage)`;return t(e),{success:!1,error:e}}if(q===!1&&M<0){const e=`Invalid fromOffset: ${M} (must be >= 0 for absolute distance)`;return t(e),{success:!1,error:e}}}if(P!==void 0){if(c!==!1&&(P<0||P>1)){const e=`Invalid toOffset: ${P} (must be 0-1 for percentage)`;return t(e),{success:!1,error:e}}if(c===!1&&P<0){const e=`Invalid toOffset: ${P} (must be >= 0 for absolute distance)`;return t(e),{success:!1,error:e}}}if(q===!1&&M===void 0){const e="fromOffset is required when fromIsPercentage is false";return t(e),{success:!1,error:e}}if(c===!1&&P===void 0){const e="toOffset is required when toIsPercentage is false";return t(e),{success:!1,error:e}}const w={from:o,to:v,fromPosition:M,fromIsPercentage:q,toPosition:P,toIsPercentage:c};return r(e=>e.map((i,u)=>u===h?j(w):i)),t(null),{success:!0}},[I]),p=n.useCallback((o,v)=>{if(!I.some(h=>h.fromLineId===o&&h.toLineId===v)){const h=`Connection from '${o}' to '${v}' not found`;return t(h),{success:!1,error:h}}return r(h=>h.filter(S=>!(S.fromLineId===o&&S.toLineId===v))),t(null),{success:!0}},[I]),f=n.useCallback(()=>{a([]),r([]),t(null)},[]);return{lines:s,curves:I,setScene:C,addLine:D,updateLine:k,removeLine:E,addConnection:x,updateConnection:l,removeConnection:p,clear:f,error:d,_loadScene:m}}function B({lines:s,wheelbase:a}){const[I,r]=n.useState([]),[d,t]=n.useState(null),m=n.useRef([]),C=n.useCallback(l=>{m.current=l,r(l),t(null)},[]),D=n.useCallback(l=>{const p=Array.isArray(l)?l:[l],f=[];for(const h of p)m.current.some(q=>q.id===h.id)&&f.push(`Vehicle with ID '${h.id}' already exists`);if(f.length>0)return t(f.join("; ")),{success:!1,errors:f};const o=p.map(N),{vehicles:v,errors:g}=T.validateAndCreateVehicles(o,s,a);return g.length>0?(t(g.join("; ")),{success:!1,errors:g}):(m.current=[...m.current,...v],r(m.current),t(null),{success:!0})},[s,a]),k=n.useCallback((l,p)=>{const f=m.current.findIndex(P=>P.id===l);if(f===-1){const P=`Vehicle with ID '${l}' not found`;return t(P),{success:!1,error:P}}const o=m.current[f];if(o.state!=="idle"){const P=`Cannot update vehicle '${l}' while it is ${o.state}. Vehicle must be idle.`;return t(P),{success:!1,error:P}}const v=p.lineId??o.lineId;if(!s.find(P=>P.id===v)){const P=`Line '${v}' not found`;return t(P),{success:!1,error:P}}let h,S;p.lineId!==void 0&&p.position===void 0?(h=0,S=!0):p.position!==void 0?(h=p.position,S=p.isPercentage??!0):(h=o.offset,S=o.isPercentage);const q={vehicleId:l,lineId:v,offset:h,isPercentage:S},{vehicles:c,errors:M}=T.validateAndCreateVehicles([q],s,a);return M.length>0?(t(M.join("; ")),{success:!1,error:M.join("; ")}):(m.current=m.current.map((P,w)=>w===f?c[0]:P),r(m.current),t(null),{success:!0})},[s,a]),E=n.useCallback(l=>{if(!m.current.some(f=>f.id===l)){const f=`Vehicle with ID '${l}' not found`;return t(f),{success:!1,error:f}}return m.current=m.current.filter(f=>f.id!==l),r(m.current),t(null),{success:!0}},[]),x=n.useCallback(()=>{m.current=[],r([]),t(null)},[]);return{vehicles:I,addVehicles:D,updateVehicle:k,removeVehicle:E,clear:x,error:d,_loadVehicles:C}}function W({vehicles:s,lines:a}){const[I,r]=n.useState(new Map),[d,t]=n.useState(null),m=n.useRef(new Map),C=n.useCallback(()=>m.current,[]),D=n.useCallback(x=>{m.current=x,r(x),t(null)},[]),k=n.useCallback((x,l)=>{if(!s.some(c=>c.id===x)){const c=`Vehicle '${x}' not found`;return t(c),{success:!1,error:c}}const f=a.find(c=>c.id===l.targetLineId);if(!f){const c=`Line '${l.targetLineId}' not found`;return t(c),{success:!1,error:c}}const o=l.isPercentage!==!1,v=Q.distance(f.start,f.end);if(!o&&l.targetPosition===void 0){const c="targetPosition is required when isPercentage is false";return t(c),{success:!1,error:c}}const g=l.targetPosition??1;if(o){if(g<0||g>1){const c=`Invalid targetPosition: ${g} (must be 0-1 for percentage)`;return t(c),{success:!1,error:c}}}else{if(g<0){const c=`Invalid targetPosition: ${g} (must be >= 0 for absolute distance)`;return t(c),{success:!1,error:c}}if(g>v){const c=`Position ${g} exceeds line length ${v}`;return t(c),{success:!1,error:c}}}const h=H({vehicleId:x,...l}),S=new Map(m.current),q=S.get(x)||[];return S.set(x,[...q,h]),m.current=S,r(S),t(null),{success:!0}},[s,a]),E=n.useCallback(x=>{if(x!==void 0){if(!s.some(f=>f.id===x)){const f=`Vehicle '${x}' not found`;return t(f),{success:!1,error:f}}const p=new Map(m.current);p.delete(x),m.current=p,r(p)}else m.current=new Map,r(new Map);return t(null),{success:!0}},[s]);return{vehicleQueues:I,getVehicleQueues:C,queueMovement:k,clearQueue:E,error:d,_loadQueues:D}}function Z({vehicles:s,lines:a,vehicleQueues:I,getVehicleQueues:r,wheelbase:d,tangentMode:t,curves:m,eventEmitter:C}){const[D,k]=n.useState([]),E=n.useMemo(()=>({wheelbase:d,tangentMode:t}),[d,t]),x=n.useMemo(()=>new Map(a.map(c=>[c.id,c])),[a]),l=n.useRef(new Map);n.useEffect(()=>{const{movingVehicles:c,stateMap:M}=Q.initializeAllVehicles(s,x);l.current=M;const P=setTimeout(()=>{k(c)},0);return()=>clearTimeout(P)},[s,x]);const p=n.useRef(null);n.useEffect(()=>{a.length>0&&(p.current=Q.buildGraph(a,m,E))},[a,m,E]);const f=n.useRef(0),o=n.useRef(!1),v=n.useCallback(c=>{if(!o.current)return!1;let M=!1;for(const[,w]of l.current)if(w.vehicle.state==="moving"){M=!0;break}if(!M)return!1;const P=[];for(const[w,e]of l.current){if(e.vehicle.state!=="moving"||!e.execution)continue;const i=e.execution;let u;if(i.front.currentSegmentIndex<i.path.segments.length){const L=i.path.segments[i.front.currentSegmentIndex];if(L.type==="line"){const V=x.get(L.lineId);V&&(u=Math.sqrt(Math.pow(V.end.x-V.start.x,2)+Math.pow(V.end.y-V.start.y,2)))}}const b=Q.updateAxlePosition(e.vehicle.rear,i.rear,i.path,c,x,i.curveDataMap),$=Q.updateAxlePosition(e.vehicle.front,i.front,i.path,c,x,i.curveDataMap,u);if(e.vehicle={...e.vehicle,rear:b.axleState,front:$.axleState},e.execution.rear=b.execution,e.execution.front=$.execution,b.completed){const L={linesMap:x,config:E,vehicleQueues:I,curves:m,graphRef:p,prepareCommandPath:Q.prepareCommandPath,onCommandComplete:O=>P.push({type:"commandComplete",data:O}),onCommandStart:O=>P.push({type:"commandStart",data:O})},V=Q.handleArrival(e,L);e.vehicle=V.vehicle,V.newExecution!==void 0&&(e.execution=V.newExecution),V.vehicle.state!=="moving"&&P.push({type:"stateChange",data:{vehicleId:w,from:"moving",to:V.vehicle.state}});const y=V.vehicle.rear.position,A=V.vehicle.front.position;P.push({type:"positionUpdate",data:{vehicleId:w,rear:y,front:A,center:{x:(y.x+A.x)/2,y:(y.y+A.y)/2},angle:Math.atan2(A.y-y.y,A.x-y.x)}})}}if(k(w=>w.map(e=>{const i=l.current.get(e.id);return i?i.vehicle:e})),C&&P.length>0){const w=f.current;setTimeout(()=>{f.current===w&&P.forEach(({type:e,data:i})=>{C.emit(e,i)})},0)}for(const[,w]of l.current)if(w.vehicle.state==="moving")return!0;return!1},[x,m,E,I,C]),g=n.useCallback(()=>{if(o.current)return!0;const c=p.current;if(!c)return!1;const M=r?r():I,P=[];let w=!1;for(const[e,i]of l.current){const u=i.vehicle,b=M.get(e);if(!b||b.length===0)continue;const $=b[0],L={graph:c,linesMap:x,curves:m,config:E},V=Q.prepareCommandPath(u,$,L);if(!V){console.warn(`No path found for vehicle ${e}`);continue}const y=Q.calculateFrontAxlePosition(V.path,0,0,d);l.current.set(e,{...i,execution:{path:V.path,curveDataMap:V.curveDataMap,currentCommandIndex:0,rear:{currentSegmentIndex:0,segmentDistance:0},front:y?{currentSegmentIndex:y.segmentIndex,segmentDistance:y.segmentDistance}:{currentSegmentIndex:0,segmentDistance:0}},vehicle:{...u,state:"moving"}}),w=!0,u.state!=="moving"&&P.push({id:e,fromState:u.state,command:$,startPosition:{lineId:u.rear.lineId,absoluteOffset:u.rear.absoluteOffset,position:u.rear.position}})}if(!w)return!1;if(o.current=!0,k(e=>e.map(i=>{const u=l.current.get(i.id);return u?u.vehicle:i})),C&&P.length>0){const e=f.current;setTimeout(()=>{f.current===e&&P.forEach(({id:i,fromState:u,command:b,startPosition:$})=>{C.emit("commandStart",{vehicleId:i,command:b,commandIndex:0,startPosition:$}),C.emit("stateChange",{vehicleId:i,from:u,to:"moving"})})},0)}return!0},[x,m,I,r,E,d,C]),h=n.useCallback(()=>{f.current++,o.current=!1;const{movingVehicles:c,stateMap:M}=Q.initializeAllVehicles(s,x);l.current=M,k(c)},[s,x]),S=n.useCallback(c=>{const M=l.current.get(c);if(!M||M.vehicle.state!=="waiting")return!1;const P=I.get(c),w=M.execution;if(!w)return!1;const e=w.currentCommandIndex+1;if(P&&e<P.length){const i=p.current;if(i){const u=P[e],b={graph:i,linesMap:x,curves:m,config:E},$=Q.prepareCommandPath(M.vehicle,u,b);if($){const L=Q.calculateFrontAxlePosition($.path,0,0,d);if(M.execution={path:$.path,curveDataMap:$.curveDataMap,currentCommandIndex:e,rear:{currentSegmentIndex:0,segmentDistance:0},front:L?{currentSegmentIndex:L.segmentIndex,segmentDistance:L.segmentDistance}:{currentSegmentIndex:0,segmentDistance:0}},M.vehicle={...M.vehicle,state:"moving"},k(V=>V.map(y=>y.id===c?M.vehicle:y)),C){const V=f.current;setTimeout(()=>{f.current===V&&C.emit("stateChange",{vehicleId:c,from:"waiting",to:"moving"})},0)}return!0}}}if(M.vehicle={...M.vehicle,state:"idle"},M.execution=null,k(i=>i.map(u=>u.id===c?M.vehicle:u)),C){const i=f.current;setTimeout(()=>{f.current===i&&C.emit("stateChange",{vehicleId:c,from:"waiting",to:"idle"})},0)}return!0},[I,x,m,E,d,C]),q=n.useCallback(()=>{for(const[,c]of l.current)if(c.vehicle.state==="moving")return!0;return!1},[]);return{movingVehicles:D,prepare:g,tick:v,reset:h,continueVehicle:S,isMoving:q,isPrepared:o.current}}function re({wheelbase:s,tangentMode:a="proportional-40",eventEmitter:I}){const r=J(),d=B({lines:r.lines,wheelbase:s}),t=W({vehicles:d.vehicles,lines:r.lines,curves:r.curves}),m=Z({vehicles:d.vehicles,lines:r.lines,vehicleQueues:t.vehicleQueues,getVehicleQueues:t.getVehicleQueues,wheelbase:s,tangentMode:a,curves:r.curves,eventEmitter:I}),C=n.useCallback(e=>d.vehicles.filter(i=>i.lineId===e||i.rear.lineId===e),[d.vehicles]),D=n.useCallback(e=>C(e).length>0,[C]),k=n.useCallback(e=>{const i=r.addLine(e);return i.success?{success:!0}:{success:!1,error:i.error}},[r]),E=n.useCallback((e,i)=>{const u=r.updateLine(e,i);return u.success?{success:!0}:{success:!1,error:u.error}},[r]),x=n.useCallback(e=>{const i=[],u=C(e);u.length>0&&(i.push({type:"vehicle_on_removed_line",message:`${u.length} vehicle(s) are on line '${e}'`,details:{lineId:e,vehicleIds:u.map(L=>L.id)}}),u.forEach(L=>{d.removeVehicle(L.id),t.clearQueue(L.id)}));const b=r.curves.filter(L=>L.fromLineId===e||L.toLineId===e);b.length>0&&i.push({type:"orphaned_connection",message:`${b.length} connection(s) will be removed`,details:{lineId:e,connectionCount:b.length}});const $=r.removeLine(e);return $.success?{success:!0,warnings:i.length>0?i:void 0}:{success:!1,error:$.error}},[r,C,d,t]),l=n.useCallback(()=>{r.clear(),d.clear(),t.clearQueue()},[r,d,t]),p=n.useCallback((e,i,u)=>{const b=r.addConnection({from:e,to:i,fromPosition:u?.fromOffset,fromIsPercentage:u?.fromIsPercentage,toPosition:u?.toOffset,toIsPercentage:u?.toIsPercentage});return b.success?{success:!0}:{success:!1,error:b.error}},[r]),f=n.useCallback((e,i,u)=>{const b=r.updateConnection(e,i,u);return b.success?{success:!0}:{success:!1,error:b.error}},[r]),o=n.useCallback((e,i)=>{const u=r.removeConnection(e,i);return u.success?{success:!0}:{success:!1,error:u.error}},[r]),v=n.useCallback(e=>{const i=d.addVehicles(e);return i.success?{success:!0}:{success:!1,error:i.errors?.join("; ")}},[d]),g=n.useCallback((e,i)=>{const u=d.updateVehicle(e,i);return u.success?{success:!0}:{success:!1,error:u.error}},[d]),h=n.useCallback(e=>{const i=[],u=t.vehicleQueues.get(e);u&&u.length>0&&(i.push({type:"movement_queue_cleared",message:`${u.length} queued movement(s) will be cleared for vehicle '${e}'`,details:{vehicleId:e}}),t.clearQueue(e));const b=d.removeVehicle(e);return b.success?{success:!0,warnings:i.length>0?i:void 0}:{success:!1,error:b.error}},[d,t]),S=n.useCallback(()=>{d.clear(),t.clearQueue()},[d,t]),q=n.useCallback(e=>{const i={targetLineId:e.lineId,targetPosition:e.position??1,isPercentage:e.isPercentage,wait:e.wait,payload:e.payload},u=t.queueMovement(e.id,i);return u.success?{success:!0}:{success:!1,error:u.error}},[t]),c=n.useCallback(e=>{const i=t.clearQueue(e);return i.success?{success:!0}:{success:!1,error:i.error}},[t]),M=n.useCallback(e=>{const i=[],u=[],{scene:b,vehicles:$,movements:L}=T.parseAllDSL(e);b.errors.length>0&&u.push(...b.errors),$.errors.length>0&&u.push(...$.errors),L.errors.length>0&&u.push(...L.errors);const V=b.data.lines.map(z),y=(b.data.connections||[]).map(j),A=$.data.map(N),{vehicles:O,errors:R}=T.validateAndCreateVehicles(A,V,s);R.length>0&&u.push(...R);const U=new Map;for(const G of L.data){const Y=U.get(G.vehicleId)||[];Y.push(H(G)),U.set(G.vehicleId,Y)}return r._loadScene(V,y),d._loadVehicles(O),t._loadQueues(U),u.length>0&&i.push({type:"dsl_parse_error",message:`DSL loading had ${u.length} error(s)`,details:{errors:u}}),{success:!0,warnings:i.length>0?i:void 0}},[r,d,t,s]),P=n.useCallback(e=>{const i=[],u=[],b=e.lines.map(z),$=(e.connections||[]).map(j),L=(e.vehicles||[]).map(N),{vehicles:V,errors:y}=T.validateAndCreateVehicles(L,b,s);y.length>0&&u.push(...y);const A=new Map;for(const O of e.movements||[]){const R=A.get(O.vehicleId)||[];R.push(H({vehicleId:O.vehicleId,targetLineId:O.targetLineId,targetPosition:O.targetPosition,isPercentage:O.isPercentage,wait:O.wait,payload:O.payload})),A.set(O.vehicleId,R)}return r._loadScene(b,$),d._loadVehicles(V),t._loadQueues(A),u.length>0&&i.push({type:"dsl_parse_error",message:`JSON loading had ${u.length} error(s)`,details:{errors:u}}),{success:!0,warnings:i.length>0?i:void 0}},[r,d,t,s]),w=n.useMemo(()=>r.error||d.error||t.error,[r.error,d.error,t.error]);return{lines:r.lines,curves:r.curves,vehicles:d.vehicles,movingVehicles:m.movingVehicles,vehicleQueues:t.vehicleQueues,error:w,addLine:k,updateLine:E,removeLine:x,clearScene:l,connect:p,updateConnection:f,disconnect:o,addVehicles:v,updateVehicle:g,removeVehicle:h,clearVehicles:S,goto:q,clearQueue:c,prepare:m.prepare,tick:m.tick,reset:m.reset,continueVehicle:m.continueVehicle,isMoving:m.isMoving,loadFromDSL:M,loadFromJSON:P,getVehiclesOnLine:C,hasVehiclesOnLine:D}}function _(s){return s.map(a=>({id:a.id,start:a.start,end:a.end}))}function K(s){return s.map(a=>({from:a.fromLineId,to:a.toLineId,fromPosition:a.fromOffset,fromIsPercentage:a.fromIsPercentage,toPosition:a.toOffset,toIsPercentage:a.toIsPercentage}))}function ne(){const[s,a]=n.useState(""),[I,r]=n.useState(null),{lines:d,curves:t,setScene:m}=J(),C=n.useRef(!1),D=n.useRef("");n.useEffect(()=>{D.current=s},[s]),n.useEffect(()=>{if(C.current)return;const l={lines:_(d),connections:t.length>0?K(t):void 0},p=T.generateSceneDSL(l);p!==D.current&&(C.current=!0,a(p),setTimeout(()=>{C.current=!1},50))},[d,t]);const k=n.useCallback(l=>{C.current=!0,a(l);try{const{data:p,errors:f}=T.parseSceneDSL(l);f.length>0&&r(f.join("; "));const o=m(p);!o.success&&o.errors?r(v=>v?`${v}; ${o.errors.join("; ")}`:o.errors.join("; ")):f.length===0&&r(null)}catch(p){r(p instanceof Error?p.message:"Invalid scene definition")}setTimeout(()=>{C.current=!1},50)},[m]),E=n.useCallback(l=>{const p=typeof l=="function"?l(d):l,f=K(t);m({lines:_(p),connections:f.length>0?f:void 0});const o={lines:_(p),connections:f.length>0?f:void 0},v=T.generateSceneDSL(o);C.current=!0,a(v),setTimeout(()=>{C.current=!1},50)},[d,t,m]),x=n.useCallback(l=>{const p=typeof l=="function"?l(t):l,f=K(p);m({lines:_(d),connections:f.length>0?f:void 0});const o={lines:_(d),connections:f.length>0?f:void 0},v=T.generateSceneDSL(o);C.current=!0,a(v),setTimeout(()=>{C.current=!1},50)},[d,t,m]);return{lines:d,curves:t,sceneDefinitionText:s,sceneError:I,isDebouncing:!1,debounceKey:0,setLines:E,setCurves:x,setSceneDefinitionText:k}}function oe({lines:s,wheelbase:a}){const[I,r]=n.useState(""),[d,t]=n.useState(null),{vehicles:m,addVehicles:C,clear:D,error:k}=B({lines:s,wheelbase:a}),E=n.useRef(!1),x=n.useCallback(l=>{E.current=!0,r(l);try{const{data:p,errors:f}=T.parseVehiclesDSL(l),o=[...f];D();for(const v of p){const g=C(v);!g.success&&g.errors&&o.push(...g.errors)}o.length>0?t(o.join(`
2
+ `)):t(null)}catch(p){t(p instanceof Error?p.message:"Invalid initial movement")}setTimeout(()=>{E.current=!1},50)},[C,D]);return{vehicles:m,initialMovementText:I,movementError:d||k,isDebouncing:!1,debounceKey:0,setInitialMovementText:x}}function ce({lines:s,vehicles:a}){const[I,r]=n.useState(""),[d,t]=n.useState([]),[m,C]=n.useState(null),{vehicleQueues:D,queueMovement:k,clearQueue:E,error:x}=W({vehicles:a,lines:s}),l=n.useRef(!1),p=n.useCallback(f=>{l.current=!0,r(f);try{const{data:o,errors:v}=T.parseMovementDSL(f),g=[...v];E();for(const h of o){const S=k(h.vehicleId,{targetLineId:h.targetLineId,targetPosition:h.targetPosition,isPercentage:h.isPercentage,wait:h.wait,payload:h.payload});!S.success&&S.error&&g.push(S.error)}t(o),g.length>0?C(g.join(`
3
+ `)):C(null)}catch(o){C(o instanceof Error?o.message:"Invalid movement sequence"),t([])}setTimeout(()=>{l.current=!1},50)},[k,E]);return{movementSequenceText:I,gotoCommands:d,vehicleQueues:D,sequenceError:m||x,isDebouncing:!1,debounceKey:0,setMovementSequenceText:p}}const X=n.createContext(null);function ee(){const s=n.useContext(X);if(!s)throw new Error("useVehicleEventEmitter must be used within a VehicleEventProvider");return s}function ie(){return n.useMemo(()=>new T.VehicleEventEmitter,[])}function ae(s,a,I=[]){const r=ee();n.useEffect(()=>r.on(s,a),[r,s,...I])}function ue({children:s}){const a=n.useMemo(()=>new T.VehicleEventEmitter,[]);return te.jsx(X.Provider,{value:a,children:s})}exports.VehicleEventContext=X;exports.VehicleEventProvider=ue;exports.useAnimation=Z;exports.useCreateVehicleEventEmitter=ie;exports.useInitialMovement=oe;exports.useMovementQueue=W;exports.useMovementSequence=ce;exports.useScene=J;exports.useSceneDefinition=ne;exports.useVehicleEvent=ae;exports.useVehicleEventEmitter=ee;exports.useVehicleSimulation=re;exports.useVehicles=B;