UNPKG

ftr-timetable

Version:

A versatile timetable component for React

391 lines (349 loc) 18.9 kB
(function(x,t){typeof exports=="object"&&typeof module<"u"?t(exports,require("react/jsx-runtime"),require("react"),require("date-fns"),require("styled-components")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react","date-fns","styled-components"],t):(x=typeof globalThis<"u"?globalThis:x||self,t(x["ftr-timetable"]={},x["react/jsx-runtime"],x.React,x.dateFns,x.styledComponents))})(this,function(x,t,h,m,p){"use strict";const v=h.createContext(void 0),L=({children:e,...o})=>t.jsx(v.Provider,{value:{...o,ref:h.createRef()},children:e}),g=()=>{const e=h.useContext(v);if(e===void 0)throw new Error("useTimeTableContext must be used within the context of TimeTableContext");return e},P=p.div` position: absolute; box-shadow: -1px -1px 2px 0 rgba(0, 0, 0, 0.2); `,T=h.memo(function({date:e}){const{ref:o,displayStyle:a,showTimeMarker:l,startingHour:d,styles:s}=g(),n=h.useMemo(()=>{const i=m.format(new Date(e),"yyyy-MM-dd"),r=m.format(m.subHours(new Date,d),"yyyy-MM-dd");if(i!==r)return-1;const c=m.addHours(m.startOfDay(new Date(e)),d),f=new Date,b=m.differenceInMinutes(f,c);return Math.max(b,0)},[e,d]);return h.useEffect(()=>{var r,c;if(typeof document>"u"||!o.current)return;const i=Math.max(n-180,0);(c=(r=o.current).scrollTo)==null||c.call(r,{top:a==="vertical"?i:0,left:a==="horizontal"?i:0,behavior:"smooth"})},[n,a,o]),n<1||!l?null:t.jsx(P,{style:{backgroundColor:s.timeMarkerColor||"#666",width:a==="horizontal"?"2px":"80%",height:a==="horizontal"?"33.333333%":"2px",left:a==="horizontal"?`${n}px`:0,top:a==="horizontal"?0:`${n}px`}})}),q=p.div` position: absolute; width: 100%; font-size: 0.875rem; line-height: 1.25rem; padding: 0 0.5rem; `,E=p.div` position: absolute; height: 100%; font-size: 0.875rem; line-height: 1.25rem; padding: 1px 0; `,k=p.div` position: relative; height: 100%; padding: 1px; `,D=p.div` display: flex; position: relative; height: 100%; color: ${e=>e.$styles.itemTextColor||"inherit"}; background: ${e=>e.$styles.itemBackgroundColor||"#304151"}; cursor: pointer; border-radius: 5px; box-shadow: 0 2px 5px -4px rgba(0, 0, 0, 0.4); &:hover { box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.1); background: ${e=>e.$styles.itemHoverBackgroundColor||e.$styles.itemBackgroundColor||"#374151"}; } &.ftr-timetable-item__vertical { padding: 0.25rem; flex-direction: column; .ftr-timetable-item__inner { top: 62px; } } &.ftr-timetable-item__horizontal { padding: 0.125rem 0.25rem; flex-direction: row; .ftr-timetable-item__inner { left: 164px; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; } } &.item-cancelled { opacity: 0.5; .ftr-timetable-item__inner { text-decoration: line-through; } } .ftr-timetable-item__inner { position: sticky; overflow: hidden; text-overflow: ellipsis; font-size: 12px; .ftr-timetable-item__info { font-size: 10px; font-weight: normal; opacity: 0.9; } } `,H=h.memo(function({item:e,eventStartOffset:o,eventSize:a,intersections:l,offset:d}){const{onItemClick:s,renderItem:n,styles:i}=g();return t.jsx(q,{title:e.name,style:{top:`${o}px`,height:`${a}px`,left:`calc(100% / ${l+1} * ${d})`,maxWidth:`calc(100% / ${l+1})`},children:t.jsx(k,{onClick:()=>s==null?void 0:s(e),children:n?n(e):t.jsx(D,{$styles:i,className:"ftr-timetable-item ftr-timetable-item__vertical",style:e.style,children:t.jsxs("div",{className:"ftr-timetable-item__inner",children:[t.jsx("div",{children:e.name}),e.info&&t.jsx("div",{className:"ftr-timetable-item__info",children:e.info})]})})})})}),V=h.memo(function({item:e,eventStartOffset:o,eventSize:a,intersections:l,offset:d}){const{onItemClick:s,renderItem:n,styles:i}=g();return t.jsx(E,{title:e.name,style:{left:`${o}px`,width:`${a}px`,top:`calc(100% / ${l+1} * ${d})`,maxHeight:`calc(100% / ${l+1})`},children:t.jsx(k,{onClick:()=>s==null?void 0:s(e),children:n?n(e):t.jsx(D,{$styles:i,className:`ftr-timetable-item ftr-timetable-item__horizontal${e.cancelled?" item-cancelled":""}${e.className?` ${e.className}`:""}`,style:e.style,children:t.jsxs("div",{className:"ftr-timetable-item__inner",children:[t.jsx("div",{children:e.name}),e.info&&t.jsx("div",{className:"ftr-timetable-item__info",children:e.info})]})})})})}),C=h.memo(function({item:e,intersections:o,offset:a}){const{startingHour:l,numberOfHours:d,selectedDate:s,displayStyle:n}=g(),i=m.differenceInDays(new Date(e.startDate),new Date(s)),r=m.subDays(m.addHours(m.startOfDay(new Date(e.startDate)),l),i),c=new Date(Math.max(new Date(e.startDate).getTime(),new Date(r).getTime())),f=m.differenceInMinutes(c,r),b=m.differenceInMinutes(new Date(e.endDate),c),w=Math.min(b,d*60-f);return n==="vertical"?t.jsx(H,{item:e,intersections:o,offset:a,eventStartOffset:f,eventSize:w}):t.jsx(V,{item:e,intersections:o,offset:a,eventStartOffset:f,eventSize:w})}),z=e=>h.useMemo(()=>e.reduce((l,d,s)=>{const n=new Date(d.startDate).getTime(),i=new Date(d.endDate).getTime();let r=0;const c=l.filter(f=>n>=f.start&&n<f.end||i>=f.start&&i<f.end);for(const f of c){if(f.offset>0){r--;break}if(f.intersections===0){f.intersections+=1;continue}for(const b of l.filter(w=>f.with.includes(w.index)))(n>=b.start&&n<b.end||i>=b.start&&i<b.end)&&(f.intersections+=1)}return[...l,{item:d,start:n,end:i,offset:c.length+r,intersections:c.length,index:s,with:c.map(f=>f.index)}]},[]),[e]),O=p.div` &::-webkit-scrollbar { width: 0px; height: 8px; background: #1f2937; } &::-webkit-scrollbar-thumb { background: #555; border-radius: 50%; border: solid 2px #1f2937; } &::-webkit-scrollbar-thumb:hover { background: hsl(from #888 h s calc(l - 5)); } position: relative; overflow: auto; width: 100%; max-height: 100%; max-width: 100vw; box-sizing: border-box !important; * { box-sizing: border-box !important; } `,Y=p.div` position: absolute; width: 100%; height: 100%; left: 0; top: 0; color: ${e=>e.$styles.dateTextColor||"inherit"}; background: ${e=>e.$styles.backgroundColor||"#1f2937"}; .ftr-timetable-datetime { display: flex; flex-direction: row; position: sticky; top: 0; z-index: 3; background: ${e=>e.$styles.dateBackgroundColor||"#1f2937"}; width: 100%; height: 44px; &__date { position: sticky; top: 0; left: 0; z-index: 2; background: ${e=>e.$styles.datePickerBackgroundColor||e.$styles.dateBackgroundColor||"#1f2937"}; display: flex; justify-content: space-between; width: 10rem; height: 100%; flex-shrink: 0; flex-direction: row; } &__select { display: flex; flex-direction: row; align-items: center; width: 100%; height: 100%; padding-left: 0.5rem; border-right: ${e=>e.$styles.borderStyle||"solid 2px #374151"}; border-bottom: ${e=>e.$styles.borderStyle||"solid 2px #374151"}; select { background: transparent url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='${e=>{var o;return((o=e.$styles.dateTextColor)==null?void 0:o.replace("#","%23"))||"%23fff"}}'><polygon points='0,0 100,0 50,50'/></svg>") no-repeat calc(100% - 10px) calc(50% + 3px); background-size: 10px; color: inherit; font-family: inherit; border: none; outline: none; font-size: 0.875rem; line-height: 1.25rem; width: 100%; -webkit-appearance: none; appearance: none; } } &__hours { display: flex; flex-direction: row; position: relative; border-bottom: ${e=>e.$styles.borderStyle||"solid 2px #374151"}; width: 100%; height: 100%; } &__hour { display: flex; flex-direction: column; justify-content: flex-end; width: 60px; padding-left: 0.25rem; padding-bottom: 0.25rem; font-size: 0.75rem; height: 100%; &:not(:first-child) { border-left: ${e=>e.$styles.borderStyle||"solid 2px #374151"}; } } } `,A=p.div` display: flex; flex-direction: row; // background-color: ${e=>e.$styles.backgroundColor||"#1f2937"}; height: 60px; .ftr-timetable-location { height: 100%; width: 10rem; z-index: 2; position: sticky; top: 0; left: 0; color: ${e=>e.$styles.locationTextColor||"inherit"}; background: ${e=>e.$styles.locationBackgroundColor||"#000"}; &__inner { display: flex; align-items: center; height: 100%; padding: 0 0.5rem; font-size: 0.875rem; line-height: 1.25rem; border-right: ${e=>e.$styles.borderStyle||"solid 2px #374151"}; border-bottom: ${e=>e.$styles.borderStyle||"solid 2px #374151"}; } &__name { width: 100%; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; } } .ftr-timetable-location-items { flex: 1; position: relative; height: 100%; border-bottom: ${e=>e.$styles.borderStyle||"solid 2px #374151"}; // background-color: ${e=>e.$styles.backgroundColor||"#1f2937"}; } `,G=h.memo(function({location:e}){const{items:o,onLocationClick:a,renderLocation:l,styles:d}=g(),s=o.filter(i=>i.locationId===e.id),n=z(s);return t.jsxs(A,{$styles:d,children:[t.jsx("div",{className:"ftr-timetable-location ftr-timetable-location__horizontal","data-testid":`timetable-location-${e.id}`,title:e.name,onClick:()=>a==null?void 0:a(e),style:e.style,children:l?l(e):t.jsx("div",{className:"ftr-timetable-location__inner",children:t.jsx("div",{className:"ftr-timetable-location__name",children:e.name})})}),t.jsx("div",{className:"ftr-timetable-location-items",children:n.map((i,r)=>t.jsx(C,{item:i.item,intersections:i.intersections,offset:i.offset},`tt_${i.item.id}_${r}`))})]})}),J=({dateChange:e,locations:o,dates:a,hours:l,selectedDate:d})=>{const{ref:s,dateFormat:n,styles:i}=g();return t.jsx(O,{ref:s,"data-testid":"timetable-horizontal",className:"ftr-timetable ftr-timetable__horizontal",style:{height:`${o.length*60+52}px`},children:t.jsxs(Y,{$styles:i,style:{minWidth:`${l.length*60+160}px`},children:[t.jsxs("div",{className:"ftr-timetable-datetime",children:[t.jsx("div",{className:"ftr-timetable-datetime__date",children:t.jsx("div",{className:"ftr-timetable-datetime__select",children:t.jsx("select",{value:d,onChange:r=>e(r.target.value),children:a.map(r=>t.jsx("option",{value:r,children:m.format(new Date(r),n)},r))})})}),t.jsxs("div",{className:"ftr-timetable-datetime__hours",children:[l.map((r,c)=>t.jsx("div",{className:"ftr-timetable-datetime__hour",children:r.display},`hour_${c}`)),t.jsx(T,{date:d})]})]}),o.map((r,c)=>t.jsx(G,{location:r},`location_${c}`))]})})},K=p.div` &::-webkit-scrollbar { width: 0px; height: 8px; background: #1f2937; } &::-webkit-scrollbar-thumb { background: #555; border-radius: 50%; border: solid 2px #1f2937; } &::-webkit-scrollbar-thumb:hover { background: hsl(from #888 h s calc(l - 5)); } height: 100%; max-width: 100vw; position: relative; overflow: auto; box-sizing: border-box !important; * { box-sizing: border-box !important; } `,Q=p.div` position: absolute; width: 100%; height: 100%; left: 0; top: 0; transform: translateY(-1px); color: ${e=>e.$styles.textColor||"#fff"}; .ftr-timetable-datetime { display: flex; flex-direction: row; width: 100%; &__container { width: 8rem; color: ${e=>e.$styles.dateTextColor||"inherit"}; background: ${e=>e.$styles.dateBackgroundColor||"#1f2937"}; position: sticky; left: 0; top: 0; z-index: 3; } &__date { width: 100%; height: 60px; background: ${e=>e.$styles.datePickerBackgroundColor||e.$styles.dateBackgroundColor||"#1f2937"}; position: sticky; top: 0; z-index: 2; } &__select { display: flex; flex-direction: row; align-items: center; width: 100%; height: 100%; padding-left: 0.5rem; border-right: ${e=>e.$styles.borderStyle||"solid 2px #374151"}; border-bottom: ${e=>e.$styles.borderStyle||"solid 2px #374151"}; select { width: 100%; background: transparent url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='${e=>{var o;return((o=e.$styles.dateTextColor)==null?void 0:o.replace("#","%23"))||"%23fff"}}'><polygon points='0,0 100,0 50,50'/></svg>") no-repeat calc(100% - 10px) calc(50% + 3px); background-size: 10px; color: inherit; font-family: inherit; border: none; outline: none; font-size: 0.875rem; line-height: 1.25rem; -webkit-appearance: none; appearance: none; } } &__hours { position: relative; z-index: 1; border-right: ${e=>e.$styles.borderStyle||"solid 2px #374151"}; } &__hour { display: flex; justify-content: flex-end; height: 60px; padding-top: 0.25rem; padding-right: 0.5rem; position: relative; z-index: 2; font-size: 0.75rem; line-height: 1rem; &:not(:first-child) { border-top: ${e=>e.$styles.borderStyle||"solid 2px #374151"}; } } } .ftr-timetable-locations { display: flex; flex-direction: row; flex: 1; position: relative; } `,U=p.div` display: flex; flex: 1; flex-direction: column; .ftr-timetable-location { height: 60px; position: sticky; top: 0; z-index: 2; color: ${e=>e.$styles.locationTextColor||"inherit"}; background: ${e=>e.$styles.locationBackgroundColor||"#000"}; &__inner { display: flex; flex-direction: row; align-items: center; padding: 0 0.5rem; font-size: 0.875rem; line-height: 1.25rem; height: 100%; border-right: ${e=>e.$styles.borderStyle||"solid 2px #374151"}; border-bottom: ${e=>e.$styles.borderStyle||"solid 2px #374151"}; } &__name { width: 100%; text-overflow: ellipsis; overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; } } .ftr-timetable-location-items { display: flex; flex: 1; flex-direction: column; position: relative; background: ${e=>e.$styles.backgroundColor||"#1f2937"}; border-right: ${e=>e.$styles.borderStyle||"solid 2px #374151"}; } `,X=h.memo(function({location:e}){const{items:o,onLocationClick:a,renderLocation:l,styles:d}=g(),s=o.filter(i=>i.locationId===e.id),n=z(s);return t.jsxs(U,{$styles:d,children:[t.jsx("div",{className:"ftr-timetable-location ftr-timetable-location__vertical","data-testid":`timetable-location-${e.id}`,title:e.name,onClick:()=>a==null?void 0:a(e),style:e.style,children:l?l(e):t.jsx("div",{className:"ftr-timetable-location__inner",children:t.jsx("div",{className:"ftr-timetable-location__name",children:e.name})})}),t.jsx("div",{className:"ftr-timetable-location-items",children:n.map((i,r)=>t.jsx(C,{item:i.item,intersections:i.intersections,offset:i.offset},`tt_${i.item.id}_${r}`))})]})}),Z=({dateChange:e,locations:o,dates:a,hours:l,selectedDate:d})=>{const{ref:s,dateFormat:n,styles:i}=g();return t.jsx(K,{ref:s,"data-testid":"timetable-vertical",className:"ftr-timetable ftr-timetable-vertical",children:t.jsx(Q,{$styles:i,children:t.jsxs("div",{className:"ftr-timetable-datetime",style:{minWidth:`${o.length*200}px`},children:[t.jsxs("div",{className:"ftr-timetable-datetime__container",children:[t.jsx("div",{className:"ftr-timetable-datetime__date",children:t.jsx("div",{className:"ftr-timetable-datetime__select",children:t.jsx("select",{value:d,onChange:r=>e(r.target.value),children:a.map(r=>t.jsx("option",{value:r,children:m.format(new Date(r),n)},r))})})}),t.jsxs("div",{className:"ftr-timetable-datetime__hours",children:[l.map((r,c)=>t.jsx("div",{className:"ftr-timetable-datetime__hour",children:r.display},`hour_${c}`)),t.jsx(T,{date:d})]})]}),t.jsx("div",{className:"ftr-timetable-locations",children:o.map((r,c)=>t.jsx(X,{location:r},`location_${c}`))})]})})})},F=(e,o,a,l)=>h.useMemo(()=>{const s=[];if(!(e!=null&&e.length)||!l)return s;const n=m.addHours(m.startOfDay(new Date(l)),o),i=m.addHours(n,a);for(const r of e)(new Date(r.startDate)>=n&&new Date(r.startDate)<i||new Date(r.endDate)>n&&new Date(r.endDate)<=i)&&s.push(r);return s.sort((r,c)=>new Date(r.startDate).getTime()-new Date(c.startDate).getTime())},[l,o,a,e]),R=(e,o)=>h.useMemo(()=>{if(o)return o;const l=e.flatMap(r=>{const c=[];return r.startDate&&c.push(new Date(r.startDate).getTime()),r.endDate&&c.push(new Date(r.endDate).getTime()),c}).sort();if(!l.length)return[];const d=l[0],s=l[l.length-1],n=m.differenceInDays(s,d),i=[];for(let r=0;r<=n;r++){const c=m.format(m.addDays(new Date(d),r),"yyyy-MM-dd");i.push(c)}return i},[e,o]),ee=(e,o)=>h.useMemo(()=>{var d;let l=[];for(const s of e)if((d=s.items)!=null&&d.length)for(const n of s.items.filter(i=>{const r=new Date(i.startDate),c=new Date(i.endDate);return isNaN(r.getTime())||isNaN(c.getTime())?(console.error("Invalid startDate or endDate format",i),!1):!0}))l.push({...n,locationId:s.id});return o!=null&&o.length&&(l=l.concat(o.filter(s=>{const n=new Date(s.startDate),i=new Date(s.endDate);return isNaN(n.getTime())||isNaN(i.getTime())?(console.error("Invalid startDate or endDate format",s),!1):!0}))),l},[o,e]),te=({locations:e,items:o,dates:a,dateFormat:l="eee dd MMMM",onItemClick:d,onLocationClick:s,onDateChange:n,variant:i,renderItem:r,renderLocation:c,startingHour:f=6,numberOfHours:b=24,showTimeMarker:w=!0,styles:N})=>{const re=h.useMemo(()=>({backgroundColor:"#1f2937",dateBackgroundColor:"#1f2937",textColor:"#fff",borderStyle:"solid 2px #374151",...N}),[N]),[y,M]=h.useState(),I=ee(e,o),ie=F(I,f,b,y),_=R(I,a),S=h.useMemo(()=>i||(e.length>1?"horizontal":"vertical"),[i,e]),B=h.useMemo(()=>{const u=[];for(let $=f;$<f+b;$++){const W=$<24?$:$-24;u.push({hour:$,display:`${W<10?"0":""}${W}:00`})}return u},[b,f]);h.useEffect(()=>{M(u=>u||_[0])},[_]),h.useEffect(()=>{y&&(n==null||n(y))},[n,y]);const j=h.useCallback(u=>{M(u)},[]);return y?t.jsx(L,{startingHour:f,numberOfHours:b,onItemClick:d,onLocationClick:s,displayStyle:S,renderItem:r,renderLocation:c,dateFormat:l,selectedDate:y,showTimeMarker:w,items:ie,styles:re,children:S==="horizontal"?t.jsx(J,{dateChange:j,hours:B,locations:e,dates:_,selectedDate:y}):t.jsx(Z,{dateChange:j,hours:B,locations:e,dates:_,selectedDate:y})}):t.jsx(t.Fragment,{})};x.TimeTable=te,Object.defineProperty(x,Symbol.toStringTag,{value:"Module"})}); //# sourceMappingURL=index.umd.js.map