UNPKG

react-svg-seatmap

Version:

React components that render a highly-customizable seatmap based on a provided SVG

23 lines (22 loc) 17 kB
(function(P,d){typeof exports=="object"&&typeof module<"u"?d(exports,require("react"),require("svg-pan-zoom"),require("lodash"),require("react-selecto")):typeof define=="function"&&define.amd?define(["exports","react","svg-pan-zoom","lodash","react-selecto"],d):(P=typeof globalThis<"u"?globalThis:P||self,d(P.index={},P.React,P.svgPanZoom,P.lodash,P.Selecto))})(this,function(P,d,ce,ae,le){"use strict";var W={exports:{}},z={};/** * @license React * react-jsx-runtime.production.js * * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */var Q;function ie(){if(Q)return z;Q=1;var r=Symbol.for("react.transitional.element"),i=Symbol.for("react.fragment");function v(h,a,b){var T=null;if(b!==void 0&&(T=""+b),a.key!==void 0&&(T=""+a.key),"key"in a){b={};for(var O in a)O!=="key"&&(b[O]=a[O])}else b=a;return a=b.ref,{$$typeof:r,type:h,key:T,ref:a!==void 0?a:null,props:b}}return z.Fragment=i,z.jsx=v,z.jsxs=v,z}var q={};/** * @license React * react-jsx-runtime.development.js * * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */var K;function ue(){return K||(K=1,process.env.NODE_ENV!=="production"&&function(){function r(e){if(e==null)return null;if(typeof e=="function")return e.$$typeof===t?null:e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case C:return"Fragment";case I:return"Profiler";case U:return"StrictMode";case N:return"Suspense";case L:return"SuspenseList";case _:return"Activity"}if(typeof e=="object")switch(typeof e.tag=="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),e.$$typeof){case S:return"Portal";case Y:return(e.displayName||"Context")+".Provider";case p:return(e._context.displayName||"Context")+".Consumer";case B:var l=e.render;return e=e.displayName,e||(e=l.displayName||l.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case D:return l=e.displayName||null,l!==null?l:r(e.type)||"Memo";case s:l=e._payload,e=e._init;try{return r(e(l))}catch{}}return null}function i(e){return""+e}function v(e){try{i(e);var l=!1}catch{l=!0}if(l){l=console;var E=l.error,A=typeof Symbol=="function"&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||"Object";return E.call(l,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",A),i(e)}}function h(e){if(e===C)return"<>";if(typeof e=="object"&&e!==null&&e.$$typeof===s)return"<...>";try{var l=r(e);return l?"<"+l+">":"<...>"}catch{return"<...>"}}function a(){var e=o.A;return e===null?null:e.getOwner()}function b(){return Error("react-stack-top-frame")}function T(e){if(u.call(e,"key")){var l=Object.getOwnPropertyDescriptor(e,"key").get;if(l&&l.isReactWarning)return!1}return e.key!==void 0}function O(e,l){function E(){Z||(Z=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",l))}E.isReactWarning=!0,Object.defineProperty(e,"key",{get:E,configurable:!0})}function w(){var e=r(this.type);return oe[e]||(oe[e]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),e=this.props.ref,e!==void 0?e:null}function g(e,l,E,A,F,G,M,J){return E=G.ref,e={$$typeof:j,type:e,key:l,props:G,_owner:F},(E!==void 0?E:null)!==null?Object.defineProperty(e,"ref",{enumerable:!1,get:w}):Object.defineProperty(e,"ref",{enumerable:!1,value:null}),e._store={},Object.defineProperty(e._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(e,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(e,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:M}),Object.defineProperty(e,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:J}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}function x(e,l,E,A,F,G,M,J){var k=l.children;if(k!==void 0)if(A)if(c(k)){for(A=0;A<k.length;A++)R(k[A]);Object.freeze&&Object.freeze(k)}else console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");else R(k);if(u.call(l,"key")){k=r(e);var V=Object.keys(l).filter(function(_e){return _e!=="key"});A=0<V.length?"{key: someKey, "+V.join(": ..., ")+": ...}":"{key: someKey}",se[k+A]||(V=0<V.length?"{"+V.join(": ..., ")+": ...}":"{}",console.error(`A props object containing a "key" prop is being spread into JSX: let props = %s; <%s {...props} /> React keys must be passed directly to JSX without using spread: let props = %s; <%s key={someKey} {...props} />`,A,k,V,k),se[k+A]=!0)}if(k=null,E!==void 0&&(v(E),k=""+E),T(l)&&(v(l.key),k=""+l.key),"key"in l){E={};for(var X in l)X!=="key"&&(E[X]=l[X])}else E=l;return k&&O(E,typeof e=="function"?e.displayName||e.name||"Unknown":e),g(e,k,G,F,a(),E,M,J)}function R(e){typeof e=="object"&&e!==null&&e.$$typeof===j&&e._store&&(e._store.validated=1)}var m=d,j=Symbol.for("react.transitional.element"),S=Symbol.for("react.portal"),C=Symbol.for("react.fragment"),U=Symbol.for("react.strict_mode"),I=Symbol.for("react.profiler"),p=Symbol.for("react.consumer"),Y=Symbol.for("react.context"),B=Symbol.for("react.forward_ref"),N=Symbol.for("react.suspense"),L=Symbol.for("react.suspense_list"),D=Symbol.for("react.memo"),s=Symbol.for("react.lazy"),_=Symbol.for("react.activity"),t=Symbol.for("react.client.reference"),o=m.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,u=Object.prototype.hasOwnProperty,c=Array.isArray,y=console.createTask?console.createTask:function(){return null};m={"react-stack-bottom-frame":function(e){return e()}};var Z,oe={},ne=m["react-stack-bottom-frame"].bind(m,b)(),re=y(h(b)),se={};q.Fragment=C,q.jsx=function(e,l,E,A,F){var G=1e4>o.recentlyCreatedOwnerStacks++;return x(e,l,E,!1,A,F,G?Error("react-stack-top-frame"):ne,G?y(h(e)):re)},q.jsxs=function(e,l,E,A,F){var G=1e4>o.recentlyCreatedOwnerStacks++;return x(e,l,E,!0,A,F,G?Error("react-stack-top-frame"):ne,G?y(h(e)):re)}}()),q}var $;function fe(){return $||($=1,process.env.NODE_ENV==="production"?W.exports=ie():W.exports=ue()),W.exports}var f=fe();const n={root:"_root_94c36_1",svgContainer:"_svgContainer_94c36_8",controls:"_controls_94c36_18",controlsLeft:"_controlsLeft_94c36_25",controlsRight:"_controlsRight_94c36_31",actionGroup:"_actionGroup_94c36_37",actionGroupUnstyled:"_actionGroupUnstyled_94c36_37",actionButton:"_actionButton_94c36_48",actionButtonSelected:"_actionButtonSelected_94c36_77",icon:"_icon_94c36_92",error:"_error_94c36_101",seatUnavailable:"_seatUnavailable_94c36_105",seatAvailable:"_seatAvailable_94c36_110",seatSelected:"_seatSelected_94c36_117",seatHover:"_seatHover_94c36_126"};function ee(r){var i,v,h="";if(typeof r=="string"||typeof r=="number")h+=r;else if(typeof r=="object")if(Array.isArray(r)){var a=r.length;for(i=0;i<a;i++)r[i]&&(v=ee(r[i]))&&(h&&(h+=" "),h+=v)}else for(v in r)r[v]&&(h&&(h+=" "),h+=v);return h}function H(){for(var r,i,v=0,h="",a=arguments.length;v<a;v++)(r=arguments[v])&&(i=ee(r))&&(h&&(h+=" "),h+=i);return h}const de=r=>{const i=d.useRef(void 0);return d.useEffect(()=>{i.current=r}),i.current},me=({availableSeats:r,selectedSeatIds:i,svg:v,className:h,onSeatSelect:a,onSeatDeselect:b,onSeatHover:T,onSeatHoverEnd:O,allowDragAndPan:w=!0,showZoomControls:g=!0,leftControls:x,rightControls:R})=>{const[m,j]=d.useState(""),[S,C]=d.useState(!1),[U,I]=d.useState(!1),p=de({svgString:m,selectedSeatIds:i,availableSeats:r}),Y=d.useCallback(t=>i&&i.includes(t.id),[i]),B=d.useCallback(t=>r.find(o=>{try{return t.matches(o.cssSelector)}catch{return!1}}),[r]),N=d.useCallback(()=>ce(`.${n.svgContainer} svg`,{dblClickZoomEnabled:!1,mouseWheelZoomEnabled:!0,zoomScaleSensitivity:.5}),[]);d.useEffect(()=>{fetch(v).then(t=>{if(t.ok)return t.text();throw new Error("Unable to fetch SVG")}).then(t=>j(t)).catch(t=>{C(!0),console.error("Failed to load SVG:",t)})},[v]);const L=d.useCallback((t,o)=>{o?(t.classList.remove(n.seatUnavailable),i!=null&&i.includes(o.id)?(t.classList.add(n.seatSelected),t.classList.remove(n.seatAvailable)):(t.classList.add(n.seatAvailable),t.classList.remove(n.seatSelected)),o.color&&t.setAttribute("style",`stroke: ${o.color} !important;${Y(o)?" fill: "+o.color+" !important;":""}`)):(t.classList.add(n.seatUnavailable),t.classList.remove(n.seatAvailable),t.classList.remove(n.seatSelected))},[Y,i]);d.useEffect(()=>{if(!m||S){console.error("No SVG, exiting");return}U&&(document.querySelectorAll(`.${n.svgContainer} circle, .${n.svgContainer} path, .${n.svgContainer} ellipse`).forEach(o=>{const u=B(o);L(o,u)}),I(!1))},[U,B,L,m,S]),d.useEffect(()=>{if(!m||S)return;const t=N();t.resize(),t.center(),t.fit()},[m,N,S]),d.useEffect(()=>{if(!m||S)return;const t=N();w?t.enablePan():t.disablePan()},[m,w,N,S]),d.useEffect(()=>{const t=c=>{const y=c.target,Z=B(y);Z&&(Y(Z)&&b?b(Z):a&&a(Z))},o=c=>{const y=c.target,Z=B(y);Z&&(c.type==="mouseover"&&T?T(Z):O&&O(Z))},u=document.querySelectorAll(`.${n.svgContainer} circle, .${n.svgContainer} path, .${n.svgContainer} ellipse`);return u.forEach(c=>{c.removeEventListener("pointerdown",t),c.removeEventListener("mouseover",o),c.removeEventListener("mouseout",o),c.addEventListener("pointerdown",t),c.addEventListener("mouseover",o),c.addEventListener("mouseout",o)}),()=>{u.forEach(c=>{c.removeEventListener("pointerdown",t),c.removeEventListener("mouseover",o),c.removeEventListener("mouseout",o)})}},[b,a,T,O,r,m,B,Y]),d.useEffect(()=>{if(!m||S)return;const t=r.filter(o=>{const u=p==null?void 0:p.availableSeats.find(c=>c.id===o.id);return!ae.isEqual(o,u)});for(const o of t){const u=document.querySelector(o.cssSelector);u&&L(u,o)}},[r,p==null?void 0:p.availableSeats,L,m,S]),d.useEffect(()=>{let t=i||[];i&&(p!=null&&p.selectedSeatIds)&&(t=i.filter(o=>p.selectedSeatIds&&!p.selectedSeatIds.includes(o)).concat(p.selectedSeatIds.filter(o=>!i.includes(o))));for(const o of t){const u=r.find(y=>y.id===o);if(!u)continue;const c=document.querySelector(u.cssSelector);c&&L(c,u)}},[r,p==null?void 0:p.selectedSeatIds,i,L]);const D=d.useCallback(t=>t&&typeof t=="object"&&"style"in t?f.jsx("div",{className:H(n.actionGroup,{[n.actionGroupUnstyled]:t.style==="none"}),children:t.control}):f.jsx("div",{className:n.actionGroup,children:t}),[]),s=d.useMemo(()=>(I(!0),f.jsx("div",{className:n.svgContainer,dangerouslySetInnerHTML:{__html:m}})),[m]),_=d.useMemo(()=>{const t=()=>{N().zoomIn()},o=()=>{const c=N();c.resize(),c.center(),c.fit()},u=()=>{N().zoomOut()};return f.jsxs("div",{className:H(n.root,h),children:[f.jsxs("div",{className:`${n.controls} ${n.controlsLeft}`,children:[g&&f.jsxs("div",{className:n.actionGroup,children:[f.jsx("button",{type:"button",className:n.actionButton,onClick:t,title:"Zoom In",children:f.jsxs("svg",{className:n.icon,viewBox:"0 -960 960 960",children:[f.jsx("title",{children:"Zoom In"}),f.jsx("path",{d:"M440-440H200v-80h240v-240h80v240h240v80H520v240h-80v-240Z"})]})}),f.jsx("button",{type:"button",className:n.actionButton,onClick:o,title:"Reset Zoom",children:f.jsxs("svg",{className:n.icon,viewBox:"0 -960 960 960",children:[f.jsx("title",{children:"Reset zoom"}),f.jsx("path",{d:"M480-160q-134 0-227-93t-93-227q0-134 93-227t227-93q69 0 132 28.5T720-690v-110h80v280H520v-80h168q-32-56-87.5-88T480-720q-100 0-170 70t-70 170q0 100 70 170t170 70q77 0 139-44t87-116h84q-28 106-114 173t-196 67Z"})]})}),f.jsx("button",{type:"button",className:n.actionButton,onClick:u,title:"Zoom Out",children:f.jsxs("svg",{className:n.icon,viewBox:"0 -960 960 960",children:[f.jsx("title",{children:"Zoom Out"}),f.jsx("path",{d:"M200-440v-80h560v80H200Z"})]})})]}),x==null?void 0:x.map(c=>D(c))]}),s,f.jsx("div",{className:H(n.controls,n.controlsRight),children:R==null?void 0:R.map(c=>D(c))})]})},[h,x,R,D,N,s,g]);return S?f.jsx("div",{className:H(n.root,h),children:f.jsxs("div",{className:n.error,children:["ERROR: Unable to fetch SVG from the given URL: ",v]})}):_},te=({availableSeats:r,selectedSeatIds:i,svg:v,className:h,displayGroupMapping:a,onSeatSelect:b,onSeatDeselect:T,rightControls:O,leftControls:w,withDragSelection:g=!0,withGroupSelection:x=!0})=>{const[R,m]=d.useState(null),[j,S]=d.useState(null),C=(s,_)=>{var u;const t=(u=s==null?void 0:s.selectionGroups)==null?void 0:u[_];return typeof t=="object"?r.filter(c=>U(c,s,_)&&U(c,s,t.parent)):r.filter(c=>U(c,s,_))},U=(s,_,t)=>{var c,y;let o=(c=s.selectionGroups)==null?void 0:c[t];typeof o=="object"&&(o=o.value);const u=(y=_.selectionGroups)==null?void 0:y[t];return typeof u=="object"?o===u.value:o===u},I=(s,_)=>{const t=r.find(u=>u.id===s.id);if(!t)return;let o=[t];if(R==="group"&&j){const u=C(t,j);o=[...o,...u]}_&&b?b(o):!_&&T&&T(o)},p=s=>{const _=[];s.added.forEach(t=>{const o=r.find(u=>t.matches(u.cssSelector));o&&(t.classList.add(n.seatSelected),t.classList.remove(n.seatAvailable),_.push(o))}),_.length>0&&b&&b(_)},Y=s=>{s.added.forEach(_=>{_.classList.add(n.seatSelected),_.classList.remove(n.seatAvailable)}),s.removed.forEach(_=>{_.classList.remove(n.seatSelected),_.classList.add(n.seatAvailable)})},B=(s,_)=>{const t=r.find(u=>u.id===s.id);if(!t)return;const o=document.querySelector(t.cssSelector);if(o&&(_?o.classList.add(n.seatHover):o.classList.remove(n.seatHover),R==="group"&&j)){const u=C(t,j);for(const c of u){const y=document.querySelector(c.cssSelector);y&&(_?y.classList.add(n.seatHover):y.classList.remove(n.seatHover))}}},N=d.useMemo(()=>r.map(s=>({id:s.id,cssSelector:s.cssSelector,color:s.displayGroup&&typeof(a==null?void 0:a[s.displayGroup])=="string"?a==null?void 0:a[s.displayGroup]:void 0,icon:s.displayGroup&&typeof(a==null?void 0:a[s.displayGroup])!="string"?a==null?void 0:a[s.displayGroup]:void 0,selected:!1})),[r,a]),L=d.useMemo(()=>{const s=[];if(x){const _=r.map(o=>{if(o.selectionGroups)return Object.keys(o.selectionGroups)}).flat(),t=Array.from(new Set(_)).filter(o=>o!==void 0);s.push(...t.map(o=>f.jsx("button",{type:"button",className:H(n.actionButton,{[n.actionButtonSelected]:R==="group"&&j===o}),onClick:()=>{R==="group"&&j===o?(m(null),S(null)):(m("group"),S(o))},children:Array.from(o)[0]},o)))}return g&&s.push(f.jsx("button",{type:"button",className:H(n.actionButton,{[n.actionButtonSelected]:R==="drag"}),onClick:()=>m(R==="drag"?null:"drag"),title:"Lasso select",children:f.jsxs("svg",{className:n.icon,viewBox:"0 -960 960 960",children:[f.jsx("title",{children:"Lasso select"}),f.jsx("path",{d:"m161-516-80-8q6-46 20.5-89.5T141-696l68 42q-20 31-31.5 66T161-516Zm36 316q-33-32-57-70.5T101-352l76-26q12 35 31 65.5t45 56.5l-56 56Zm110-552-42-68q39-25 82.5-39.5T437-880l8 80q-37 5-72 16.5T307-752ZM479-82q-35 0-69.5-5.5T343-106l26-76q27 9 54 14.5t56 5.5v80Zm226-626q-26-26-56.5-45T583-784l26-76q43 15 81.5 39t70.5 57l-56 56Zm86 594L679-226v104h-80v-240h240v80H735l112 112-56 56Zm8-368q0-29-5.5-56T779-592l76-26q13 32 18.5 66.5T879-482h-80Z"})]})},"multi-select")),s},[r,j,R,g,x]),D=d.useMemo(()=>{const s=[];return L&&L.length&&s.push(L),w&&w.length&&s.push(...w),s},[w,L]);return f.jsxs(f.Fragment,{children:[R==="drag"&&f.jsx(le,{container:document.body,dragContainer:window,selectableTargets:[`.${n.svgContainer} .${n.seatAvailable}`],selectByClick:!1,selectFromInside:!0,continueSelect:!0,toggleContinueSelect:"shift",keyContainer:window,hitRate:100,onSelect:Y,onSelectEnd:p}),f.jsx(me,{svg:v,className:h,availableSeats:N,selectedSeatIds:i,onSeatSelect:s=>I(s,!0),onSeatDeselect:s=>I(s,!1),onSeatHover:s=>B(s,!0),onSeatHoverEnd:s=>B(s,!1),leftControls:D,rightControls:O,allowDragAndPan:R!=="drag"})]})},ve=({seats:r,value:i,onChange:v,className:h,svg:a,displayGroupMapping:b,leftControls:T,rightControls:O,withDragSelection:w,withGroupSelection:g})=>{const x=(m,j)=>{let S=[...i||[]];for(const C of m)j?S=[...S,C]:S=S.filter(U=>U!==C);v&&v(S)},R=d.useMemo(()=>r.map(m=>({...m,cssSelector:m.cssSelector||""})),[r]);if(a)return f.jsx(te,{availableSeats:R,selectedSeatIds:i,svg:a,className:h,onSeatSelect:m=>x(m.map(j=>j.id),!0),onSeatDeselect:m=>x(m.map(j=>j.id),!1),displayGroupMapping:b,leftControls:T,rightControls:O,withDragSelection:w,withGroupSelection:g})},he=({seats:r,selectedSeatIds:i,onClick:v,className:h,svg:a,displayGroupMapping:b,leftControls:T,rightControls:O})=>{const w=d.useMemo(()=>r.map(g=>({...g,cssSelector:g.cssSelector||""})),[r]);if(a)return f.jsx(te,{availableSeats:w,selectedSeatIds:i,svg:a,className:h,onSeatSelect:g=>{v&&v(g.map(x=>x.id)[0],!0)},onSeatDeselect:g=>{v&&v(g.map(x=>x.id)[0],!1)},displayGroupMapping:b,leftControls:T,rightControls:O,withDragSelection:!1,withGroupSelection:!1})};P.SeatmapAccordion=he,P.SeatmapInput=ve,Object.defineProperty(P,Symbol.toStringTag,{value:"Module"})});