UNPKG

@mopex/react-gantt-flow

Version:

A lightweight and high-performance React (TypeScript) based Gantt chart component.

33 lines (32 loc) 18 kB
(function(B,p){typeof exports=="object"&&typeof module<"u"?p(exports,require("react")):typeof define=="function"&&define.amd?define(["exports","react"],p):(B=typeof globalThis<"u"?globalThis:B||self,p(B["react-gantt-flow"]={},B.React))})(this,function(B,p){"use strict";var oe=document.createElement("style");oe.textContent=`._axis-text_orqt4_1{font-size:10px;font-weight:700;fill:#454444;-webkit-user-select:none;user-select:none}._months-text_cazi6_1{font-size:14px;font-weight:700;fill:#454444}._bar-date-handle_y4tcz_1,._bar-progress-handle_1l6rn_1{fill:#2e2d2d;opacity:.8;cursor:ew-resize}._default-bar_12p1y_1{border:1px solid #454444;fill:#fff;stroke:#454444;stroke-width:.5}._progress-bar_12p1y_8{fill:#d7d7d7}._task-name_12p1y_12{fill:#454444;font-size:10px;pointer-events:none;-webkit-user-select:none;user-select:none;white-space:nowrap;text-overflow:ellipsis}._dependencies-arrow-path_1giuk_1{fill:none;stroke:gray}._dependencies-arrow-circle_1giuk_6{fill:gray} /*$vite$:1*/`,document.head.appendChild(oe);var $={exports:{}},V={};/** * @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 ae;function me(){if(ae)return V;ae=1;var e=Symbol.for("react.transitional.element"),n=Symbol.for("react.fragment");function a(r,s,o){var u=null;if(o!==void 0&&(u=""+o),s.key!==void 0&&(u=""+s.key),"key"in s){o={};for(var f in s)f!=="key"&&(o[f]=s[f])}else o=s;return s=o.ref,{$$typeof:e,type:r,key:u,ref:s!==void 0?s:null,props:o}}return V.Fragment=n,V.jsx=a,V.jsxs=a,V}var J={};/** * @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 ce;function _e(){return ce||(ce=1,process.env.NODE_ENV!=="production"&&function(){function e(t){if(t==null)return null;if(typeof t=="function")return t.$$typeof===F?null:t.displayName||t.name||null;if(typeof t=="string")return t;switch(t){case w:return"Fragment";case M:return"Profiler";case O:return"StrictMode";case P:return"Suspense";case b:return"SuspenseList";case H:return"Activity"}if(typeof t=="object")switch(typeof t.tag=="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),t.$$typeof){case _:return"Portal";case N:return(t.displayName||"Context")+".Provider";case S:return(t._context.displayName||"Context")+".Consumer";case I:var i=t.render;return t=t.displayName,t||(t=i.displayName||i.name||"",t=t!==""?"ForwardRef("+t+")":"ForwardRef"),t;case k:return i=t.displayName||null,i!==null?i:e(t.type)||"Memo";case j:i=t._payload,t=t._init;try{return e(t(i))}catch{}}return null}function n(t){return""+t}function a(t){try{n(t);var i=!1}catch{i=!0}if(i){i=console;var T=i.error,D=typeof Symbol=="function"&&Symbol.toStringTag&&t[Symbol.toStringTag]||t.constructor.name||"Object";return T.call(i,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",D),n(t)}}function r(t){if(t===w)return"<>";if(typeof t=="object"&&t!==null&&t.$$typeof===j)return"<...>";try{var i=e(t);return i?"<"+i+">":"<...>"}catch{return"<...>"}}function s(){var t=W.A;return t===null?null:t.getOwner()}function o(){return Error("react-stack-top-frame")}function u(t){if(X.call(t,"key")){var i=Object.getOwnPropertyDescriptor(t,"key").get;if(i&&i.isReactWarning)return!1}return t.key!==void 0}function f(t,i){function T(){A||(A=!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)",i))}T.isReactWarning=!0,Object.defineProperty(t,"key",{get:T,configurable:!0})}function d(){var t=e(this.type);return G[t]||(G[t]=!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.")),t=this.props.ref,t!==void 0?t:null}function l(t,i,T,D,v,E,L,z){return T=E.ref,t={$$typeof:g,type:t,key:i,props:E,_owner:v},(T!==void 0?T:null)!==null?Object.defineProperty(t,"ref",{enumerable:!1,get:d}):Object.defineProperty(t,"ref",{enumerable:!1,value:null}),t._store={},Object.defineProperty(t._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(t,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(t,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:L}),Object.defineProperty(t,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:z}),Object.freeze&&(Object.freeze(t.props),Object.freeze(t)),t}function R(t,i,T,D,v,E,L,z){var y=i.children;if(y!==void 0)if(D)if(Y(y)){for(D=0;D<y.length;D++)x(y[D]);Object.freeze&&Object.freeze(y)}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 x(y);if(X.call(i,"key")){y=e(t);var K=Object.keys(i).filter(function(Be){return Be!=="key"});D=0<K.length?"{key: someKey, "+K.join(": ..., ")+": ...}":"{key: someKey}",Q[y+D]||(K=0<K.length?"{"+K.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} />`,D,y,K,y),Q[y+D]=!0)}if(y=null,T!==void 0&&(a(T),y=""+T),u(i)&&(a(i.key),y=""+i.key),"key"in i){T={};for(var se in i)se!=="key"&&(T[se]=i[se])}else T=i;return y&&f(T,typeof t=="function"?t.displayName||t.name||"Unknown":t),l(t,y,E,v,s(),T,L,z)}function x(t){typeof t=="object"&&t!==null&&t.$$typeof===g&&t._store&&(t._store.validated=1)}var h=p,g=Symbol.for("react.transitional.element"),_=Symbol.for("react.portal"),w=Symbol.for("react.fragment"),O=Symbol.for("react.strict_mode"),M=Symbol.for("react.profiler"),S=Symbol.for("react.consumer"),N=Symbol.for("react.context"),I=Symbol.for("react.forward_ref"),P=Symbol.for("react.suspense"),b=Symbol.for("react.suspense_list"),k=Symbol.for("react.memo"),j=Symbol.for("react.lazy"),H=Symbol.for("react.activity"),F=Symbol.for("react.client.reference"),W=h.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,X=Object.prototype.hasOwnProperty,Y=Array.isArray,m=console.createTask?console.createTask:function(){return null};h={"react-stack-bottom-frame":function(t){return t()}};var A,G={},te=h["react-stack-bottom-frame"].bind(h,o)(),Z=m(r(o)),Q={};J.Fragment=w,J.jsx=function(t,i,T,D,v){var E=1e4>W.recentlyCreatedOwnerStacks++;return R(t,i,T,!1,D,v,E?Error("react-stack-top-frame"):te,E?m(r(t)):Z)},J.jsxs=function(t,i,T,D,v){var E=1e4>W.recentlyCreatedOwnerStacks++;return R(t,i,T,!0,D,v,E?Error("react-stack-top-frame"):te,E?m(r(t)):Z)}}()),J}var ie;function pe(){return ie||(ie=1,process.env.NODE_ENV==="production"?$.exports=me():$.exports=_e()),$.exports}var c=pe();const ge="React Gantt Flow",C={LEFT_MARGIN:40,RIGHT_MARGIN:80,GRID_STROKE_WIDTH:1,GRID_COLUMN_WIDTH:50,BAR_AREA_HEIGHT:50,BAR_ALIGN_MARGIN:10,AXIS_HEIGHT:50,BAR_ARROW_STROKE_WIDTH:1.5},le=30,Re=(e,n,a)=>{const{LEFT_MARGIN:r,RIGHT_MARGIN:s}=C;return p.useMemo(()=>({dateToX:f=>{const d=n.getTime()-e.getTime();if(d===0)return 0;const l=f.getTime()-e.getTime();return r+l/d*(a-s)},xToDate:f=>{const d=n.getTime()-e.getTime();if(d===0)return new Date(e);const l=a-s,R=f-r;return new Date(e.getTime()+R/l*d)}}),[e,n,a,r,s])},ue=Symbol.for("constructDateFrom");function q(e,n){return typeof e=="function"?e(n):e&&typeof e=="object"&&ue in e?e[ue](n):e instanceof Date?new e.constructor(n):new Date(n)}function he(e,n){return q(e,e)}function ee(e,n,a){const r=he(e);return isNaN(n)?q(e,NaN):(n&&r.setDate(r.getDate()+n),r)}function Te(e,...n){const a=q.bind(null,n.find(r=>typeof r=="object"));return n.map(a)}function De(e,n){const[a,r]=Te(e,n.start,n.end);return{start:a,end:r}}function xe(e,n){const{start:a,end:r}=De(n==null?void 0:n.in,e);let s=+a>+r;const o=s?+a:+r,u=s?r:a;u.setHours(0,0,0,0);let f=1;const d=[];for(;+u<=o;)d.push(q(a,u)),u.setDate(u.getDate()+f),u.setHours(0,0,0,0);return s?d.reverse():d}const Ee=p.memo(({axisHeight:e,chartWidth:n,chartHeight:a,days:r,taskCount:s,dateToX:o})=>{const{BAR_AREA_HEIGHT:u,GRID_STROKE_WIDTH:f}=C,d=()=>Array.from({length:s}).map((h,g)=>{const _=e+g*u,w=u;return c.jsx("rect",{x:0,y:_,width:n,height:w,fill:"white"},`row-${_}`)}),l=()=>r.map((h,g)=>{const _=h.getDay();if(_!==0&&_!==6)return null;const w=o(h),O=r[g+1],M=O?o(O)-w:10;return c.jsx("rect",{x:w,y:e,width:M,height:a,fill:"#f7f7f7"},`weekend-${h.toISOString()}`)}),R=()=>r.map(h=>{const g=o(h);return c.jsx("line",{x1:g,y1:e,x2:g,y2:e+a,stroke:"#ededed",strokeWidth:f},h.toISOString())}),x=()=>Array.from({length:s+1}).map((h,g)=>{const _=e+g*u;return c.jsx("line",{x1:0,y1:_,x2:n,y2:_,stroke:"#ededed",strokeWidth:f},`hline-${_}`)});return c.jsxs("g",{children:[d(),l(),R(),x()]})}),we=p.memo(Ee),be={"axis-text":"_axis-text_orqt4_1"},Ae=p.memo(({axisHeight:e,days:n,yOffset:a=0,dateToX:r})=>c.jsx("g",{transform:`translate(0, ${a})`,children:n.map(s=>{const o=r(s),u=s.getDate().toString();return c.jsx("g",{transform:`translate(${o}, 0)`,children:c.jsx("text",{className:be["axis-text"],y:e/2,textAnchor:"middle",children:u})},s.toISOString())})})),ye=p.memo(Ae),Se={"months-text":"_months-text_cazi6_1"},Ie=p.memo(({axisHeight:e,days:n,dateToX:a})=>{if(!n||n.length===0)return null;const r=[];let s=`${n[0].getFullYear()}-${n[0].getMonth()}`,o=n[0].toLocaleDateString("en-US",{year:"numeric",month:"long"}),u=n[0],f=n[0];for(let d=1;d<n.length;d++){const l=n[d],R=`${l.getFullYear()}-${l.getMonth()}`;R===s||(r.push({key:s,month:o,start:u,end:f}),s=R,o=l.toLocaleDateString("en-US",{year:"numeric",month:"long"}),u=l),f=l}return r.push({key:s,month:o,start:u,end:f}),c.jsx("g",{children:r.map(d=>{const l=a(d.start);return c.jsx("g",{children:c.jsx("text",{className:Se["months-text"],x:l-5,y:e/1.3,textAnchor:"start",children:d.month})},d.key)})})}),je=p.memo(Ie),ve={"bar-date-handle":"_bar-date-handle_y4tcz_1"},de=({type:e,x:n,y:a,onMouseDownDateHandle:r})=>c.jsx("rect",{tabIndex:0,className:ve["bar-date-handle"],x:n,y:a,width:5,height:20,ry:2,rx:2,onMouseDown:s=>r(e,s)}),Oe={"bar-progress-handle":"_bar-progress-handle_1l6rn_1"},Me=({progressPoint:e,onMouseDownProgressHandle:n})=>c.jsx("polygon",{tabIndex:0,className:Oe["bar-progress-handle"],points:e,onMouseDown:n}),ne={"default-bar":"_default-bar_12p1y_1","progress-bar":"_progress-bar_12p1y_8","task-name":"_task-name_12p1y_12"},U=24*60*60*1e3,Ne=({task:e,index:n,dateToX:a,xToDate:r,onDateChange:s})=>{const[o,u]=p.useState(e.startDate),[f,d]=p.useState(e.endDate),[l,R]=p.useState(e.progress),[x,h]=p.useState(!1),[g,_]=p.useState(null),[w,O]=p.useState(!1),{BAR_AREA_HEIGHT:M,GRID_COLUMN_WIDTH:S,BAR_ALIGN_MARGIN:N}=C,I=p.useRef({initialMouseX:0,initialStartX:0,initialEndX:0,initialProgress:e.progress}),P=p.useRef(null),b=a(o),k=a(f),j=k-b,H=n*M,F=j*l/100,W=(m,A)=>{A.stopPropagation(),A.preventDefault(),I.current.initialMouseX=A.clientX,m==="start"?(I.current.initialStartX=b,_("start")):(I.current.initialEndX=k,_("end"))},X=m=>{m.stopPropagation(),m.preventDefault(),I.current.initialMouseX=m.clientX,I.current.initialProgress=l,_("progress")},Y=m=>{m.stopPropagation(),m.preventDefault(),I.current.initialMouseX=m.clientX,I.current.initialStartX=b,I.current.initialEndX=k,_("bar")};return p.useEffect(()=>{const m=G=>{const{initialMouseX:te,initialStartX:Z,initialEndX:Q,initialProgress:t}=I.current,i=G.clientX-te;if(g==="start"){const D=Math.round(i/S),v=r(Z);let E=new Date(v.getTime()+D*U);const L=f.getTime()-U;E.getTime()>L&&(E=new Date(L)),u(E),s(e.id,E,f,l,!1)}else if(g==="end"){const D=Math.round(i/S),v=r(Q);let E=new Date(v.getTime()+D*U);const L=o.getTime()+U;E.getTime()<L&&(E=new Date(L)),d(E),s(e.id,o,E,l,!1)}else if(g==="bar"){const D=Math.round(i/S),v=r(Z),E=r(Q),L=new Date(v.getTime()+D*U),z=new Date(E.getTime()+D*U);u(L),d(z),s(e.id,L,z,l,!1)}else if(g==="progress"){const T=i/j*100;let D=t+T;D=Math.max(0,Math.min(100,D)),R(D),s(e.id,o,f,D,!1)}},A=()=>{const G=g!==null;_(null),G&&s(e.id,o,f,l,!0)};return g!==null?(window.addEventListener("mousemove",m),window.addEventListener("mouseup",A)):(window.removeEventListener("mousemove",m),window.removeEventListener("mouseup",A)),()=>{window.removeEventListener("mousemove",m),window.removeEventListener("mouseup",A)}},[e.id,g,f,o,l,j,S,r,s]),p.useEffect(()=>{g===null&&(u(e.startDate),d(e.endDate),R(e.progress))},[e.startDate,e.endDate,e.progress,g]),p.useEffect(()=>{if(P.current){const m=P.current.getBBox();O(m.width+10>j)}},[j]),c.jsxs("g",{onMouseEnter:()=>h(!0),onMouseLeave:()=>h(!1),children:[c.jsx("rect",{className:ne["default-bar"],x:b,y:H+N,rx:"5",ry:"5",width:j,height:M-N*2,onMouseDown:Y}),l>0&&c.jsx("rect",{className:ne["progress-bar"],x:b,y:H+N,rx:"5",ry:"5",width:F,height:M-N*2,onMouseDown:Y}),c.jsx("text",{ref:P,className:ne["task-name"],x:w?k+5:b+j/2,y:H+M/1.95,dominantBaseline:"middle",textAnchor:w?"start":"middle",children:e.name}),x&&c.jsxs(c.Fragment,{children:[c.jsx(de,{type:"start",x:b+2,y:H+15,onMouseDownDateHandle:W}),c.jsx(Me,{progressPoint:` ${b+F}, ${H+35} ${b+F-5}, ${H+40} ${b+F+5}, ${H+40} `,onMouseDownProgressHandle:X}),c.jsx(de,{type:"end",x:k-7,y:H+15,onMouseDownDateHandle:W})]})]})};function Pe(e,n,a,r){const{GRID_COLUMN_WIDTH:s,BAR_AREA_HEIGHT:o,GRID_STROKE_WIDTH:u}=C,f=2,d=s/2*f,l=o/2*f;return` M ${e} ${n} C ${e+d} ${n+l}, ${a-d} ${r-l}, ${a+u/2} ${r} `}const fe={"dependencies-arrow-path":"_dependencies-arrow-path_1giuk_1","dependencies-arrow-circle":"_dependencies-arrow-circle_1giuk_6"},He=({barPositions:e,tasks:n})=>{const{BAR_AREA_HEIGHT:a,BAR_ARROW_STROKE_WIDTH:r}=C;return c.jsx(c.Fragment,{children:n.map((s,o)=>!s.dependencies||s.dependencies.length===0?null:s.dependencies.map(u=>{const f=n.findIndex(w=>w.id===u);if(f===-1)return null;const d=e[f],l=e[o],R=d.x+d.width,x=d.y+a/2,h=l.x,g=l.y+a/2,_=Pe(R,x,h,g);return c.jsxs("g",{children:[c.jsx("path",{d:_,className:fe["dependencies-arrow-path"],strokeWidth:r}),c.jsx("circle",{className:fe["dependencies-arrow-circle"],cx:h,cy:g,r:5})]},`arrow-${u}-${s.id}`)}))})},Ge=p.memo(({tasks:e,chartMinDate:n,chartMaxDate:a,dateToX:r,xToDate:s,onTaskUpdate:o})=>{const{BAR_AREA_HEIGHT:u,AXIS_HEIGHT:f}=C,d=e.map((R,x)=>{const h=r(R.startDate),g=r(R.endDate)-r(R.startDate),_=x*u;return{x:h,y:_,width:g}}),l=(R,x,h,g,_=!0)=>{o(R,x,h,g,_)};return c.jsxs("g",{transform:`translate(0, ${f})`,children:[c.jsx(He,{tasks:e,barPositions:d}),e.map((R,x)=>c.jsx(Ne,{task:R,index:x,dateToX:r,xToDate:s,onDateChange:l,chartMinDate:n,chartMaxDate:a},`bar-${R.id}`))]})}),ke=p.memo(Ge),Le=({axisHeight:e,chartHeight:n,dateToX:a})=>{const{GRID_STROKE_WIDTH:r}=C,s=a(new Date);return c.jsxs("g",{children:[c.jsx("line",{x1:s,y1:e,x2:s,y2:e+n,stroke:"red",strokeWidth:r}),c.jsx("circle",{cx:s,cy:e,r:5,fill:"red"}),c.jsxs("circle",{cx:s,cy:e,fill:"none",stroke:"red",strokeWidth:2,children:[c.jsx("animate",{attributeName:"r",from:"5",to:"20",dur:"1.5s",begin:"0s",repeatCount:"indefinite"}),c.jsx("animate",{attributeName:"opacity",from:"1",to:"0",dur:"1.5s",begin:"0s",repeatCount:"indefinite"})]})]})},We=({axisHeight:e,barAreaHeight:n,tasks:a,dateToX:r})=>{const{GRID_STROKE_WIDTH:s}=C,o=r(new Date),u="#92e896",f="#FFD54F",d="#66BB6A",l="#fac51b",R=3;return c.jsx("g",{children:a.map((x,h)=>{const _=e+h*n,w=n-s;if(x.progress===0||x.progress===100)return null;const O=r(new Date(x.startDate)),S=r(new Date(x.endDate))-R/2-O,N=O+S*x.progress/100,I=Math.min(o,N),P=Math.abs(N-o);if(P===0)return null;const b=N>o?u:f,k=N>o?d:l;return c.jsx("rect",{x:I,y:_,width:P,height:w,fill:b,opacity:.5,stroke:k,strokeWidth:R},`inazuma-${x.id}`)})})};function Ce(e){const n=e.reduce((r,s)=>s.startDate<r?s.startDate:r,e[0].startDate),a=e.reduce((r,s)=>s.endDate>r?s.endDate:r,e[0].endDate);return{min:n,max:a}}function Fe(e,n){return xe({start:e,end:n})}const re=e=>{if(e.length===0){const r=new Date;return[ee(r,-2),ee(r,le)]}const{min:n,max:a}=Ce(e);return[ee(n,-2),ee(a,le)]},Xe=({disparityDisplay:e,task:n,todaysLineDisplay:a,autoLayoutDependencies:r=!1,onDateChange:s})=>{const[o,u]=p.useState(n),[f,d]=p.useState(re(n)),[l,R]=f,{LEFT_MARGIN:x,GRID_COLUMN_WIDTH:h,BAR_AREA_HEIGHT:g,AXIS_HEIGHT:_}=C;p.useEffect(()=>{u(n),d(re(n))},[n]);const w=p.useMemo(()=>Fe(l,R),[l,R]),O=p.useMemo(()=>x+w.length*h,[w.length,x,h]),M=p.useMemo(()=>o.length*g+_,[o.length,g,_]),{dateToX:S,xToDate:N}=Re(l,R,O),I=p.useCallback((P,b,k,j,H=!0)=>{const F=o.find(m=>m.id===P),W=F!==void 0?b.getTime()-F.startDate.getTime():0,X=new Set;if(r&&W!==0){const m=A=>{for(const G of o)G.dependencies.includes(A)&&!X.has(G.id)&&(X.add(G.id),m(G.id))};m(P)}const Y=o.map(m=>m.id===P?{...m,startDate:b,endDate:k,...j!==void 0?{progress:j}:{}}:X.has(m.id)?{...m,startDate:new Date(m.startDate.getTime()+W),endDate:new Date(m.endDate.getTime()+W)}:m);if(u(Y),H&&d(re(Y)),H&&s){s(P,b,k,j);for(const m of X){const A=Y.find(G=>G.id===m);A&&s(m,A.startDate,A.endDate,A.progress)}}},[o,s,r]);return c.jsxs("svg",{width:O,height:M,children:[c.jsx("title",{children:ge}),c.jsx(je,{days:w,dateToX:S,axisHeight:_/2}),c.jsx(ye,{days:w,dateToX:S,axisHeight:_/2,yOffset:_/2}),c.jsx(we,{days:w,taskCount:o.length,dateToX:S,axisHeight:_,chartWidth:O,chartHeight:M}),e&&c.jsx(We,{tasks:o,dateToX:S,axisHeight:_,barAreaHeight:g}),c.jsx(ke,{tasks:o,dateToX:S,xToDate:N,onTaskUpdate:I,chartMinDate:l,chartMaxDate:R}),a&&c.jsx(Le,{dateToX:S,axisHeight:_,chartHeight:M})]})},Ye=p.memo(Xe);B.GanttFlow=Ye,Object.defineProperty(B,Symbol.toStringTag,{value:"Module"})});