fluentui-react-calendar
Version:
A read-only calendar component with day, week, and month views for React applications
25 lines (24 loc) • 20.3 kB
JavaScript
(function(d,P){typeof exports=="object"&&typeof module<"u"?module.exports=P(require("react")):typeof define=="function"&&define.amd?define(["react"],P):(d=typeof globalThis<"u"?globalThis:d||self,d.FluentUIReactCalendar=P(d.React))})(this,function(d){"use strict";var P=document.createElement("style");P.textContent=`:root{--primary-color: #0078d4;--primary-light: #c7e0f4;--primary-dark: #106ebe;--text-primary: #323130;--text-secondary: #605e5c;--border-color: #edebe9;--bg-light: #faf9f8;--bg-white: #ffffff;--event-color: #0078d4;--event-hover: #106ebe;--selected-color: #deecf9}.calendar-container{font-family:Segoe UI,Tahoma,Geneva,Verdana,sans-serif;color:var(--text-primary);background-color:var(--bg-white);width:100%;height:100%;display:flex;flex-direction:column;overflow:hidden}.calendar-header{display:flex;justify-content:space-between;align-items:center;padding:12px 24px;border-bottom:1px solid var(--border-color);flex-shrink:0}.calendar-title h2{margin:0;font-size:20px;font-weight:600}.calendar-actions{display:flex;align-items:center;gap:8px}button{background-color:var(--bg-white);border:1px solid var(--border-color);border-radius:2px;padding:6px 12px;font-size:14px;cursor:pointer;transition:all .2s ease;color:var(--text-primary);display:flex;align-items:center;justify-content:center}button:hover{background-color:var(--bg-light)}.nav-button{font-size:18px;font-weight:700;padding:5px 10px;border:none}.today-button{font-weight:500}.view-switcher{display:flex;border:1px solid var(--border-color);border-radius:2px;overflow:hidden}.view-switcher button{border:none;border-radius:0;border-right:1px solid var(--border-color);margin:0;padding:8px 16px}.view-switcher button:last-child{border-right:none}.view-switcher button.active{background-color:var(--primary-color);color:#fff}.calendar-body{flex:1;display:flex;min-height:0;overflow:hidden;position:relative}.month-view{display:flex;flex-direction:column;width:100%;height:100%}.weekday-header{display:grid;grid-template-columns:repeat(7,1fr);text-align:center;border-bottom:1px solid var(--border-color);border-right:1px solid var(--border-color);font-weight:600;font-size:14px;background-color:var(--bg-white);flex-shrink:0}.weekday-header div{padding:12px;color:var(--text-secondary);border-left:1px solid var(--border-color)}.days-grid{display:grid;grid-template-columns:repeat(7,1fr);grid-auto-rows:1fr;border-left:1px solid var(--border-color);flex:1;overflow:auto;min-height:0;width:100%;height:100%}.calendar-day{border-right:1px solid var(--border-color);border-bottom:1px solid var(--border-color);padding:8px;position:relative;background-color:var(--bg-white);cursor:pointer;display:flex;flex-direction:column;overflow:hidden;aspect-ratio:1/1}.calendar-day:hover{background-color:var(--bg-light)}.calendar-day.empty{cursor:default}.calendar-day.today{background-color:#ffaa440d}.calendar-day.today .day-number{background-color:var(--primary-color);color:var(--bg-white)}.calendar-day.selected{background-color:var(--selected-color)}.day-header{display:flex;justify-content:flex-end;margin-bottom:4px}.day-number{display:flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:50%;font-weight:500}.day-events{flex:1;display:flex;flex-direction:column;gap:4px;overflow:hidden}.event-pill{background-color:var(--event-color);color:#fff;font-size:12px;padding:3px 8px;border-radius:3px;margin-bottom:3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:pointer;text-decoration:none}.event-pill:hover{background-color:var(--event-hover)}.event-more{font-size:12px;font-weight:500;color:var(--text-secondary);text-align:center;margin-top:2px}.week-view{display:flex;flex-direction:column;width:100%;height:100%;overflow:hidden}.week-days-container{display:flex;flex:1;width:100%;min-height:0;overflow:auto;border-left:1px solid var(--border-color);border-bottom:1px solid var(--border-color)}.week-day-column{flex:1;border-right:1px solid var(--border-color);display:flex;flex-direction:column;height:100%;cursor:pointer;min-width:0}.week-day-column:hover{background-color:var(--bg-light)}.week-day-column.today{background-color:#ffaa440d}.week-day-column.selected{background-color:var(--selected-color)}.week-day-header{padding:16px;text-align:center;border-bottom:1px solid var(--border-color);flex-shrink:0}.week-day-header .weekday{font-weight:600;color:var(--text-secondary);margin-bottom:8px}.week-day-header .date{font-size:24px;font-weight:500}.week-day-events{padding:12px;flex:1;overflow-y:auto;display:flex;flex-direction:column;gap:8px;min-height:70vh}.week-event{background-color:var(--event-color);color:#fff;border-radius:4px;padding:8px 12px;cursor:pointer;text-decoration:none;display:block;height:auto;white-space:normal;word-wrap:break-word;word-break:break-word;-webkit-hyphens:auto;hyphens:auto;line-height:1.4;font-size:13px}.week-event:hover{background-color:var(--event-hover)}.week-event-more{font-size:12px;color:var(--text-secondary);text-align:center;padding:4px;font-weight:500}.day-view{display:flex;flex-direction:column;width:100%;height:100%;overflow:hidden}.day-header{padding:12px;text-align:center;flex-shrink:0}.day-header h3{margin:0;font-weight:600}.day-body{display:flex;flex:1;min-height:0;overflow:hidden;width:100%}.time-column{width:80px;flex-shrink:0;border-right:1px solid var(--border-color);overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--text-secondary) transparent}.time-column::-webkit-scrollbar{width:6px}.time-column::-webkit-scrollbar-thumb{background-color:var(--text-secondary);border-radius:3px}.time-column::-webkit-scrollbar-track{background:transparent}.time-slot{height:60px;display:flex;align-items:flex-start;justify-content:center;padding:4px 8px;font-size:12px;color:var(--text-secondary);position:relative;border-bottom:1px solid var(--border-color)}.time-slot span{transform:translateY(-6px)}.events-column{flex:1;width:calc(100% - 80px);overflow-y:auto;min-width:0;scrollbar-width:thin;scrollbar-color:var(--text-secondary) transparent}.events-column::-webkit-scrollbar{width:6px}.events-column::-webkit-scrollbar-thumb{background-color:var(--text-secondary);border-radius:3px}.events-column::-webkit-scrollbar-track{background:transparent}.day-time-slot{height:60px;border-bottom:1px solid var(--border-color);padding:2px;position:relative}.day-event{background-color:var(--event-color);color:#fff;border-radius:3px;padding:8px;font-size:13px;position:absolute;width:calc(100% - 20px);z-index:1;cursor:pointer;min-height:50px;max-height:56px;overflow:hidden;text-decoration:none;display:block}.day-event:hover{background-color:var(--event-hover)}.event-time{font-weight:600;margin-bottom:4px}.event-title{font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.nav-icon{width:20px;height:20px;display:block}.nav-icon.left{transform:rotate(180deg)}@media (max-width: 768px){.calendar-header{flex-direction:column;gap:16px;padding:12px}}@media (max-width: 480px){.view-switcher button{padding:6px 10px;font-size:12px}}
/*$vite$:1*/`,document.head.appendChild(P);var W={exports:{}},I={};/**
* @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 re(){if(q)return I;q=1;var j=Symbol.for("react.transitional.element"),w=Symbol.for("react.fragment");function T(s,f,i){var _=null;if(i!==void 0&&(_=""+i),f.key!==void 0&&(_=""+f.key),"key"in f){i={};for(var A in f)A!=="key"&&(i[A]=f[A])}else i=f;return f=i.ref,{$$typeof:j,type:s,key:_,ref:f!==void 0?f:null,props:i}}return I.Fragment=w,I.jsx=T,I.jsxs=T,I}var L={};/**
* @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 ee;function oe(){return ee||(ee=1,process.env.NODE_ENV!=="production"&&function(){function j(e){if(e==null)return null;if(typeof e=="function")return e.$$typeof===u?null:e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case E:return"Fragment";case z:return"Profiler";case N:return"StrictMode";case H:return"Suspense";case o:return"SuspenseList";case v: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 k:return"Portal";case X:return(e.displayName||"Context")+".Provider";case G:return(e._context.displayName||"Context")+".Consumer";case $:var r=e.render;return e=e.displayName,e||(e=r.displayName||r.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case n:return r=e.displayName||null,r!==null?r:j(e.type)||"Memo";case a:r=e._payload,e=e._init;try{return j(e(r))}catch{}}return null}function w(e){return""+e}function T(e){try{w(e);var r=!1}catch{r=!0}if(r){r=console;var c=r.error,p=typeof Symbol=="function"&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||"Object";return c.call(r,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",p),w(e)}}function s(e){if(e===E)return"<>";if(typeof e=="object"&&e!==null&&e.$$typeof===a)return"<...>";try{var r=j(e);return r?"<"+r+">":"<...>"}catch{return"<...>"}}function f(){var e=y.A;return e===null?null:e.getOwner()}function i(){return Error("react-stack-top-frame")}function _(e){if(h.call(e,"key")){var r=Object.getOwnPropertyDescriptor(e,"key").get;if(r&&r.isReactWarning)return!1}return e.key!==void 0}function A(e,r){function c(){l||(l=!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)",r))}c.isReactWarning=!0,Object.defineProperty(e,"key",{get:c,configurable:!0})}function B(){var e=j(this.type);return m[e]||(m[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 U(e,r,c,p,O,S,Z,Q){return c=S.ref,e={$$typeof:J,type:e,key:r,props:S,_owner:O},(c!==void 0?c:null)!==null?Object.defineProperty(e,"ref",{enumerable:!1,get:B}):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:Z}),Object.defineProperty(e,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:Q}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}function D(e,r,c,p,O,S,Z,Q){var x=r.children;if(x!==void 0)if(p)if(g(x)){for(p=0;p<x.length;p++)V(x[p]);Object.freeze&&Object.freeze(x)}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 V(x);if(h.call(r,"key")){x=j(e);var F=Object.keys(r).filter(function(ae){return ae!=="key"});p=0<F.length?"{key: someKey, "+F.join(": ..., ")+": ...}":"{key: someKey}",R[x+p]||(F=0<F.length?"{"+F.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} />`,p,x,F,x),R[x+p]=!0)}if(x=null,c!==void 0&&(T(c),x=""+c),_(r)&&(T(r.key),x=""+r.key),"key"in r){c={};for(var K in r)K!=="key"&&(c[K]=r[K])}else c=r;return x&&A(c,typeof e=="function"?e.displayName||e.name||"Unknown":e),U(e,x,S,O,f(),c,Z,Q)}function V(e){typeof e=="object"&&e!==null&&e.$$typeof===J&&e._store&&(e._store.validated=1)}var M=d,J=Symbol.for("react.transitional.element"),k=Symbol.for("react.portal"),E=Symbol.for("react.fragment"),N=Symbol.for("react.strict_mode"),z=Symbol.for("react.profiler"),G=Symbol.for("react.consumer"),X=Symbol.for("react.context"),$=Symbol.for("react.forward_ref"),H=Symbol.for("react.suspense"),o=Symbol.for("react.suspense_list"),n=Symbol.for("react.memo"),a=Symbol.for("react.lazy"),v=Symbol.for("react.activity"),u=Symbol.for("react.client.reference"),y=M.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,h=Object.prototype.hasOwnProperty,g=Array.isArray,b=console.createTask?console.createTask:function(){return null};M={"react-stack-bottom-frame":function(e){return e()}};var l,m={},C=M["react-stack-bottom-frame"].bind(M,i)(),Y=b(s(i)),R={};L.Fragment=E,L.jsx=function(e,r,c,p,O){var S=1e4>y.recentlyCreatedOwnerStacks++;return D(e,r,c,!1,p,O,S?Error("react-stack-top-frame"):C,S?b(s(e)):Y)},L.jsxs=function(e,r,c,p,O){var S=1e4>y.recentlyCreatedOwnerStacks++;return D(e,r,c,!0,p,O,S?Error("react-stack-top-frame"):C,S?b(s(e)):Y)}}()),L}var te;function ne(){return te||(te=1,process.env.NODE_ENV==="production"?W.exports=re():W.exports=oe()),W.exports}var t=ne();return({events:j})=>{const[w,T]=d.useState(new Date),[s,f]=d.useState("month"),[i,_]=d.useState(new Date),A=t.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",width:"32",height:"32",viewBox:"0 0 12 12",className:"nav-icon",children:t.jsx("path",{fill:"currentColor",d:"M4.47 2.22a.75.75 0 0 0 0 1.06L7.19 6L4.47 8.72a.75.75 0 0 0 1.06 1.06l3.25-3.25a.75.75 0 0 0 0-1.06L5.53 2.22a.75.75 0 0 0-1.06 0"})}),B=t.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",width:"32",height:"32",viewBox:"0 0 12 12",className:"nav-icon left",children:t.jsx("path",{fill:"currentColor",d:"M4.47 2.22a.75.75 0 0 0 0 1.06L7.19 6L4.47 8.72a.75.75 0 0 0 1.06 1.06l3.25-3.25a.75.75 0 0 0 0-1.06L5.53 2.22a.75.75 0 0 0-1.06 0"})}),U=d.useCallback(o=>{const n=String(o.getDate()).padStart(2,"0"),a=String(o.getMonth()+1).padStart(2,"0"),v=o.getFullYear();return`${n}-${a}-${v}`},[]),D=d.useCallback(o=>{const n=U(o);return j[n]||[]},[j,U]),V=d.useCallback(()=>{T(o=>{const n=new Date(o);return s==="month"?n.setMonth(o.getMonth()-1):s==="week"?n.setDate(o.getDate()-7):s==="day"&&n.setDate(o.getDate()-1),n})},[s]),M=d.useCallback(()=>{T(o=>{const n=new Date(o);return s==="month"?n.setMonth(o.getMonth()+1):s==="week"?n.setDate(o.getDate()+7):s==="day"&&n.setDate(o.getDate()+1),n})},[s]),J=d.useCallback(()=>{T(new Date),_(new Date)},[]),k=d.useCallback(o=>{const[n]=o.split(":"),a=parseInt(n,10),v=a>=12?"PM":"AM";return`${a%12||12}:${o.split(":")[1]} ${v}`},[]),E=d.useCallback((o,n)=>{n.stopPropagation(),o&&window.open(o,"_blank")},[]),N=d.useMemo(()=>{const o=(l,m)=>new Date(l,m+1,0).getDate(),n=(l,m)=>new Date(l,m,1).getDay(),a=w.getFullYear(),v=w.getMonth(),u=o(a,v),y=n(a,v),h=[];for(let l=0;l<24;l++){const m=l.toString().padStart(2,"0"),C=l%12||12,Y=l>=12?"PM":"AM";h.push({hour:l,time:`${m}:00`,time12:`${C}:00 ${Y}`})}const g=[],b=new Date(w);b.setDate(w.getDate()-w.getDay());for(let l=0;l<7;l++){const m=new Date(b);m.setDate(b.getDate()+l),g.push(m)}return{year:a,month:v,daysInMonth:u,firstDay:y,timeSlots:h,daysOfWeek:g}},[w]),z=d.useCallback(()=>{const{year:o,month:n,daysInMonth:a,firstDay:v}=N,u=[],y=new Date;for(let h=0;h<v;h++)u.push(t.jsx("div",{className:"calendar-day empty"},`empty-${h}`));for(let h=1;h<=a;h++){const g=new Date(o,n,h),b=D(g),l=b.slice(0,2),m=b.length>2?b.length-2:0,C=g.getDate()===y.getDate()&&g.getMonth()===y.getMonth()&&g.getFullYear()===y.getFullYear(),Y=g.getDate()===i.getDate()&&g.getMonth()===i.getMonth()&&g.getFullYear()===i.getFullYear();u.push(t.jsxs("div",{className:`calendar-day ${C?"today":""} ${Y?"selected":""}`,onClick:()=>{_(new Date(o,n,h)),f("day")},children:[t.jsx("div",{className:"day-header",children:t.jsx("span",{className:"day-number",children:h})}),t.jsxs("div",{className:"day-events",children:[l.map((R,e)=>t.jsxs("a",{className:"event-pill",href:R.link,target:"_blank",rel:"noopener noreferrer",onClick:r=>E(R.link,r),title:`${k(R.time)} - ${R.event}`,children:[k(R.time)," - ",R.event]},e)),m>0&&t.jsxs("div",{className:"event-more",children:["+",m," more"]})]})]},`day-${h}`))}return t.jsxs("div",{className:"month-view",children:[t.jsxs("div",{className:"weekday-header",children:[t.jsx("div",{children:"Sunday"}),t.jsx("div",{children:"Monday"}),t.jsx("div",{children:"Tuesday"}),t.jsx("div",{children:"Wednesday"}),t.jsx("div",{children:"Thursday"}),t.jsx("div",{children:"Friday"}),t.jsx("div",{children:"Saturday"})]}),t.jsx("div",{className:"days-grid",children:u})]})},[N,D,i,k,E]),G=d.useCallback(()=>{const{daysOfWeek:o}=N,n=new Date;return t.jsx("div",{className:"week-view",children:t.jsx("div",{className:"week-days-container",children:o.map((a,v)=>{const u=D(a),y=a.getDate()===n.getDate()&&a.getMonth()===n.getMonth()&&a.getFullYear()===n.getFullYear(),h=a.getDate()===i.getDate()&&a.getMonth()===i.getMonth()&&a.getFullYear()===i.getFullYear(),g=u.slice(0,4),b=u.length>4?u.length-4:0;return t.jsxs("div",{className:`week-day-column ${y?"today":""} ${h?"selected":""}`,onClick:()=>{_(new Date(a)),f("day")},children:[t.jsxs("div",{className:"week-day-header",children:[t.jsx("div",{className:"weekday",children:a.toLocaleDateString("en-US",{weekday:"long"})}),t.jsx("div",{className:"date",children:a.getDate()})]}),t.jsxs("div",{className:"week-day-events",children:[g.map((l,m)=>t.jsxs("a",{className:"week-event",href:l.link,target:"_blank",rel:"noopener noreferrer",onClick:C=>E(l.link,C),title:`${k(l.time)} - ${l.event}`,children:[t.jsx("div",{className:"event-time",children:k(l.time)}),t.jsx("div",{className:"event-title",children:l.event})]},m)),b>0&&t.jsxs("div",{className:"week-event-more",children:["+",b," more"]})]})]},v)})})})},[N,D,i,k,E]),X=d.useCallback(()=>{const{timeSlots:o}=N,n=D(i);return t.jsxs("div",{className:"day-view",children:[t.jsx("div",{className:"day-header",children:t.jsx("h3",{children:i.toLocaleDateString("en-US",{weekday:"long",month:"long",day:"numeric",year:"numeric"})})}),t.jsxs("div",{className:"day-body",children:[t.jsx("div",{className:"time-column",children:o.map(a=>t.jsx("div",{className:"time-slot",children:t.jsx("span",{children:a.time12})},a.time))}),t.jsx("div",{className:"events-column",children:o.map(a=>{const v=n.filter(u=>u.time.startsWith(a.hour.toString().padStart(2,"0")));return t.jsx("div",{className:"day-time-slot",children:v.map((u,y)=>t.jsxs("a",{className:"day-event",href:u.link,target:"_blank",rel:"noopener noreferrer",onClick:h=>E(u.link,h),title:`${k(u.time)} - ${u.event}`,children:[t.jsx("div",{className:"event-time",children:k(u.time)}),t.jsx("div",{className:"event-title",children:u.event})]},y))},a.time)})})]})]})},[N,D,i,k,E]),$=d.useMemo(()=>{switch(s){case"month":return z();case"week":return G();case"day":return X();default:return z()}},[s,z,G,X]),H=d.useMemo(()=>{if(s==="month")return t.jsx("h2",{children:w.toLocaleDateString("en-US",{month:"long",year:"numeric"})});if(s==="week"){const{daysOfWeek:o}=N;return t.jsxs("h2",{children:[o[0].toLocaleDateString("en-US",{month:"short",day:"numeric"})," - ",o[6].toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric"})]})}else if(s==="day")return t.jsx("h2",{children:i.toLocaleDateString("en-US",{month:"long",day:"numeric",year:"numeric"})})},[s,w,i,N]);return t.jsxs("div",{className:"calendar-container",children:[t.jsxs("div",{className:"calendar-header",children:[t.jsx("div",{style:{width:"200px"},children:t.jsx("div",{className:"calendar-title",children:H})}),t.jsxs("div",{className:"calendar-actions",children:[t.jsx("button",{onClick:V,className:"nav-button",children:B}),t.jsx("button",{onClick:J,className:"today-button",children:"Today"}),t.jsx("button",{onClick:M,className:"nav-button",children:A})]}),t.jsxs("div",{className:"view-switcher",children:[t.jsx("button",{onClick:()=>f("day"),className:s==="day"?"active":"",children:"Day"}),t.jsx("button",{onClick:()=>f("week"),className:s==="week"?"active":"",children:"Week"}),t.jsx("button",{onClick:()=>f("month"),className:s==="month"?"active":"",children:"Month"})]})]}),t.jsx("div",{className:"calendar-body",children:$})]})}});
//# sourceMappingURL=index.cjs.map