@zonetrix/viewer 2.5.0 → 2.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/README.md CHANGED
@@ -108,6 +108,7 @@ function BookingApp() {
108
108
  | `onFloorChange` | `(floorId: string) => void` | No | Callback when floor changes |
109
109
  | `reservedSeats` | `string[]` | No | Array of seat IDs/numbers to mark as reserved |
110
110
  | `unavailableSeats` | `string[]` | No | Array of seat IDs/numbers to mark as unavailable |
111
+ | `selectedSeats` | `string[]` | No | Array of seat IDs for controlled selection mode |
111
112
  | `onSeatSelect` | `(seat: SeatData) => void` | No | Callback when a seat is selected |
112
113
  | `onSeatDeselect` | `(seat: SeatData) => void` | No | Callback when a seat is deselected |
113
114
  | `onSelectionChange` | `(seats: SeatData[]) => void` | No | Callback when selection changes |
@@ -341,7 +342,88 @@ function CustomFloorSelector() {
341
342
  }
342
343
  ```
343
344
 
344
- ### 7. Error Handling
345
+ ### 7. Controlled Selection Mode
346
+
347
+ For complete control over seat selection state (e.g., syncing with external state, URL params, or database):
348
+
349
+ ```tsx
350
+ import { useState } from 'react';
351
+ import { SeatMapViewer } from '@zonetrix/viewer';
352
+ import type { SeatData } from '@zonetrix/viewer';
353
+
354
+ function ControlledSelection() {
355
+ const [selectedSeatIds, setSelectedSeatIds] = useState<string[]>([]);
356
+
357
+ const handleSeatSelect = (seat: SeatData) => {
358
+ setSelectedSeatIds(prev => [...prev, seat.id]);
359
+ };
360
+
361
+ const handleSeatDeselect = (seat: SeatData) => {
362
+ setSelectedSeatIds(prev => prev.filter(id => id !== seat.id));
363
+ };
364
+
365
+ return (
366
+ <SeatMapViewer
367
+ config={venueConfig}
368
+ selectedSeats={selectedSeatIds} // Controlled mode
369
+ onSeatSelect={handleSeatSelect}
370
+ onSeatDeselect={handleSeatDeselect}
371
+ />
372
+ );
373
+ }
374
+ ```
375
+
376
+ **Use cases for controlled selection mode:**
377
+ - Syncing selection with URL query parameters
378
+ - Persisting selection in Redux/Zustand store
379
+ - Loading pre-selected seats from database
380
+ - Implementing undo/redo functionality
381
+ - Syncing selection across multiple components
382
+ - Integrating with shopping cart state management
383
+
384
+ **Example with cart integration:**
385
+
386
+ ```tsx
387
+ import { useState } from 'react';
388
+ import { SeatMapViewer } from '@zonetrix/viewer';
389
+ import type { SeatData } from '@zonetrix/viewer';
390
+
391
+ function CartIntegration() {
392
+ const [cartItems, setCartItems] = useState<SeatData[]>([]);
393
+
394
+ // Derive selected IDs from cart
395
+ const selectedSeatIds = cartItems.map(seat => seat.id);
396
+
397
+ const handleSeatSelect = (seat: SeatData) => {
398
+ setCartItems(prev => [...prev, seat]);
399
+ };
400
+
401
+ const handleSeatDeselect = (seat: SeatData) => {
402
+ setCartItems(prev => prev.filter(item => item.id !== seat.id));
403
+ };
404
+
405
+ const totalPrice = cartItems.reduce((sum, seat) => sum + (seat.price || 0), 0);
406
+
407
+ return (
408
+ <div>
409
+ <SeatMapViewer
410
+ config={venueConfig}
411
+ selectedSeats={selectedSeatIds}
412
+ onSeatSelect={handleSeatSelect}
413
+ onSeatDeselect={handleSeatDeselect}
414
+ />
415
+
416
+ <div className="cart">
417
+ <h3>Shopping Cart</h3>
418
+ <p>Selected: {cartItems.length} seat(s)</p>
419
+ <p>Total: ${totalPrice.toFixed(2)}</p>
420
+ </div>
421
+ </div>
422
+ );
423
+ }
424
+ ```
425
+
426
+ ### 8. Error Handling
345
427
 
346
428
  ```tsx
347
429
  import { SeatMapViewer } from '@zonetrix/viewer';
@@ -7,6 +7,7 @@ export interface SeatMapViewerProps {
7
7
  onFloorChange?: (floorId: string) => void;
8
8
  reservedSeats?: string[];
9
9
  unavailableSeats?: string[];
10
+ selectedSeats?: string[];
10
11
  onSeatSelect?: (seat: SeatData) => void;
11
12
  onSeatDeselect?: (seat: SeatData) => void;
12
13
  onSelectionChange?: (seats: SeatData[]) => void;
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("react/jsx-runtime"),e=require("react"),L=require("react-konva");function dt(n){const[i,d]=e.useState(null),[r,b]=e.useState(!1),[S,p]=e.useState(null),v=async()=>{if(n){b(!0),p(null);try{const y=await fetch(n);if(!y.ok)throw new Error(`Failed to fetch config: ${y.statusText}`);const a=await y.json();d(a)}catch(y){const a=y instanceof Error?y:new Error("Unknown error occurred");p(a),console.error("Failed to fetch seat map config:",a)}finally{b(!1)}}};return e.useEffect(()=>{v()},[n]),{config:i,loading:r,error:S,refetch:v}}function ft(n){const[i,d]=e.useState({width:0,height:0});return e.useEffect(()=>{const r=n.current;if(!r)return;const{width:b,height:S}=r.getBoundingClientRect();b>0&&S>0&&d({width:b,height:S});const p=new ResizeObserver(v=>{const y=v[0];if(!y)return;const{width:a,height:s}=y.contentRect;a>0&&s>0&&d(u=>u.width===a&&u.height===s?u:{width:a,height:s})});return p.observe(r),()=>{p.disconnect()}},[n]),i}function ut(n,i){return Math.sqrt(Math.pow(i.x-n.x,2)+Math.pow(i.y-n.y,2))}function ht(n,i){return{x:(n.x+i.x)/2,y:(n.y+i.y)/2}}function xt(n,i){const d=e.useRef(null),r=e.useRef(null),b=e.useRef(1);e.useEffect(()=>{const S=n.current;if(!S||!i.enabled)return;const p=S.container(),v=s=>{if(s.touches.length===2){s.preventDefault();const u={x:s.touches[0].clientX,y:s.touches[0].clientY},g={x:s.touches[1].clientX,y:s.touches[1].clientY};d.current=ut(u,g),r.current=ht(u,g),b.current=i.currentScale}},y=s=>{if(s.touches.length!==2)return;s.preventDefault();const u={x:s.touches[0].clientX,y:s.touches[0].clientY},g={x:s.touches[1].clientX,y:s.touches[1].clientY},k=ut(u,g),C=ht(u,g);if(d.current!==null&&r.current!==null){const R=k/d.current,P=Math.min(Math.max(i.currentScale*R,i.minScale),i.maxScale),V=p.getBoundingClientRect(),_=C.x-V.left,G=C.y-V.top,W=i.currentScale,T={x:(_-i.currentPosition.x)/W,y:(G-i.currentPosition.y)/W},et=C.x-r.current.x,nt=C.y-r.current.y,ot={x:_-T.x*P+et,y:G-T.y*P+nt};i.onScaleChange(P,ot),d.current=k,r.current=C}},a=s=>{s.touches.length<2&&(d.current=null,r.current=null)};return p.addEventListener("touchstart",v,{passive:!1}),p.addEventListener("touchmove",y,{passive:!1}),p.addEventListener("touchend",a),()=>{p.removeEventListener("touchstart",v),p.removeEventListener("touchmove",y),p.removeEventListener("touchend",a)}},[n,i])}const pt={canvasBackground:"#1a1a1a",stageColor:"#808080",seatAvailable:"#2C2B30",seatReserved:"#FCEA00",seatSelected:"#3A7DE5",seatUnavailable:"#6b7280",seatHidden:"#4a4a4a",gridLines:"#404040",currency:"KD"},gt=e.memo(({seat:n,state:i,colors:d,onClick:r,onMouseEnter:b,onMouseLeave:S})=>{const y={available:d.seatAvailable,reserved:d.seatReserved,selected:d.seatSelected,unavailable:d.seatUnavailable,hidden:d.seatHidden}[i],a=i==="available"||i==="selected",s=e.useCallback(()=>{a&&r(n)},[n,r,a]),u=e.useCallback(C=>{b(n,C);const R=C.target.getStage();R&&a&&(R.container().style.cursor="pointer")},[n,b,a]),g=e.useCallback(C=>{S();const R=C.target.getStage();R&&(R.container().style.cursor="grab")},[S]),k={x:n.position.x,y:n.position.y,fill:y,stroke:"#ffffff",strokeWidth:1,onClick:s,onTap:s,onMouseEnter:u,onMouseLeave:g};return n.shape==="circle"?o.jsx(L.Circle,{...k,radius:12}):o.jsx(L.Rect,{...k,width:24,height:24,offsetX:12,offsetY:12,cornerRadius:n.shape==="square"?0:4})});gt.displayName="ViewerSeat";const yt=e.memo(({stage:n,stageColor:i})=>o.jsxs(L.Group,{x:n.position.x,y:n.position.y,children:[o.jsx(L.Rect,{width:n.config.width,height:n.config.height,fill:i+"80",stroke:"#ffffff",strokeWidth:2,cornerRadius:10}),o.jsx(L.Text,{text:n.config.label,x:0,y:0,width:n.config.width,height:n.config.height,fontSize:24,fontStyle:"bold",fill:"#ffffff",align:"center",verticalAlign:"middle"})]}));yt.displayName="ViewerStage";const mt=e.memo(({floors:n,currentFloorId:i,onFloorChange:d,showAllOption:r,allLabel:b,position:S,className:p})=>{const v=e.useMemo(()=>[...n].sort((g,k)=>g.order-k.order),[n]),a={position:"absolute",display:"flex",alignItems:"center",gap:"8px",padding:"8px 12px",backgroundColor:"rgba(26, 26, 26, 0.95)",borderRadius:"8px",margin:"12px",zIndex:10,...{"top-left":{top:0,left:0},"top-right":{top:0,right:0},"bottom-left":{bottom:0,left:0},"bottom-right":{bottom:0,right:0}}[S]},s={padding:"10px 16px",fontSize:"14px",fontWeight:500,border:"1px solid #444",borderRadius:"6px",backgroundColor:"transparent",color:"#fff",cursor:"pointer",transition:"all 0.2s ease",minHeight:"44px",touchAction:"manipulation"},u={...s,backgroundColor:"#3A7DE5",borderColor:"#3A7DE5"};return o.jsxs("div",{className:p,style:a,children:[r&&o.jsx("button",{type:"button",onClick:()=>d(null),style:i===null?u:s,children:b}),v.map(g=>o.jsx("button",{type:"button",onClick:()=>d(g.id),style:i===g.id?u:s,children:g.name},g.id))]})});mt.displayName="FloorSelectorBar";const bt=e.memo(({scale:n,minScale:i,maxScale:d,onZoomIn:r,onZoomOut:b,position:S,className:p})=>{const y={position:"absolute",display:"flex",flexDirection:"column",gap:"4px",padding:"8px",backgroundColor:"rgba(26, 26, 26, 0.95)",borderRadius:"8px",margin:"12px",zIndex:10,...{"top-left":{top:0,left:0},"top-right":{top:0,right:0},"bottom-left":{bottom:0,left:0},"bottom-right":{bottom:0,right:0}}[S]},a={width:"44px",height:"44px",minWidth:"44px",minHeight:"44px",fontSize:"22px",fontWeight:"bold",border:"1px solid #444",borderRadius:"6px",backgroundColor:"transparent",color:"#fff",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",transition:"all 0.2s ease",touchAction:"manipulation"},s={...a,opacity:.4,cursor:"not-allowed"},u=n<d,g=n>i;return o.jsxs("div",{className:p,style:y,children:[o.jsx("button",{type:"button",onClick:r,disabled:!u,style:u?a:s,title:"Zoom In",children:"+"}),o.jsx("button",{type:"button",onClick:b,disabled:!g,style:g?a:s,title:"Zoom Out",children:"−"})]})});bt.displayName="ZoomControls";const St=e.memo(({visible:n,x:i,y:d,seat:r,currency:b,state:S})=>{if(!n||!r)return null;const p=r.seatNumber||(r.rowLabel&&r.columnLabel?`${r.rowLabel}-${r.columnLabel}`:"N/A"),v={position:"fixed",left:`${i+15}px`,top:`${d+15}px`,zIndex:1e3,pointerEvents:"none"},y={backgroundColor:"rgba(26, 26, 26, 0.95)",color:"#fff",border:"1px solid #444",borderRadius:"8px",padding:"8px 12px",fontSize:"13px",boxShadow:"0 4px 12px rgba(0, 0, 0, 0.3)",minWidth:"140px"},a={color:"#9ca3af",marginRight:"4px"},s={fontWeight:600},u={color:"#4ade80",fontWeight:600},g={fontSize:"11px",color:"#6b7280",textTransform:"capitalize",marginTop:"4px"};return o.jsx("div",{style:v,children:o.jsxs("div",{style:y,children:[r.sectionName&&o.jsxs("div",{style:{marginBottom:"4px"},children:[o.jsx("span",{style:a,children:"Section:"}),o.jsx("span",{style:{...s,color:"#3b82f6"},children:r.sectionName})]}),o.jsxs("div",{style:{marginBottom:"4px"},children:[o.jsx("span",{style:a,children:"Seat:"}),o.jsx("span",{style:s,children:p})]}),r.price!==void 0&&r.price>0&&o.jsxs("div",{style:{marginBottom:"4px"},children:[o.jsx("span",{style:a,children:"Price:"}),o.jsxs("span",{style:u,children:[b," ",r.price.toFixed(2)]})]}),o.jsxs("div",{style:g,children:["Status: ",S]})]})})});St.displayName="SeatTooltip";const Vt=({config:n,configUrl:i,floorId:d,onFloorChange:r,reservedSeats:b=[],unavailableSeats:S=[],onSeatSelect:p,onSeatDeselect:v,onSelectionChange:y,colorOverrides:a,showTooltip:s=!0,zoomEnabled:u=!0,className:g="",onConfigLoad:k,onError:C,showFloorSelector:R,floorSelectorPosition:P="top-left",floorSelectorClassName:V,showAllFloorsOption:_=!0,allFloorsLabel:G="All",fitToView:W=!0,fitPadding:T=40,showZoomControls:et=!0,zoomControlsPosition:nt="bottom-right",zoomControlsClassName:ot,maxZoom:I=3,zoomStep:U=.25,touchEnabled:vt=!0})=>{const st=e.useRef(null),at=e.useRef(null),w=ft(at),[X,wt]=e.useState(new Set),[j,A]=e.useState(1),[M,D]=e.useState({x:0,y:0}),[Ct,jt]=e.useState(null),[Mt,kt]=e.useState(1),Z=e.useRef({width:0,height:0}),[B,lt]=e.useState({visible:!1,x:0,y:0,seat:null,state:"available"}),{config:Rt,loading:Et,error:z}=dt(i),l=n||Rt,it=d!==void 0,E=it?d||null:Ct,It=e.useCallback(t=>{it||jt(t),r?.(t)},[it,r]),rt=l?.floors||[],Nt=R!==void 0?R:rt.length>1,K=e.useMemo(()=>l?{...l.colors,...a}:{...pt,...a},[l,a]),Y=e.useMemo(()=>{if(!l)return[];let t=l.seats.filter(c=>c.state!=="hidden");return E&&(t=t.filter(c=>c.floorId===E||!c.floorId&&E==="floor_default")),t},[l,E]),J=e.useMemo(()=>l?.stages?E?l.stages.filter(t=>t.floorId===E||!t.floorId&&E==="floor_default"):l.stages:[],[l,E]),N=e.useMemo(()=>{if(!l||Y.length===0&&J.length===0)return null;const t=12;let c=1/0,f=1/0,h=-1/0,x=-1/0;return Y.forEach(m=>{c=Math.min(c,m.position.x-t),f=Math.min(f,m.position.y-t),h=Math.max(h,m.position.x+t),x=Math.max(x,m.position.y+t)}),J.forEach(m=>{c=Math.min(c,m.position.x),f=Math.min(f,m.position.y),h=Math.max(h,m.position.x+(m.config?.width||200)),x=Math.max(x,m.position.y+(m.config?.height||100))}),{minX:c,minY:f,maxX:h,maxY:x,width:h-c,height:x-f}},[l,Y,J]);e.useEffect(()=>{if(!W||!l||!N||w.width===0||w.height===0)return;const t=Math.abs(w.width-Z.current.width),c=Math.abs(w.height-Z.current.height);if(!(Z.current.width===0)&&t<10&&c<10)return;Z.current=w;const h=w.width,x=w.height,m=h-T*2,q=x-T*2,Q=m/N.width,ct=q/N.height,tt=Math.min(Q,ct,I),Bt=N.minX+N.width/2,zt=N.minY+N.height/2,$t=h/2,Ht=x/2,Ot=$t-Bt*tt,qt=Ht-zt*tt;A(tt),D({x:Ot,y:qt}),kt(tt)},[W,l,N,T,I,w,E]);const $=e.useMemo(()=>{const t=new Set(b),c=new Set(S);return{reserved:t,unavailable:c}},[b,S]),H=e.useCallback(t=>{const c=t.id,f=t.seatNumber||"";return $.unavailable.has(c)||$.unavailable.has(f)?"unavailable":$.reserved.has(c)||$.reserved.has(f)?"reserved":X.has(c)?"selected":t.state},[$,X]);e.useEffect(()=>{l&&k&&k(l)},[l,k]),e.useEffect(()=>{z&&C&&C(z)},[z,C]);const Lt=e.useCallback(t=>{const c=H(t);if(c!=="available"&&c!=="selected")return;const f=X.has(t.id);wt(h=>{const x=new Set(h);return f?x.delete(t.id):x.add(t.id),x}),f?v?.(t):(p?.(t),p||console.log("Seat selected:",t))},[H,X,p,v]),O=e.useMemo(()=>l?Y.filter(t=>X.has(t.id)):[],[Y,X]);e.useEffect(()=>{y?.(O)},[O,y]);const F=Mt,Dt=e.useCallback(()=>{if(!u)return;const t=Math.min(j+U,I);if(t!==j){const c=w.width||l?.canvas.width||800,f=w.height||l?.canvas.height||600,h=c/2,x=f/2,m={x:(h-M.x)/j,y:(x-M.y)/j};A(t),D({x:h-m.x*t,y:x-m.y*t})}},[u,j,U,I,w,l,M]),Tt=e.useCallback(()=>{if(!u)return;const t=Math.max(j-U,F);if(t!==j){const c=w.width||l?.canvas.width||800,f=w.height||l?.canvas.height||600,h=c/2,x=f/2,m={x:(h-M.x)/j,y:(x-M.y)/j};A(t),D({x:h-m.x*t,y:x-m.y*t})}},[u,j,U,F,w,l,M]),Xt=e.useCallback(t=>{D({x:t.target.x(),y:t.target.y()})},[]),Yt=e.useCallback(t=>{if(!u)return;t.evt.preventDefault();const c=st.current;if(!c)return;const f=c.scaleX(),h=c.getPointerPosition();if(!h)return;const x=1.1,m=t.evt.deltaY>0?f/x:f*x,q=Math.min(Math.max(m,F),I),Q={x:(h.x-M.x)/f,y:(h.y-M.y)/f},ct={x:h.x-Q.x*q,y:h.y-Q.y*q};A(q),D(ct)},[u,M,F,I]);xt(st,{enabled:vt&&u,minScale:F,maxScale:I,currentScale:j,currentPosition:M,onScaleChange:(t,c)=>{A(t),D(c)},onPositionChange:t=>{D(t)}});const Ft=e.useCallback((t,c)=>{if(!s)return;const f=c.target.getStage();if(!f)return;const h=f.getPointerPosition();if(!h)return;const x=f.container().getBoundingClientRect();lt({visible:!0,x:x.left+h.x,y:x.top+h.y,seat:t,state:H(t)})},[s,H]),Pt=e.useCallback(()=>{lt(t=>({...t,visible:!1}))},[]);if(Et)return o.jsx("div",{className:`flex items-center justify-center h-full ${g}`,children:o.jsx("p",{children:"Loading seat map..."})});if(z)return o.jsx("div",{className:`flex items-center justify-center h-full ${g}`,children:o.jsxs("p",{className:"text-red-500",children:["Error loading seat map: ",z.message]})});if(!l)return o.jsx("div",{className:`flex items-center justify-center h-full ${g}`,children:o.jsx("p",{children:"No configuration provided"})});const Wt=w.width||l.canvas.width,At=w.height||l.canvas.height;return o.jsxs("div",{ref:at,className:`relative ${g}`,style:{width:"100%",height:"100%"},children:[Nt&&rt.length>0&&o.jsx(mt,{floors:rt,currentFloorId:E,onFloorChange:It,showAllOption:_,allLabel:G,position:P,className:V}),o.jsxs(L.Stage,{ref:st,width:Wt,height:At,scaleX:j,scaleY:j,x:M.x,y:M.y,draggable:!0,onDragEnd:Xt,onWheel:Yt,style:{backgroundColor:l.canvas.backgroundColor,cursor:"grab"},children:[o.jsx(L.Layer,{listening:!1,children:J.map(t=>o.jsx(yt,{stage:t,stageColor:K.stageColor},t.id))}),o.jsx(L.Layer,{children:Y.map(t=>o.jsx(gt,{seat:t,state:H(t),colors:K,onClick:Lt,onMouseEnter:Ft,onMouseLeave:Pt},t.id))})]}),s&&o.jsx(St,{visible:B.visible,x:B.x,y:B.y,seat:B.seat,currency:K.currency,state:B.state}),et&&u&&o.jsx(bt,{scale:j,minScale:F,maxScale:I,onZoomIn:Dt,onZoomOut:Tt,position:nt,className:ot}),O.length>0&&o.jsxs("div",{className:"absolute top-4 right-4 bg-white dark:bg-gray-800 p-4 rounded shadow-lg",children:[o.jsxs("h3",{className:"font-semibold mb-2",children:["Selected Seats (",O.length,")"]}),o.jsx("div",{className:"max-h-48 overflow-y-auto space-y-1",children:O.map(t=>o.jsxs("div",{className:"text-sm",children:[t.seatNumber,t.price&&` - ${K.currency} ${t.price.toFixed(2)}`]},t.id))})]})]})};exports.DEFAULT_COLORS=pt;exports.SeatMapViewer=Vt;exports.useConfigFetcher=dt;exports.useContainerSize=ft;exports.useTouchGestures=xt;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("react/jsx-runtime"),e=require("react"),I=require("react-konva");function pt(n){const[r,u]=e.useState(null),[i,m]=e.useState(!1),[b,f]=e.useState(null),v=async()=>{if(n){m(!0),f(null);try{const y=await fetch(n);if(!y.ok)throw new Error(`Failed to fetch config: ${y.statusText}`);const a=await y.json();u(a)}catch(y){const a=y instanceof Error?y:new Error("Unknown error occurred");f(a),console.error("Failed to fetch seat map config:",a)}finally{m(!1)}}};return e.useEffect(()=>{v()},[n]),{config:r,loading:i,error:b,refetch:v}}function gt(n){const[r,u]=e.useState({width:0,height:0});return e.useEffect(()=>{const i=n.current;if(!i)return;const{width:m,height:b}=i.getBoundingClientRect();m>0&&b>0&&u({width:m,height:b});const f=new ResizeObserver(v=>{const y=v[0];if(!y)return;const{width:a,height:s}=y.contentRect;a>0&&s>0&&u(g=>g.width===a&&g.height===s?g:{width:a,height:s})});return f.observe(i),()=>{f.disconnect()}},[n]),r}function ft(n,r){return Math.sqrt(Math.pow(r.x-n.x,2)+Math.pow(r.y-n.y,2))}function xt(n,r){return{x:(n.x+r.x)/2,y:(n.y+r.y)/2}}function yt(n,r){const u=e.useRef(null),i=e.useRef(null),m=e.useRef(1);e.useEffect(()=>{const b=n.current;if(!b||!r.enabled)return;const f=b.container(),v=s=>{if(s.touches.length===2){s.preventDefault();const g={x:s.touches[0].clientX,y:s.touches[0].clientY},h={x:s.touches[1].clientX,y:s.touches[1].clientY};u.current=ft(g,h),i.current=xt(g,h),m.current=r.currentScale}},y=s=>{if(s.touches.length!==2)return;s.preventDefault();const g={x:s.touches[0].clientX,y:s.touches[0].clientY},h={x:s.touches[1].clientX,y:s.touches[1].clientY},M=ft(g,h),C=xt(g,h);if(u.current!==null&&i.current!==null){const R=M/u.current,D=Math.min(Math.max(r.currentScale*R,r.minScale),r.maxScale),V=f.getBoundingClientRect(),_=C.x-V.left,G=C.y-V.top,U=r.currentScale,P={x:(_-r.currentPosition.x)/U,y:(G-r.currentPosition.y)/U},W=C.x-i.current.x,ot=C.y-i.current.y,it={x:_-P.x*D+W,y:G-P.y*D+ot};r.onScaleChange(D,it),u.current=M,i.current=C}},a=s=>{s.touches.length<2&&(u.current=null,i.current=null)};return f.addEventListener("touchstart",v,{passive:!1}),f.addEventListener("touchmove",y,{passive:!1}),f.addEventListener("touchend",a),()=>{f.removeEventListener("touchstart",v),f.removeEventListener("touchmove",y),f.removeEventListener("touchend",a)}},[n,r])}const mt={canvasBackground:"#1a1a1a",stageColor:"#808080",seatAvailable:"#2C2B30",seatReserved:"#FCEA00",seatSelected:"#3A7DE5",seatUnavailable:"#6b7280",seatHidden:"#4a4a4a",gridLines:"#404040",currency:"KD"},bt=e.memo(({seat:n,state:r,colors:u,onClick:i,onMouseEnter:m,onMouseLeave:b})=>{const y={available:u.seatAvailable,reserved:u.seatReserved,selected:u.seatSelected,unavailable:u.seatUnavailable,hidden:u.seatHidden}[r],a=r==="available"||r==="selected",s=e.useCallback(()=>{a&&i(n)},[n,i,a]),g=e.useCallback(C=>{m(n,C);const R=C.target.getStage();R&&a&&(R.container().style.cursor="pointer")},[n,m,a]),h=e.useCallback(C=>{b();const R=C.target.getStage();R&&(R.container().style.cursor="grab")},[b]),M={x:n.position.x,y:n.position.y,fill:y,stroke:"#ffffff",strokeWidth:1,onClick:s,onTap:s,onMouseEnter:g,onMouseLeave:h};return n.shape==="circle"?o.jsx(I.Circle,{...M,radius:12}):o.jsx(I.Rect,{...M,width:24,height:24,offsetX:12,offsetY:12,cornerRadius:n.shape==="square"?0:4})});bt.displayName="ViewerSeat";const St=e.memo(({stage:n,stageColor:r})=>{const u=b=>({stage:"🎭",table:"⬜",wall:"▬",barrier:"🛡️","dj-booth":"🎵",bar:"🍷","entry-exit":"🚪",custom:"➕"})[b||"stage"]||"🎭",i=n.config.color||r,m=u(n.config.objectType);return o.jsxs(I.Group,{x:n.position.x,y:n.position.y,rotation:n.config.rotation||0,children:[o.jsx(I.Rect,{width:n.config.width,height:n.config.height,fill:i+"80",stroke:"#ffffff",strokeWidth:2,cornerRadius:10}),o.jsx(I.Text,{text:m,x:0,y:0,width:n.config.width,height:n.config.height*.4,fontSize:32,fill:"#ffffff",align:"center",verticalAlign:"middle"}),o.jsx(I.Text,{text:n.config.label,x:0,y:n.config.height*.4,width:n.config.width,height:n.config.height*.6,fontSize:20,fontStyle:"bold",fill:"#ffffff",align:"center",verticalAlign:"middle"})]})});St.displayName="ViewerStage";const vt=e.memo(({floors:n,currentFloorId:r,onFloorChange:u,showAllOption:i,allLabel:m,position:b,className:f})=>{const v=e.useMemo(()=>[...n].sort((h,M)=>h.order-M.order),[n]),a={position:"absolute",display:"flex",alignItems:"center",gap:"8px",padding:"8px 12px",backgroundColor:"rgba(26, 26, 26, 0.95)",borderRadius:"8px",margin:"12px",zIndex:10,...{"top-left":{top:0,left:0},"top-right":{top:0,right:0},"bottom-left":{bottom:0,left:0},"bottom-right":{bottom:0,right:0}}[b]},s={padding:"10px 16px",fontSize:"14px",fontWeight:500,border:"1px solid #444",borderRadius:"6px",backgroundColor:"transparent",color:"#fff",cursor:"pointer",transition:"all 0.2s ease",minHeight:"44px",touchAction:"manipulation"},g={...s,backgroundColor:"#3A7DE5",borderColor:"#3A7DE5"};return o.jsxs("div",{className:f,style:a,children:[i&&o.jsx("button",{type:"button",onClick:()=>u(null),style:r===null?g:s,children:m}),v.map(h=>o.jsx("button",{type:"button",onClick:()=>u(h.id),style:r===h.id?g:s,children:h.name},h.id))]})});vt.displayName="FloorSelectorBar";const wt=e.memo(({scale:n,minScale:r,maxScale:u,onZoomIn:i,onZoomOut:m,position:b,className:f})=>{const y={position:"absolute",display:"flex",flexDirection:"column",gap:"4px",padding:"8px",backgroundColor:"rgba(26, 26, 26, 0.95)",borderRadius:"8px",margin:"12px",zIndex:10,...{"top-left":{top:0,left:0},"top-right":{top:0,right:0},"bottom-left":{bottom:0,left:0},"bottom-right":{bottom:0,right:0}}[b]},a={width:"44px",height:"44px",minWidth:"44px",minHeight:"44px",fontSize:"22px",fontWeight:"bold",border:"1px solid #444",borderRadius:"6px",backgroundColor:"transparent",color:"#fff",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",transition:"all 0.2s ease",touchAction:"manipulation"},s={...a,opacity:.4,cursor:"not-allowed"},g=n<u,h=n>r;return o.jsxs("div",{className:f,style:y,children:[o.jsx("button",{type:"button",onClick:i,disabled:!g,style:g?a:s,title:"Zoom In",children:"+"}),o.jsx("button",{type:"button",onClick:m,disabled:!h,style:h?a:s,title:"Zoom Out",children:"−"})]})});wt.displayName="ZoomControls";const Ct=e.memo(({visible:n,x:r,y:u,seat:i,currency:m,state:b})=>{if(!n||!i)return null;const f=i.seatNumber||(i.rowLabel&&i.columnLabel?`${i.rowLabel}-${i.columnLabel}`:"N/A"),v={position:"fixed",left:`${r+15}px`,top:`${u+15}px`,zIndex:1e3,pointerEvents:"none"},y={backgroundColor:"rgba(26, 26, 26, 0.95)",color:"#fff",border:"1px solid #444",borderRadius:"8px",padding:"8px 12px",fontSize:"13px",boxShadow:"0 4px 12px rgba(0, 0, 0, 0.3)",minWidth:"140px"},a={color:"#9ca3af",marginRight:"4px"},s={fontWeight:600},g={color:"#4ade80",fontWeight:600},h={fontSize:"11px",color:"#6b7280",textTransform:"capitalize",marginTop:"4px"};return o.jsx("div",{style:v,children:o.jsxs("div",{style:y,children:[i.sectionName&&o.jsxs("div",{style:{marginBottom:"4px"},children:[o.jsx("span",{style:a,children:"Section:"}),o.jsx("span",{style:{...s,color:"#3b82f6"},children:i.sectionName})]}),o.jsxs("div",{style:{marginBottom:"4px"},children:[o.jsx("span",{style:a,children:"Seat:"}),o.jsx("span",{style:s,children:f})]}),i.price!==void 0&&i.price>0&&o.jsxs("div",{style:{marginBottom:"4px"},children:[o.jsx("span",{style:a,children:"Price:"}),o.jsxs("span",{style:g,children:[m," ",i.price.toFixed(2)]})]}),o.jsxs("div",{style:h,children:["Status: ",b]})]})})});Ct.displayName="SeatTooltip";const Ut=({config:n,configUrl:r,floorId:u,onFloorChange:i,reservedSeats:m=[],unavailableSeats:b=[],selectedSeats:f,onSeatSelect:v,onSeatDeselect:y,onSelectionChange:a,colorOverrides:s,showTooltip:g=!0,zoomEnabled:h=!0,className:M="",onConfigLoad:C,onError:R,showFloorSelector:D,floorSelectorPosition:V="top-left",floorSelectorClassName:_,showAllFloorsOption:G=!0,allFloorsLabel:U="All",fitToView:P=!0,fitPadding:W=40,showZoomControls:ot=!0,zoomControlsPosition:it="bottom-right",zoomControlsClassName:jt,maxZoom:N=3,zoomStep:Z=.25,touchEnabled:Mt=!0})=>{const st=e.useRef(null),ut=e.useRef(null),w=gt(ut),[X,ht]=e.useState(new Set),[j,A]=e.useState(1),[k,T]=e.useState({x:0,y:0}),[kt,Rt]=e.useState(null),[Et,It]=e.useState(1),K=e.useRef({width:0,height:0}),[z,dt]=e.useState({visible:!1,x:0,y:0,seat:null,state:"available"}),{config:Nt,loading:Lt,error:B}=pt(r),l=n||Nt,rt=u!==void 0,E=rt?u||null:kt,J=f!==void 0,Tt=e.useCallback(t=>{rt||Rt(t),i?.(t)},[rt,i]),ct=l?.floors||[],Dt=D!==void 0?D:ct.length>1,Q=e.useMemo(()=>l?{...l.colors,...s}:{...mt,...s},[l,s]),Y=e.useMemo(()=>{if(!l)return[];let t=l.seats.filter(c=>c.state!=="hidden");return E&&(t=t.filter(c=>c.floorId===E||!c.floorId&&E==="floor_default")),t},[l,E]),tt=e.useMemo(()=>l?.stages?E?l.stages.filter(t=>t.floorId===E||!t.floorId&&E==="floor_default"):l.stages:[],[l,E]),L=e.useMemo(()=>{if(!l||Y.length===0&&tt.length===0)return null;const t=12;let c=1/0,x=1/0,d=-1/0,p=-1/0;return Y.forEach(S=>{c=Math.min(c,S.position.x-t),x=Math.min(x,S.position.y-t),d=Math.max(d,S.position.x+t),p=Math.max(p,S.position.y+t)}),tt.forEach(S=>{c=Math.min(c,S.position.x),x=Math.min(x,S.position.y),d=Math.max(d,S.position.x+(S.config?.width||200)),p=Math.max(p,S.position.y+(S.config?.height||100))}),{minX:c,minY:x,maxX:d,maxY:p,width:d-c,height:p-x}},[l,Y,tt]);e.useEffect(()=>{if(!P||!l||!L||w.width===0||w.height===0)return;const t=Math.abs(w.width-K.current.width),c=Math.abs(w.height-K.current.height);if(!(K.current.width===0)&&t<10&&c<10)return;K.current=w;const d=w.width,p=w.height,S=d-W*2,q=p-W*2,et=S/L.width,lt=q/L.height,nt=Math.min(et,lt,N),$t=L.minX+L.width/2,Ht=L.minY+L.height/2,qt=d/2,Vt=p/2,_t=qt-$t*nt,Gt=Vt-Ht*nt;A(nt),T({x:_t,y:Gt}),It(nt)},[P,l,L,W,N,w,E]);const O=e.useMemo(()=>{const t=new Set(m),c=new Set(b);return{reserved:t,unavailable:c}},[m,b]),at=e.useMemo(()=>f?new Set(f):null,[f]),$=e.useCallback(t=>{const c=t.id,x=t.seatNumber||"";return O.unavailable.has(c)||O.unavailable.has(x)?"unavailable":O.reserved.has(c)||O.reserved.has(x)?"reserved":X.has(c)?"selected":t.state},[O,X]);e.useEffect(()=>{l&&C&&C(l)},[l,C]),e.useEffect(()=>{B&&R&&R(B)},[B,R]),e.useEffect(()=>{J&&at&&ht(at)},[J,at]);const Xt=e.useCallback(t=>{const c=$(t);if(c!=="available"&&c!=="selected")return;const x=X.has(t.id);J||ht(d=>{const p=new Set(d);return x?p.delete(t.id):p.add(t.id),p}),x?y?.(t):(v?.(t),v||console.log("Seat selected:",t))},[$,X,J,v,y]),H=e.useMemo(()=>l?Y.filter(t=>X.has(t.id)):[],[Y,X]);e.useEffect(()=>{a?.(H)},[H,a]);const F=Et,Yt=e.useCallback(()=>{if(!h)return;const t=Math.min(j+Z,N);if(t!==j){const c=w.width||l?.canvas.width||800,x=w.height||l?.canvas.height||600,d=c/2,p=x/2,S={x:(d-k.x)/j,y:(p-k.y)/j};A(t),T({x:d-S.x*t,y:p-S.y*t})}},[h,j,Z,N,w,l,k]),Ft=e.useCallback(()=>{if(!h)return;const t=Math.max(j-Z,F);if(t!==j){const c=w.width||l?.canvas.width||800,x=w.height||l?.canvas.height||600,d=c/2,p=x/2,S={x:(d-k.x)/j,y:(p-k.y)/j};A(t),T({x:d-S.x*t,y:p-S.y*t})}},[h,j,Z,F,w,l,k]),Pt=e.useCallback(t=>{T({x:t.target.x(),y:t.target.y()})},[]),Wt=e.useCallback(t=>{if(!h)return;t.evt.preventDefault();const c=st.current;if(!c)return;const x=c.scaleX(),d=c.getPointerPosition();if(!d)return;const p=1.1,S=t.evt.deltaY>0?x/p:x*p,q=Math.min(Math.max(S,F),N),et={x:(d.x-k.x)/x,y:(d.y-k.y)/x},lt={x:d.x-et.x*q,y:d.y-et.y*q};A(q),T(lt)},[h,k,F,N]);yt(st,{enabled:Mt&&h,minScale:F,maxScale:N,currentScale:j,currentPosition:k,onScaleChange:(t,c)=>{A(t),T(c)},onPositionChange:t=>{T(t)}});const At=e.useCallback((t,c)=>{if(!g)return;const x=c.target.getStage();if(!x)return;const d=x.getPointerPosition();if(!d)return;const p=x.container().getBoundingClientRect();dt({visible:!0,x:p.left+d.x,y:p.top+d.y,seat:t,state:$(t)})},[g,$]),zt=e.useCallback(()=>{dt(t=>({...t,visible:!1}))},[]);if(Lt)return o.jsx("div",{className:`flex items-center justify-center h-full ${M}`,children:o.jsx("p",{children:"Loading seat map..."})});if(B)return o.jsx("div",{className:`flex items-center justify-center h-full ${M}`,children:o.jsxs("p",{className:"text-red-500",children:["Error loading seat map: ",B.message]})});if(!l)return o.jsx("div",{className:`flex items-center justify-center h-full ${M}`,children:o.jsx("p",{children:"No configuration provided"})});const Bt=w.width||l.canvas.width,Ot=w.height||l.canvas.height;return o.jsxs("div",{ref:ut,className:`relative ${M}`,style:{width:"100%",height:"100%"},children:[Dt&&ct.length>0&&o.jsx(vt,{floors:ct,currentFloorId:E,onFloorChange:Tt,showAllOption:G,allLabel:U,position:V,className:_}),o.jsxs(I.Stage,{ref:st,width:Bt,height:Ot,scaleX:j,scaleY:j,x:k.x,y:k.y,draggable:!0,onDragEnd:Pt,onWheel:Wt,style:{backgroundColor:l.canvas.backgroundColor,cursor:"grab"},children:[o.jsx(I.Layer,{listening:!1,children:tt.map(t=>o.jsx(St,{stage:t,stageColor:Q.stageColor},t.id))}),o.jsx(I.Layer,{children:Y.map(t=>o.jsx(bt,{seat:t,state:$(t),colors:Q,onClick:Xt,onMouseEnter:At,onMouseLeave:zt},t.id))})]}),g&&o.jsx(Ct,{visible:z.visible,x:z.x,y:z.y,seat:z.seat,currency:Q.currency,state:z.state}),ot&&h&&o.jsx(wt,{scale:j,minScale:F,maxScale:N,onZoomIn:Yt,onZoomOut:Ft,position:it,className:jt}),H.length>0&&o.jsxs("div",{className:"absolute top-4 right-4 bg-white dark:bg-gray-800 p-4 rounded shadow-lg",children:[o.jsxs("h3",{className:"font-semibold mb-2",children:["Selected Seats (",H.length,")"]}),o.jsx("div",{className:"max-h-48 overflow-y-auto space-y-1",children:H.map(t=>o.jsxs("div",{className:"text-sm",children:[t.seatNumber,t.price&&` - ${Q.currency} ${t.price.toFixed(2)}`]},t.id))})]})]})};exports.DEFAULT_COLORS=mt;exports.SeatMapViewer=Ut;exports.useConfigFetcher=pt;exports.useContainerSize=gt;exports.useTouchGestures=yt;
package/dist/index.mjs CHANGED
@@ -1,97 +1,97 @@
1
1
  import { jsx as h, jsxs as w } from "react/jsx-runtime";
2
- import { useState as L, useEffect as W, useRef as z, useCallback as I, useMemo as T, memo as U } from "react";
3
- import { Stage as Gt, Layer as gt, Group as Ut, Rect as mt, Text as Kt, Circle as Jt } from "react-konva";
4
- function Qt(e) {
5
- const [o, d] = L(null), [i, m] = L(!1), [b, p] = L(null), S = async () => {
2
+ import { useState as E, useEffect as T, useRef as F, useCallback as N, useMemo as Y, memo as U } from "react";
3
+ import { Stage as Qt, Layer as mt, Group as te, Rect as wt, Text as bt, Circle as ee } from "react-konva";
4
+ function ne(e) {
5
+ const [i, a] = E(null), [n, x] = E(!1), [m, u] = E(null), v = async () => {
6
6
  if (e) {
7
- m(!0), p(null);
7
+ x(!0), u(null);
8
8
  try {
9
9
  const y = await fetch(e);
10
10
  if (!y.ok)
11
11
  throw new Error(`Failed to fetch config: ${y.statusText}`);
12
12
  const s = await y.json();
13
- d(s);
13
+ a(s);
14
14
  } catch (y) {
15
15
  const s = y instanceof Error ? y : new Error("Unknown error occurred");
16
- p(s), console.error("Failed to fetch seat map config:", s);
16
+ u(s), console.error("Failed to fetch seat map config:", s);
17
17
  } finally {
18
- m(!1);
18
+ x(!1);
19
19
  }
20
20
  }
21
21
  };
22
- return W(() => {
23
- S();
22
+ return T(() => {
23
+ v();
24
24
  }, [e]), {
25
- config: o,
26
- loading: i,
27
- error: b,
28
- refetch: S
25
+ config: i,
26
+ loading: n,
27
+ error: m,
28
+ refetch: v
29
29
  };
30
30
  }
31
- function te(e) {
32
- const [o, d] = L({ width: 0, height: 0 });
33
- return W(() => {
34
- const i = e.current;
35
- if (!i) return;
36
- const { width: m, height: b } = i.getBoundingClientRect();
37
- m > 0 && b > 0 && d({ width: m, height: b });
38
- const p = new ResizeObserver((S) => {
39
- const y = S[0];
31
+ function oe(e) {
32
+ const [i, a] = E({ width: 0, height: 0 });
33
+ return T(() => {
34
+ const n = e.current;
35
+ if (!n) return;
36
+ const { width: x, height: m } = n.getBoundingClientRect();
37
+ x > 0 && m > 0 && a({ width: x, height: m });
38
+ const u = new ResizeObserver((v) => {
39
+ const y = v[0];
40
40
  if (!y) return;
41
- const { width: s, height: n } = y.contentRect;
42
- s > 0 && n > 0 && d((a) => a.width === s && a.height === n ? a : { width: s, height: n });
41
+ const { width: s, height: o } = y.contentRect;
42
+ s > 0 && o > 0 && a((g) => g.width === s && g.height === o ? g : { width: s, height: o });
43
43
  });
44
- return p.observe(i), () => {
45
- p.disconnect();
44
+ return u.observe(n), () => {
45
+ u.disconnect();
46
46
  };
47
- }, [e]), o;
47
+ }, [e]), i;
48
48
  }
49
- function yt(e, o) {
50
- return Math.sqrt(Math.pow(o.x - e.x, 2) + Math.pow(o.y - e.y, 2));
49
+ function vt(e, i) {
50
+ return Math.sqrt(Math.pow(i.x - e.x, 2) + Math.pow(i.y - e.y, 2));
51
51
  }
52
- function xt(e, o) {
52
+ function St(e, i) {
53
53
  return {
54
- x: (e.x + o.x) / 2,
55
- y: (e.y + o.y) / 2
54
+ x: (e.x + i.x) / 2,
55
+ y: (e.y + i.y) / 2
56
56
  };
57
57
  }
58
- function ee(e, o) {
59
- const d = z(null), i = z(null), m = z(1);
60
- W(() => {
61
- const b = e.current;
62
- if (!b || !o.enabled) return;
63
- const p = b.container(), S = (n) => {
64
- if (n.touches.length === 2) {
65
- n.preventDefault();
66
- const a = { x: n.touches[0].clientX, y: n.touches[0].clientY }, g = { x: n.touches[1].clientX, y: n.touches[1].clientY };
67
- d.current = yt(a, g), i.current = xt(a, g), m.current = o.currentScale;
58
+ function ie(e, i) {
59
+ const a = F(null), n = F(null), x = F(1);
60
+ T(() => {
61
+ const m = e.current;
62
+ if (!m || !i.enabled) return;
63
+ const u = m.container(), v = (o) => {
64
+ if (o.touches.length === 2) {
65
+ o.preventDefault();
66
+ const g = { x: o.touches[0].clientX, y: o.touches[0].clientY }, l = { x: o.touches[1].clientX, y: o.touches[1].clientY };
67
+ a.current = vt(g, l), n.current = St(g, l), x.current = i.currentScale;
68
68
  }
69
- }, y = (n) => {
70
- if (n.touches.length !== 2) return;
71
- n.preventDefault();
72
- const a = { x: n.touches[0].clientX, y: n.touches[0].clientY }, g = { x: n.touches[1].clientX, y: n.touches[1].clientY }, N = yt(a, g), C = xt(a, g);
73
- if (d.current !== null && i.current !== null) {
74
- const D = N / d.current, $ = Math.min(
75
- Math.max(o.currentScale * D, o.minScale),
76
- o.maxScale
77
- ), K = p.getBoundingClientRect(), J = C.x - K.left, Q = C.y - K.top, H = o.currentScale, P = {
78
- x: (J - o.currentPosition.x) / H,
79
- y: (Q - o.currentPosition.y) / H
80
- }, st = C.x - i.current.x, ct = C.y - i.current.y, at = {
81
- x: J - P.x * $ + st,
82
- y: Q - P.y * $ + ct
69
+ }, y = (o) => {
70
+ if (o.touches.length !== 2) return;
71
+ o.preventDefault();
72
+ const g = { x: o.touches[0].clientX, y: o.touches[0].clientY }, l = { x: o.touches[1].clientX, y: o.touches[1].clientY }, k = vt(g, l), C = St(g, l);
73
+ if (a.current !== null && n.current !== null) {
74
+ const D = k / a.current, P = Math.min(
75
+ Math.max(i.currentScale * D, i.minScale),
76
+ i.maxScale
77
+ ), K = u.getBoundingClientRect(), J = C.x - K.left, Q = C.y - K.top, tt = i.currentScale, z = {
78
+ x: (J - i.currentPosition.x) / tt,
79
+ y: (Q - i.currentPosition.y) / tt
80
+ }, $ = C.x - n.current.x, at = C.y - n.current.y, lt = {
81
+ x: J - z.x * P + $,
82
+ y: Q - z.y * P + at
83
83
  };
84
- o.onScaleChange($, at), d.current = N, i.current = C;
84
+ i.onScaleChange(P, lt), a.current = k, n.current = C;
85
85
  }
86
- }, s = (n) => {
87
- n.touches.length < 2 && (d.current = null, i.current = null);
86
+ }, s = (o) => {
87
+ o.touches.length < 2 && (a.current = null, n.current = null);
88
88
  };
89
- return p.addEventListener("touchstart", S, { passive: !1 }), p.addEventListener("touchmove", y, { passive: !1 }), p.addEventListener("touchend", s), () => {
90
- p.removeEventListener("touchstart", S), p.removeEventListener("touchmove", y), p.removeEventListener("touchend", s);
89
+ return u.addEventListener("touchstart", v, { passive: !1 }), u.addEventListener("touchmove", y, { passive: !1 }), u.addEventListener("touchend", s), () => {
90
+ u.removeEventListener("touchstart", v), u.removeEventListener("touchmove", y), u.removeEventListener("touchend", s);
91
91
  };
92
- }, [e, o]);
92
+ }, [e, i]);
93
93
  }
94
- const ne = {
94
+ const re = {
95
95
  canvasBackground: "#1a1a1a",
96
96
  stageColor: "#808080",
97
97
  seatAvailable: "#2C2B30",
@@ -101,45 +101,45 @@ const ne = {
101
101
  seatHidden: "#4a4a4a",
102
102
  gridLines: "#404040",
103
103
  currency: "KD"
104
- }, bt = U(({ seat: e, state: o, colors: d, onClick: i, onMouseEnter: m, onMouseLeave: b }) => {
104
+ }, Ct = U(({ seat: e, state: i, colors: a, onClick: n, onMouseEnter: x, onMouseLeave: m }) => {
105
105
  const y = {
106
- available: d.seatAvailable,
107
- reserved: d.seatReserved,
108
- selected: d.seatSelected,
109
- unavailable: d.seatUnavailable,
110
- hidden: d.seatHidden
106
+ available: a.seatAvailable,
107
+ reserved: a.seatReserved,
108
+ selected: a.seatSelected,
109
+ unavailable: a.seatUnavailable,
110
+ hidden: a.seatHidden
111
111
  // Hidden seats are filtered out, but included for type safety
112
- }[o], s = o === "available" || o === "selected", n = I(() => {
113
- s && i(e);
114
- }, [e, i, s]), a = I((C) => {
115
- m(e, C);
112
+ }[i], s = i === "available" || i === "selected", o = N(() => {
113
+ s && n(e);
114
+ }, [e, n, s]), g = N((C) => {
115
+ x(e, C);
116
116
  const D = C.target.getStage();
117
117
  D && s && (D.container().style.cursor = "pointer");
118
- }, [e, m, s]), g = I((C) => {
119
- b();
118
+ }, [e, x, s]), l = N((C) => {
119
+ m();
120
120
  const D = C.target.getStage();
121
121
  D && (D.container().style.cursor = "grab");
122
- }, [b]), N = {
122
+ }, [m]), k = {
123
123
  x: e.position.x,
124
124
  y: e.position.y,
125
125
  fill: y,
126
126
  stroke: "#ffffff",
127
127
  strokeWidth: 1,
128
- onClick: n,
129
- onTap: n,
130
- onMouseEnter: a,
131
- onMouseLeave: g
128
+ onClick: o,
129
+ onTap: o,
130
+ onMouseEnter: g,
131
+ onMouseLeave: l
132
132
  };
133
133
  return e.shape === "circle" ? /* @__PURE__ */ h(
134
- Jt,
134
+ ee,
135
135
  {
136
- ...N,
136
+ ...k,
137
137
  radius: 12
138
138
  }
139
139
  ) : /* @__PURE__ */ h(
140
- mt,
140
+ wt,
141
141
  {
142
- ...N,
142
+ ...k,
143
143
  width: 24,
144
144
  height: 24,
145
145
  offsetX: 12,
@@ -148,47 +148,73 @@ const ne = {
148
148
  }
149
149
  );
150
150
  });
151
- bt.displayName = "ViewerSeat";
152
- const St = U(({ stage: e, stageColor: o }) => /* @__PURE__ */ w(Ut, { x: e.position.x, y: e.position.y, children: [
153
- /* @__PURE__ */ h(
154
- mt,
155
- {
156
- width: e.config.width,
157
- height: e.config.height,
158
- fill: o + "80",
159
- stroke: "#ffffff",
160
- strokeWidth: 2,
161
- cornerRadius: 10
162
- }
163
- ),
164
- /* @__PURE__ */ h(
165
- Kt,
166
- {
167
- text: e.config.label,
168
- x: 0,
169
- y: 0,
170
- width: e.config.width,
171
- height: e.config.height,
172
- fontSize: 24,
173
- fontStyle: "bold",
174
- fill: "#ffffff",
175
- align: "center",
176
- verticalAlign: "middle"
177
- }
178
- )
179
- ] }));
180
- St.displayName = "ViewerStage";
181
- const vt = U(({
151
+ Ct.displayName = "ViewerSeat";
152
+ const Mt = U(({ stage: e, stageColor: i }) => {
153
+ const a = (m) => ({
154
+ stage: "🎭",
155
+ table: "⬜",
156
+ wall: "▬",
157
+ barrier: "🛡️",
158
+ "dj-booth": "🎵",
159
+ bar: "🍷",
160
+ "entry-exit": "🚪",
161
+ custom: "➕"
162
+ })[m || "stage"] || "🎭", n = e.config.color || i, x = a(e.config.objectType);
163
+ return /* @__PURE__ */ w(te, { x: e.position.x, y: e.position.y, rotation: e.config.rotation || 0, children: [
164
+ /* @__PURE__ */ h(
165
+ wt,
166
+ {
167
+ width: e.config.width,
168
+ height: e.config.height,
169
+ fill: n + "80",
170
+ stroke: "#ffffff",
171
+ strokeWidth: 2,
172
+ cornerRadius: 10
173
+ }
174
+ ),
175
+ /* @__PURE__ */ h(
176
+ bt,
177
+ {
178
+ text: x,
179
+ x: 0,
180
+ y: 0,
181
+ width: e.config.width,
182
+ height: e.config.height * 0.4,
183
+ fontSize: 32,
184
+ fill: "#ffffff",
185
+ align: "center",
186
+ verticalAlign: "middle"
187
+ }
188
+ ),
189
+ /* @__PURE__ */ h(
190
+ bt,
191
+ {
192
+ text: e.config.label,
193
+ x: 0,
194
+ y: e.config.height * 0.4,
195
+ width: e.config.width,
196
+ height: e.config.height * 0.6,
197
+ fontSize: 20,
198
+ fontStyle: "bold",
199
+ fill: "#ffffff",
200
+ align: "center",
201
+ verticalAlign: "middle"
202
+ }
203
+ )
204
+ ] });
205
+ });
206
+ Mt.displayName = "ViewerStage";
207
+ const kt = U(({
182
208
  floors: e,
183
- currentFloorId: o,
184
- onFloorChange: d,
185
- showAllOption: i,
186
- allLabel: m,
187
- position: b,
188
- className: p
209
+ currentFloorId: i,
210
+ onFloorChange: a,
211
+ showAllOption: n,
212
+ allLabel: x,
213
+ position: m,
214
+ className: u
189
215
  }) => {
190
- const S = T(
191
- () => [...e].sort((g, N) => g.order - N.order),
216
+ const v = Y(
217
+ () => [...e].sort((l, k) => l.order - k.order),
192
218
  [e]
193
219
  ), s = {
194
220
  position: "absolute",
@@ -205,8 +231,8 @@ const vt = U(({
205
231
  "top-right": { top: 0, right: 0 },
206
232
  "bottom-left": { bottom: 0, left: 0 },
207
233
  "bottom-right": { bottom: 0, right: 0 }
208
- }[b]
209
- }, n = {
234
+ }[m]
235
+ }, o = {
210
236
  padding: "10px 16px",
211
237
  fontSize: "14px",
212
238
  fontWeight: 500,
@@ -218,42 +244,42 @@ const vt = U(({
218
244
  transition: "all 0.2s ease",
219
245
  minHeight: "44px",
220
246
  touchAction: "manipulation"
221
- }, a = {
222
- ...n,
247
+ }, g = {
248
+ ...o,
223
249
  backgroundColor: "#3A7DE5",
224
250
  borderColor: "#3A7DE5"
225
251
  };
226
- return /* @__PURE__ */ w("div", { className: p, style: s, children: [
227
- i && /* @__PURE__ */ h(
252
+ return /* @__PURE__ */ w("div", { className: u, style: s, children: [
253
+ n && /* @__PURE__ */ h(
228
254
  "button",
229
255
  {
230
256
  type: "button",
231
- onClick: () => d(null),
232
- style: o === null ? a : n,
233
- children: m
257
+ onClick: () => a(null),
258
+ style: i === null ? g : o,
259
+ children: x
234
260
  }
235
261
  ),
236
- S.map((g) => /* @__PURE__ */ h(
262
+ v.map((l) => /* @__PURE__ */ h(
237
263
  "button",
238
264
  {
239
265
  type: "button",
240
- onClick: () => d(g.id),
241
- style: o === g.id ? a : n,
242
- children: g.name
266
+ onClick: () => a(l.id),
267
+ style: i === l.id ? g : o,
268
+ children: l.name
243
269
  },
244
- g.id
270
+ l.id
245
271
  ))
246
272
  ] });
247
273
  });
248
- vt.displayName = "FloorSelectorBar";
249
- const wt = U(({
274
+ kt.displayName = "FloorSelectorBar";
275
+ const It = U(({
250
276
  scale: e,
251
- minScale: o,
252
- maxScale: d,
253
- onZoomIn: i,
254
- onZoomOut: m,
255
- position: b,
256
- className: p
277
+ minScale: i,
278
+ maxScale: a,
279
+ onZoomIn: n,
280
+ onZoomOut: x,
281
+ position: m,
282
+ className: u
257
283
  }) => {
258
284
  const y = {
259
285
  position: "absolute",
@@ -270,7 +296,7 @@ const wt = U(({
270
296
  "top-right": { top: 0, right: 0 },
271
297
  "bottom-left": { bottom: 0, left: 0 },
272
298
  "bottom-right": { bottom: 0, right: 0 }
273
- }[b]
299
+ }[m]
274
300
  }, s = {
275
301
  width: "44px",
276
302
  height: "44px",
@@ -288,19 +314,19 @@ const wt = U(({
288
314
  justifyContent: "center",
289
315
  transition: "all 0.2s ease",
290
316
  touchAction: "manipulation"
291
- }, n = {
317
+ }, o = {
292
318
  ...s,
293
319
  opacity: 0.4,
294
320
  cursor: "not-allowed"
295
- }, a = e < d, g = e > o;
296
- return /* @__PURE__ */ w("div", { className: p, style: y, children: [
321
+ }, g = e < a, l = e > i;
322
+ return /* @__PURE__ */ w("div", { className: u, style: y, children: [
297
323
  /* @__PURE__ */ h(
298
324
  "button",
299
325
  {
300
326
  type: "button",
301
- onClick: i,
302
- disabled: !a,
303
- style: a ? s : n,
327
+ onClick: n,
328
+ disabled: !g,
329
+ style: g ? s : o,
304
330
  title: "Zoom In",
305
331
  children: "+"
306
332
  }
@@ -309,29 +335,29 @@ const wt = U(({
309
335
  "button",
310
336
  {
311
337
  type: "button",
312
- onClick: m,
313
- disabled: !g,
314
- style: g ? s : n,
338
+ onClick: x,
339
+ disabled: !l,
340
+ style: l ? s : o,
315
341
  title: "Zoom Out",
316
342
  children: "−"
317
343
  }
318
344
  )
319
345
  ] });
320
346
  });
321
- wt.displayName = "ZoomControls";
322
- const Ct = U(({
347
+ It.displayName = "ZoomControls";
348
+ const Nt = U(({
323
349
  visible: e,
324
- x: o,
325
- y: d,
326
- seat: i,
327
- currency: m,
328
- state: b
350
+ x: i,
351
+ y: a,
352
+ seat: n,
353
+ currency: x,
354
+ state: m
329
355
  }) => {
330
- if (!e || !i) return null;
331
- const p = i.seatNumber || (i.rowLabel && i.columnLabel ? `${i.rowLabel}-${i.columnLabel}` : "N/A"), S = {
356
+ if (!e || !n) return null;
357
+ const u = n.seatNumber || (n.rowLabel && n.columnLabel ? `${n.rowLabel}-${n.columnLabel}` : "N/A"), v = {
332
358
  position: "fixed",
333
- left: `${o + 15}px`,
334
- top: `${d + 15}px`,
359
+ left: `${i + 15}px`,
360
+ top: `${a + 15}px`,
335
361
  zIndex: 1e3,
336
362
  pointerEvents: "none"
337
363
  }, y = {
@@ -346,296 +372,299 @@ const Ct = U(({
346
372
  }, s = {
347
373
  color: "#9ca3af",
348
374
  marginRight: "4px"
349
- }, n = {
375
+ }, o = {
350
376
  fontWeight: 600
351
- }, a = {
377
+ }, g = {
352
378
  color: "#4ade80",
353
379
  fontWeight: 600
354
- }, g = {
380
+ }, l = {
355
381
  fontSize: "11px",
356
382
  color: "#6b7280",
357
383
  textTransform: "capitalize",
358
384
  marginTop: "4px"
359
385
  };
360
- return /* @__PURE__ */ h("div", { style: S, children: /* @__PURE__ */ w("div", { style: y, children: [
361
- i.sectionName && /* @__PURE__ */ w("div", { style: { marginBottom: "4px" }, children: [
386
+ return /* @__PURE__ */ h("div", { style: v, children: /* @__PURE__ */ w("div", { style: y, children: [
387
+ n.sectionName && /* @__PURE__ */ w("div", { style: { marginBottom: "4px" }, children: [
362
388
  /* @__PURE__ */ h("span", { style: s, children: "Section:" }),
363
- /* @__PURE__ */ h("span", { style: { ...n, color: "#3b82f6" }, children: i.sectionName })
389
+ /* @__PURE__ */ h("span", { style: { ...o, color: "#3b82f6" }, children: n.sectionName })
364
390
  ] }),
365
391
  /* @__PURE__ */ w("div", { style: { marginBottom: "4px" }, children: [
366
392
  /* @__PURE__ */ h("span", { style: s, children: "Seat:" }),
367
- /* @__PURE__ */ h("span", { style: n, children: p })
393
+ /* @__PURE__ */ h("span", { style: o, children: u })
368
394
  ] }),
369
- i.price !== void 0 && i.price > 0 && /* @__PURE__ */ w("div", { style: { marginBottom: "4px" }, children: [
395
+ n.price !== void 0 && n.price > 0 && /* @__PURE__ */ w("div", { style: { marginBottom: "4px" }, children: [
370
396
  /* @__PURE__ */ h("span", { style: s, children: "Price:" }),
371
- /* @__PURE__ */ w("span", { style: a, children: [
372
- m,
397
+ /* @__PURE__ */ w("span", { style: g, children: [
398
+ x,
373
399
  " ",
374
- i.price.toFixed(2)
400
+ n.price.toFixed(2)
375
401
  ] })
376
402
  ] }),
377
- /* @__PURE__ */ w("div", { style: g, children: [
403
+ /* @__PURE__ */ w("div", { style: l, children: [
378
404
  "Status: ",
379
- b
405
+ m
380
406
  ] })
381
407
  ] }) });
382
408
  });
383
- Ct.displayName = "SeatTooltip";
384
- const se = ({
409
+ Nt.displayName = "SeatTooltip";
410
+ const le = ({
385
411
  config: e,
386
- configUrl: o,
387
- floorId: d,
388
- onFloorChange: i,
389
- reservedSeats: m = [],
390
- unavailableSeats: b = [],
391
- onSeatSelect: p,
392
- onSeatDeselect: S,
393
- onSelectionChange: y,
394
- colorOverrides: s,
395
- showTooltip: n = !0,
396
- zoomEnabled: a = !0,
397
- className: g = "",
398
- onConfigLoad: N,
399
- onError: C,
412
+ configUrl: i,
413
+ floorId: a,
414
+ onFloorChange: n,
415
+ reservedSeats: x = [],
416
+ unavailableSeats: m = [],
417
+ selectedSeats: u,
418
+ onSeatSelect: v,
419
+ onSeatDeselect: y,
420
+ onSelectionChange: s,
421
+ colorOverrides: o,
422
+ showTooltip: g = !0,
423
+ zoomEnabled: l = !0,
424
+ className: k = "",
425
+ onConfigLoad: C,
426
+ onError: D,
400
427
  // Floor selector props
401
- showFloorSelector: D,
402
- floorSelectorPosition: $ = "top-left",
403
- floorSelectorClassName: K,
404
- showAllFloorsOption: J = !0,
405
- allFloorsLabel: Q = "All",
406
- fitToView: H = !0,
407
- fitPadding: P = 40,
428
+ showFloorSelector: P,
429
+ floorSelectorPosition: K = "top-left",
430
+ floorSelectorClassName: J,
431
+ showAllFloorsOption: Q = !0,
432
+ allFloorsLabel: tt = "All",
433
+ fitToView: z = !0,
434
+ fitPadding: $ = 40,
408
435
  // Zoom controls
409
- showZoomControls: st = !0,
410
- zoomControlsPosition: ct = "bottom-right",
411
- zoomControlsClassName: at,
412
- maxZoom: X = 3,
413
- zoomStep: tt = 0.25,
436
+ showZoomControls: at = !0,
437
+ zoomControlsPosition: lt = "bottom-right",
438
+ zoomControlsClassName: Dt,
439
+ maxZoom: L = 3,
440
+ zoomStep: et = 0.25,
414
441
  // Touch gestures
415
- touchEnabled: Mt = !0
442
+ touchEnabled: Rt = !0
416
443
  }) => {
417
- const lt = z(null), ft = z(null), v = te(ft), [B, kt] = L(/* @__PURE__ */ new Set()), [M, j] = L(1), [k, E] = L({ x: 0, y: 0 }), [It, Nt] = L(null), [Dt, Rt] = L(1), et = z({ width: 0, height: 0 }), [O, pt] = L({ visible: !1, x: 0, y: 0, seat: null, state: "available" }), { config: Lt, loading: Xt, error: V } = Qt(o), c = e || Lt, ht = d !== void 0, R = ht ? d || null : It, Yt = I((t) => {
418
- ht || Nt(t), i?.(t);
419
- }, [ht, i]), dt = c?.floors || [], Et = D !== void 0 ? D : dt.length > 1, nt = T(
420
- () => c ? { ...c.colors, ...s } : { ...ne, ...s },
421
- [c, s]
422
- ), F = T(() => {
444
+ const ht = F(null), gt = F(null), S = oe(gt), [j, yt] = E(/* @__PURE__ */ new Set()), [M, H] = E(1), [I, W] = E({ x: 0, y: 0 }), [Et, Lt] = E(null), [Xt, Yt] = E(1), nt = F({ width: 0, height: 0 }), [O, xt] = E({ visible: !1, x: 0, y: 0, seat: null, state: "available" }), { config: Tt, loading: Wt, error: V } = ne(i), c = e || Tt, dt = a !== void 0, R = dt ? a || null : Et, ot = u !== void 0, Pt = N((t) => {
445
+ dt || Lt(t), n?.(t);
446
+ }, [dt, n]), ut = c?.floors || [], jt = P !== void 0 ? P : ut.length > 1, it = Y(
447
+ () => c ? { ...c.colors, ...o } : { ...re, ...o },
448
+ [c, o]
449
+ ), A = Y(() => {
423
450
  if (!c) return [];
424
451
  let t = c.seats.filter((r) => r.state !== "hidden");
425
452
  return R && (t = t.filter(
426
453
  (r) => r.floorId === R || !r.floorId && R === "floor_default"
427
454
  )), t;
428
- }, [c, R]), ot = T(() => c?.stages ? R ? c.stages.filter(
455
+ }, [c, R]), rt = Y(() => c?.stages ? R ? c.stages.filter(
429
456
  (t) => t.floorId === R || !t.floorId && R === "floor_default"
430
- ) : c.stages : [], [c, R]), Y = T(() => {
431
- if (!c || F.length === 0 && ot.length === 0)
457
+ ) : c.stages : [], [c, R]), X = Y(() => {
458
+ if (!c || A.length === 0 && rt.length === 0)
432
459
  return null;
433
460
  const t = 12;
434
- let r = 1 / 0, u = 1 / 0, l = -1 / 0, f = -1 / 0;
435
- return F.forEach((x) => {
436
- r = Math.min(r, x.position.x - t), u = Math.min(u, x.position.y - t), l = Math.max(l, x.position.x + t), f = Math.max(f, x.position.y + t);
437
- }), ot.forEach((x) => {
438
- r = Math.min(r, x.position.x), u = Math.min(u, x.position.y), l = Math.max(l, x.position.x + (x.config?.width || 200)), f = Math.max(f, x.position.y + (x.config?.height || 100));
439
- }), { minX: r, minY: u, maxX: l, maxY: f, width: l - r, height: f - u };
440
- }, [c, F, ot]);
441
- W(() => {
442
- if (!H || !c || !Y || v.width === 0 || v.height === 0) return;
443
- const t = Math.abs(v.width - et.current.width), r = Math.abs(v.height - et.current.height);
444
- if (!(et.current.width === 0) && t < 10 && r < 10) return;
445
- et.current = v;
446
- const l = v.width, f = v.height, x = l - P * 2, G = f - P * 2, it = x / Y.width, ut = G / Y.height, rt = Math.min(it, ut, X), jt = Y.minX + Y.width / 2, Ot = Y.minY + Y.height / 2, Vt = l / 2, Zt = f / 2, _t = Vt - jt * rt, qt = Zt - Ot * rt;
447
- j(rt), E({ x: _t, y: qt }), Rt(rt);
448
- }, [H, c, Y, P, X, v, R]);
449
- const Z = T(() => {
450
- const t = new Set(m), r = new Set(b);
461
+ let r = 1 / 0, f = 1 / 0, d = -1 / 0, p = -1 / 0;
462
+ return A.forEach((b) => {
463
+ r = Math.min(r, b.position.x - t), f = Math.min(f, b.position.y - t), d = Math.max(d, b.position.x + t), p = Math.max(p, b.position.y + t);
464
+ }), rt.forEach((b) => {
465
+ r = Math.min(r, b.position.x), f = Math.min(f, b.position.y), d = Math.max(d, b.position.x + (b.config?.width || 200)), p = Math.max(p, b.position.y + (b.config?.height || 100));
466
+ }), { minX: r, minY: f, maxX: d, maxY: p, width: d - r, height: p - f };
467
+ }, [c, A, rt]);
468
+ T(() => {
469
+ if (!z || !c || !X || S.width === 0 || S.height === 0) return;
470
+ const t = Math.abs(S.width - nt.current.width), r = Math.abs(S.height - nt.current.height);
471
+ if (!(nt.current.width === 0) && t < 10 && r < 10) return;
472
+ nt.current = S;
473
+ const d = S.width, p = S.height, b = d - $ * 2, G = p - $ * 2, st = b / X.width, pt = G / X.height, ct = Math.min(st, pt, L), _t = X.minX + X.width / 2, qt = X.minY + X.height / 2, Gt = d / 2, Ut = p / 2, Kt = Gt - _t * ct, Jt = Ut - qt * ct;
474
+ H(ct), W({ x: Kt, y: Jt }), Yt(ct);
475
+ }, [z, c, X, $, L, S, R]);
476
+ const Z = Y(() => {
477
+ const t = new Set(x), r = new Set(m);
451
478
  return { reserved: t, unavailable: r };
452
- }, [m, b]), _ = I((t) => {
453
- const r = t.id, u = t.seatNumber || "";
454
- return Z.unavailable.has(r) || Z.unavailable.has(u) ? "unavailable" : Z.reserved.has(r) || Z.reserved.has(u) ? "reserved" : B.has(r) ? "selected" : t.state;
455
- }, [Z, B]);
456
- W(() => {
457
- c && N && N(c);
458
- }, [c, N]), W(() => {
459
- V && C && C(V);
460
- }, [V, C]);
461
- const Tt = I((t) => {
479
+ }, [x, m]), ft = Y(() => u ? new Set(u) : null, [u]), _ = N((t) => {
480
+ const r = t.id, f = t.seatNumber || "";
481
+ return Z.unavailable.has(r) || Z.unavailable.has(f) ? "unavailable" : Z.reserved.has(r) || Z.reserved.has(f) ? "reserved" : j.has(r) ? "selected" : t.state;
482
+ }, [Z, j]);
483
+ T(() => {
484
+ c && C && C(c);
485
+ }, [c, C]), T(() => {
486
+ V && D && D(V);
487
+ }, [V, D]), T(() => {
488
+ ot && ft && yt(ft);
489
+ }, [ot, ft]);
490
+ const At = N((t) => {
462
491
  const r = _(t);
463
492
  if (r !== "available" && r !== "selected")
464
493
  return;
465
- const u = B.has(t.id);
466
- kt((l) => {
467
- const f = new Set(l);
468
- return u ? f.delete(t.id) : f.add(t.id), f;
469
- }), u ? S?.(t) : (p?.(t), p || console.log("Seat selected:", t));
470
- }, [_, B, p, S]), q = T(() => c ? F.filter((t) => B.has(t.id)) : [], [F, B]);
471
- W(() => {
472
- y?.(q);
473
- }, [q, y]);
474
- const A = Dt, Wt = I(() => {
475
- if (!a) return;
476
- const t = Math.min(M + tt, X);
494
+ const f = j.has(t.id);
495
+ ot || yt((d) => {
496
+ const p = new Set(d);
497
+ return f ? p.delete(t.id) : p.add(t.id), p;
498
+ }), f ? y?.(t) : (v?.(t), v || console.log("Seat selected:", t));
499
+ }, [_, j, ot, v, y]), q = Y(() => c ? A.filter((t) => j.has(t.id)) : [], [A, j]);
500
+ T(() => {
501
+ s?.(q);
502
+ }, [q, s]);
503
+ const B = Xt, Bt = N(() => {
504
+ if (!l) return;
505
+ const t = Math.min(M + et, L);
477
506
  if (t !== M) {
478
- const r = v.width || c?.canvas.width || 800, u = v.height || c?.canvas.height || 600, l = r / 2, f = u / 2, x = {
479
- x: (l - k.x) / M,
480
- y: (f - k.y) / M
507
+ const r = S.width || c?.canvas.width || 800, f = S.height || c?.canvas.height || 600, d = r / 2, p = f / 2, b = {
508
+ x: (d - I.x) / M,
509
+ y: (p - I.y) / M
481
510
  };
482
- j(t), E({
483
- x: l - x.x * t,
484
- y: f - x.y * t
511
+ H(t), W({
512
+ x: d - b.x * t,
513
+ y: p - b.y * t
485
514
  });
486
515
  }
487
- }, [a, M, tt, X, v, c, k]), Pt = I(() => {
488
- if (!a) return;
489
- const t = Math.max(M - tt, A);
516
+ }, [l, M, et, L, S, c, I]), Ft = N(() => {
517
+ if (!l) return;
518
+ const t = Math.max(M - et, B);
490
519
  if (t !== M) {
491
- const r = v.width || c?.canvas.width || 800, u = v.height || c?.canvas.height || 600, l = r / 2, f = u / 2, x = {
492
- x: (l - k.x) / M,
493
- y: (f - k.y) / M
520
+ const r = S.width || c?.canvas.width || 800, f = S.height || c?.canvas.height || 600, d = r / 2, p = f / 2, b = {
521
+ x: (d - I.x) / M,
522
+ y: (p - I.y) / M
494
523
  };
495
- j(t), E({
496
- x: l - x.x * t,
497
- y: f - x.y * t
524
+ H(t), W({
525
+ x: d - b.x * t,
526
+ y: p - b.y * t
498
527
  });
499
528
  }
500
- }, [a, M, tt, A, v, c, k]), Bt = I((t) => {
501
- E({
529
+ }, [l, M, et, B, S, c, I]), zt = N((t) => {
530
+ W({
502
531
  x: t.target.x(),
503
532
  y: t.target.y()
504
533
  });
505
- }, []), Ft = I((t) => {
506
- if (!a) return;
534
+ }, []), $t = N((t) => {
535
+ if (!l) return;
507
536
  t.evt.preventDefault();
508
- const r = lt.current;
537
+ const r = ht.current;
509
538
  if (!r) return;
510
- const u = r.scaleX(), l = r.getPointerPosition();
511
- if (!l) return;
512
- const f = 1.1, x = t.evt.deltaY > 0 ? u / f : u * f, G = Math.min(Math.max(x, A), X), it = {
513
- x: (l.x - k.x) / u,
514
- y: (l.y - k.y) / u
515
- }, ut = {
516
- x: l.x - it.x * G,
517
- y: l.y - it.y * G
539
+ const f = r.scaleX(), d = r.getPointerPosition();
540
+ if (!d) return;
541
+ const p = 1.1, b = t.evt.deltaY > 0 ? f / p : f * p, G = Math.min(Math.max(b, B), L), st = {
542
+ x: (d.x - I.x) / f,
543
+ y: (d.y - I.y) / f
544
+ }, pt = {
545
+ x: d.x - st.x * G,
546
+ y: d.y - st.y * G
518
547
  };
519
- j(G), E(ut);
520
- }, [a, k, A, X]);
521
- ee(lt, {
522
- enabled: Mt && a,
523
- minScale: A,
524
- maxScale: X,
548
+ H(G), W(pt);
549
+ }, [l, I, B, L]);
550
+ ie(ht, {
551
+ enabled: Rt && l,
552
+ minScale: B,
553
+ maxScale: L,
525
554
  currentScale: M,
526
- currentPosition: k,
555
+ currentPosition: I,
527
556
  onScaleChange: (t, r) => {
528
- j(t), E(r);
557
+ H(t), W(r);
529
558
  },
530
559
  onPositionChange: (t) => {
531
- E(t);
560
+ W(t);
532
561
  }
533
562
  });
534
- const At = I((t, r) => {
535
- if (!n) return;
536
- const u = r.target.getStage();
537
- if (!u) return;
538
- const l = u.getPointerPosition();
539
- if (!l) return;
540
- const f = u.container().getBoundingClientRect();
541
- pt({
563
+ const Ht = N((t, r) => {
564
+ if (!g) return;
565
+ const f = r.target.getStage();
566
+ if (!f) return;
567
+ const d = f.getPointerPosition();
568
+ if (!d) return;
569
+ const p = f.container().getBoundingClientRect();
570
+ xt({
542
571
  visible: !0,
543
- x: f.left + l.x,
544
- y: f.top + l.y,
572
+ x: p.left + d.x,
573
+ y: p.top + d.y,
545
574
  seat: t,
546
575
  state: _(t)
547
576
  });
548
- }, [n, _]), zt = I(() => {
549
- pt((t) => ({ ...t, visible: !1 }));
577
+ }, [g, _]), Ot = N(() => {
578
+ xt((t) => ({ ...t, visible: !1 }));
550
579
  }, []);
551
- if (Xt)
552
- return /* @__PURE__ */ h("div", { className: `flex items-center justify-center h-full ${g}`, children: /* @__PURE__ */ h("p", { children: "Loading seat map..." }) });
580
+ if (Wt)
581
+ return /* @__PURE__ */ h("div", { className: `flex items-center justify-center h-full ${k}`, children: /* @__PURE__ */ h("p", { children: "Loading seat map..." }) });
553
582
  if (V)
554
- return /* @__PURE__ */ h("div", { className: `flex items-center justify-center h-full ${g}`, children: /* @__PURE__ */ w("p", { className: "text-red-500", children: [
583
+ return /* @__PURE__ */ h("div", { className: `flex items-center justify-center h-full ${k}`, children: /* @__PURE__ */ w("p", { className: "text-red-500", children: [
555
584
  "Error loading seat map: ",
556
585
  V.message
557
586
  ] }) });
558
587
  if (!c)
559
- return /* @__PURE__ */ h("div", { className: `flex items-center justify-center h-full ${g}`, children: /* @__PURE__ */ h("p", { children: "No configuration provided" }) });
560
- const $t = v.width || c.canvas.width, Ht = v.height || c.canvas.height;
588
+ return /* @__PURE__ */ h("div", { className: `flex items-center justify-center h-full ${k}`, children: /* @__PURE__ */ h("p", { children: "No configuration provided" }) });
589
+ const Vt = S.width || c.canvas.width, Zt = S.height || c.canvas.height;
561
590
  return /* @__PURE__ */ w(
562
591
  "div",
563
592
  {
564
- ref: ft,
565
- className: `relative ${g}`,
593
+ ref: gt,
594
+ className: `relative ${k}`,
566
595
  style: { width: "100%", height: "100%" },
567
596
  children: [
568
- Et && dt.length > 0 && /* @__PURE__ */ h(
569
- vt,
597
+ jt && ut.length > 0 && /* @__PURE__ */ h(
598
+ kt,
570
599
  {
571
- floors: dt,
600
+ floors: ut,
572
601
  currentFloorId: R,
573
- onFloorChange: Yt,
574
- showAllOption: J,
575
- allLabel: Q,
576
- position: $,
577
- className: K
602
+ onFloorChange: Pt,
603
+ showAllOption: Q,
604
+ allLabel: tt,
605
+ position: K,
606
+ className: J
578
607
  }
579
608
  ),
580
609
  /* @__PURE__ */ w(
581
- Gt,
610
+ Qt,
582
611
  {
583
- ref: lt,
584
- width: $t,
585
- height: Ht,
612
+ ref: ht,
613
+ width: Vt,
614
+ height: Zt,
586
615
  scaleX: M,
587
616
  scaleY: M,
588
- x: k.x,
589
- y: k.y,
617
+ x: I.x,
618
+ y: I.y,
590
619
  draggable: !0,
591
- onDragEnd: Bt,
592
- onWheel: Ft,
620
+ onDragEnd: zt,
621
+ onWheel: $t,
593
622
  style: { backgroundColor: c.canvas.backgroundColor, cursor: "grab" },
594
623
  children: [
595
- /* @__PURE__ */ h(gt, { listening: !1, children: ot.map((t) => /* @__PURE__ */ h(
596
- St,
624
+ /* @__PURE__ */ h(mt, { listening: !1, children: rt.map((t) => /* @__PURE__ */ h(
625
+ Mt,
597
626
  {
598
627
  stage: t,
599
- stageColor: nt.stageColor
628
+ stageColor: it.stageColor
600
629
  },
601
630
  t.id
602
631
  )) }),
603
- /* @__PURE__ */ h(gt, { children: F.map((t) => /* @__PURE__ */ h(
604
- bt,
632
+ /* @__PURE__ */ h(mt, { children: A.map((t) => /* @__PURE__ */ h(
633
+ Ct,
605
634
  {
606
635
  seat: t,
607
636
  state: _(t),
608
- colors: nt,
609
- onClick: Tt,
610
- onMouseEnter: At,
611
- onMouseLeave: zt
637
+ colors: it,
638
+ onClick: At,
639
+ onMouseEnter: Ht,
640
+ onMouseLeave: Ot
612
641
  },
613
642
  t.id
614
643
  )) })
615
644
  ]
616
645
  }
617
646
  ),
618
- n && /* @__PURE__ */ h(
619
- Ct,
647
+ g && /* @__PURE__ */ h(
648
+ Nt,
620
649
  {
621
650
  visible: O.visible,
622
651
  x: O.x,
623
652
  y: O.y,
624
653
  seat: O.seat,
625
- currency: nt.currency,
654
+ currency: it.currency,
626
655
  state: O.state
627
656
  }
628
657
  ),
629
- st && a && /* @__PURE__ */ h(
630
- wt,
658
+ at && l && /* @__PURE__ */ h(
659
+ It,
631
660
  {
632
661
  scale: M,
633
- minScale: A,
634
- maxScale: X,
635
- onZoomIn: Wt,
636
- onZoomOut: Pt,
637
- position: ct,
638
- className: at
662
+ minScale: B,
663
+ maxScale: L,
664
+ onZoomIn: Bt,
665
+ onZoomOut: Ft,
666
+ position: lt,
667
+ className: Dt
639
668
  }
640
669
  ),
641
670
  q.length > 0 && /* @__PURE__ */ w("div", { className: "absolute top-4 right-4 bg-white dark:bg-gray-800 p-4 rounded shadow-lg", children: [
@@ -646,7 +675,7 @@ const se = ({
646
675
  ] }),
647
676
  /* @__PURE__ */ h("div", { className: "max-h-48 overflow-y-auto space-y-1", children: q.map((t) => /* @__PURE__ */ w("div", { className: "text-sm", children: [
648
677
  t.seatNumber,
649
- t.price && ` - ${nt.currency} ${t.price.toFixed(2)}`
678
+ t.price && ` - ${it.currency} ${t.price.toFixed(2)}`
650
679
  ] }, t.id)) })
651
680
  ] })
652
681
  ]
@@ -654,9 +683,9 @@ const se = ({
654
683
  );
655
684
  };
656
685
  export {
657
- ne as DEFAULT_COLORS,
658
- se as SeatMapViewer,
659
- Qt as useConfigFetcher,
660
- te as useContainerSize,
661
- ee as useTouchGestures
686
+ re as DEFAULT_COLORS,
687
+ le as SeatMapViewer,
688
+ ne as useConfigFetcher,
689
+ oe as useContainerSize,
690
+ ie as useTouchGestures
662
691
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zonetrix/viewer",
3
- "version": "2.5.0",
3
+ "version": "2.7.0",
4
4
  "type": "module",
5
5
  "description": "Lightweight React component for rendering interactive seat maps",
6
6
  "main": "./dist/index.js",