@object-ui/plugin-calendar 3.0.3 → 3.1.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/.turbo/turbo-build.log +6 -6
- package/dist/index.js +959 -618
- package/dist/index.umd.cjs +2 -2
- package/dist/src/CalendarView.d.ts.map +1 -1
- package/dist/src/ObjectCalendar.d.ts +2 -0
- package/dist/src/ObjectCalendar.d.ts.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/package.json +11 -10
- package/src/CalendarView.test.tsx +1 -1
- package/src/CalendarView.tsx +117 -25
- package/src/ObjectCalendar.tsx +20 -14
- package/src/__tests__/accessibility.test.tsx +2 -2
- package/src/__tests__/calendar-bugfixes.test.tsx +230 -0
- package/src/__tests__/calendar-optimizations.test.tsx +178 -0
- package/src/__tests__/view-states.test.tsx +3 -3
- package/src/calendar-view-renderer.tsx +4 -10
- package/src/index.tsx +3 -3
package/dist/index.umd.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
(function(
|
|
1
|
+
(function(U,g){typeof exports=="object"&&typeof module<"u"?g(exports,require("react"),require("@object-ui/core"),require("@object-ui/react"),require("lucide-react"),require("@object-ui/components")):typeof define=="function"&&define.amd?define(["exports","react","@object-ui/core","@object-ui/react","lucide-react","@object-ui/components"],g):(U=typeof globalThis<"u"?globalThis:U||self,g(U.ObjectUIPluginCalendar={},U.React,U.ObjectUICore,U.ObjectUIReact,U.LucideReact,U.ObjectUIComponents))})(this,(function(U,g,J,ue,Z,C){"use strict";function Te(e){const r=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const n in e)if(n!=="default"){const c=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(r,n,c.get?c:{enumerable:!0,get:()=>e[n]})}}return r.default=e,Object.freeze(r)}const V=Te(g);var ee={exports:{}},X={};var de;function Ne(){if(de)return X;de=1;var e=Symbol.for("react.transitional.element"),r=Symbol.for("react.fragment");function n(c,i,o){var d=null;if(o!==void 0&&(d=""+o),i.key!==void 0&&(d=""+i.key),"key"in i){o={};for(var v in i)v!=="key"&&(o[v]=i[v])}else o=i;return i=o.ref,{$$typeof:e,type:c,key:d,ref:i!==void 0?i:null,props:o}}return X.Fragment=r,X.jsx=n,X.jsxs=n,X}var K={};var fe;function Oe(){return fe||(fe=1,process.env.NODE_ENV!=="production"&&(function(){function e(t){if(t==null)return null;if(typeof t=="function")return t.$$typeof===_?null:t.displayName||t.name||null;if(typeof t=="string")return t;switch(t){case A:return"Fragment";case M:return"Profiler";case F:return"StrictMode";case I:return"Suspense";case T:return"SuspenseList";case f: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 w:return"Portal";case b:return t.displayName||"Context";case Y:return(t._context.displayName||"Context")+".Consumer";case O:var x=t.render;return t=t.displayName,t||(t=x.displayName||x.name||"",t=t!==""?"ForwardRef("+t+")":"ForwardRef"),t;case P:return x=t.displayName||null,x!==null?x:e(t.type)||"Memo";case D:x=t._payload,t=t._init;try{return e(t(x))}catch{}}return null}function r(t){return""+t}function n(t){try{r(t);var x=!1}catch{x=!0}if(x){x=console;var j=x.error,k=typeof Symbol=="function"&&Symbol.toStringTag&&t[Symbol.toStringTag]||t.constructor.name||"Object";return j.call(x,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",k),r(t)}}function c(t){if(t===A)return"<>";if(typeof t=="object"&&t!==null&&t.$$typeof===D)return"<...>";try{var x=e(t);return x?"<"+x+">":"<...>"}catch{return"<...>"}}function i(){var t=u.A;return t===null?null:t.getOwner()}function o(){return Error("react-stack-top-frame")}function d(t){if(S.call(t,"key")){var x=Object.getOwnPropertyDescriptor(t,"key").get;if(x&&x.isReactWarning)return!1}return t.key!==void 0}function v(t,x){function j(){Q||(Q=!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)",x))}j.isReactWarning=!0,Object.defineProperty(t,"key",{get:j,configurable:!0})}function y(){var t=e(this.type);return re[t]||(re[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 p(t,x,j,k,z,G){var R=j.ref;return t={$$typeof:h,type:t,key:x,props:j,_owner:k},(R!==void 0?R:null)!==null?Object.defineProperty(t,"ref",{enumerable:!1,get:y}):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:z}),Object.defineProperty(t,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:G}),Object.freeze&&(Object.freeze(t.props),Object.freeze(t)),t}function E(t,x,j,k,z,G){var R=x.children;if(R!==void 0)if(k)if(L(R)){for(k=0;k<R.length;k++)a(R[k]);Object.freeze&&Object.freeze(R)}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 a(R);if(S.call(x,"key")){R=e(t);var W=Object.keys(x).filter(function(it){return it!=="key"});k=0<W.length?"{key: someKey, "+W.join(": ..., ")+": ...}":"{key: someKey}",$[R+k]||(W=0<W.length?"{"+W.join(": ..., ")+": ...}":"{}",console.error(`A props object containing a "key" prop is being spread into JSX:
|
|
2
2
|
let props = %s;
|
|
3
3
|
<%s {...props} />
|
|
4
4
|
React keys must be passed directly to JSX without using spread:
|
|
5
5
|
let props = %s;
|
|
6
|
-
<%s key={someKey} {...props} />`,E,C,z,C),R[C+E]=!0)}if(C=null,w!==void 0&&(l(w),C=""+w),g(f)&&(l(f.key),C=""+f.key),"key"in f){w={};for(var le in f)le!=="key"&&(w[le]=f[le])}else w=f;return C&&u(w,typeof e=="function"?e.displayName||e.name||"Unknown":e),d(e,C,w,m(),H,X)}function a(e){b(e)?e._store&&(e._store.validated=1):typeof e=="object"&&e!==null&&e.$$typeof===i&&(e._payload.status==="fulfilled"?b(e._payload.value)&&e._payload.value._store&&(e._payload.value._store.validated=1):e._store&&(e._store.validated=1))}function b(e){return typeof e=="object"&&e!==null&&e.$$typeof===N}var o=p,N=Symbol.for("react.transitional.element"),$=Symbol.for("react.portal"),V=Symbol.for("react.fragment"),x=Symbol.for("react.strict_mode"),F=Symbol.for("react.profiler"),P=Symbol.for("react.consumer"),_=Symbol.for("react.context"),M=Symbol.for("react.forward_ref"),S=Symbol.for("react.suspense"),I=Symbol.for("react.suspense_list"),Y=Symbol.for("react.memo"),i=Symbol.for("react.lazy"),T=Symbol.for("react.activity"),j=Symbol.for("react.client.reference"),W=o.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,q=Object.prototype.hasOwnProperty,ne=Array.isArray,G=console.createTask?console.createTask:function(){return null};o={react_stack_bottom_frame:function(e){return e()}};var U,D={},O=o.react_stack_bottom_frame.bind(o,c)(),k=G(s(c)),R={};B.Fragment=V,B.jsx=function(e,f,w){var E=1e4>W.recentlyCreatedOwnerStacks++;return y(e,f,w,!1,E?Error("react-stack-top-frame"):O,E?G(s(e)):k)},B.jsxs=function(e,f,w){var E=1e4>W.recentlyCreatedOwnerStacks++;return y(e,f,w,!0,E?Error("react-stack-top-frame"):O,E?G(s(e)):k)}})()),B}var ce;function pe(){return ce||(ce=1,process.env.NODE_ENV==="production"?Z.exports=ge():Z.exports=he()),Z.exports}var r=pe();const ee="bg-blue-500 text-white";function te({events:t=[],view:n="month",currentDate:l=new Date,locale:s="default",onEventClick:m,onDateClick:c,onViewChange:g,onNavigate:u,onAddClick:h,onEventDrop:d,className:y}){const[a,b]=L.useState(n),[o,N]=L.useState(l);L.useEffect(()=>{N(l)},[l]),L.useEffect(()=>{b(n)},[n]);const $=L.useRef(g);$.current=g,L.useEffect(()=>{const i=window.matchMedia("(max-width: 639px)"),T=j=>{j.matches&&(b("day"),$.current?.("day"))};return T(i),i.addEventListener("change",T),()=>i.removeEventListener("change",T)},[]);const V=()=>{const i=new Date(o);a==="month"?i.setMonth(i.getMonth()-1):a==="week"?i.setDate(i.getDate()-7):i.setDate(i.getDate()-1),N(i),u?.(i)},x=()=>{const i=new Date(o);a==="month"?i.setMonth(i.getMonth()+1):a==="week"?i.setDate(i.getDate()+7):i.setDate(i.getDate()+1),N(i),u?.(i)},F=()=>{const i=new Date;N(i),u?.(i)},P=i=>{b(i),g?.(i)},_=()=>{if(a==="month")return o.toLocaleDateString(s,{month:"long",year:"numeric"});if(a==="week"){const i=de(o),T=new Date(i);return T.setDate(T.getDate()+6),`${i.toLocaleDateString(s,{month:"short",day:"numeric"})} - ${T.toLocaleDateString(s,{month:"short",day:"numeric",year:"numeric"})}`}else return o.toLocaleDateString(s,{weekday:"long",month:"long",day:"numeric",year:"numeric"})},M=L.useRef(0),S=i=>{M.current=i.touches[0].clientX},I=i=>{const T=M.current-i.changedTouches[0].clientX;if(Math.abs(T)>50){const j=new Date(o);a==="day"?j.setDate(j.getDate()+(T>0?1:-1)):a==="week"?j.setDate(j.getDate()+(T>0?7:-7)):j.setMonth(j.getMonth()+(T>0?1:-1)),N(j),u?.(j)}},Y=i=>{i&&(N(i),u?.(i))};return r.jsxs("div",{role:"region","aria-label":"Calendar",className:v.cn("flex flex-col h-full bg-background",y),children:[r.jsxs("div",{className:"flex items-center justify-between p-4 border-b",children:[r.jsxs("div",{className:"flex items-center gap-4",children:[r.jsxs("div",{className:"flex items-center bg-muted/50 rounded-lg p-1 gap-1",children:[r.jsx(v.Button,{variant:"ghost",size:"sm",onClick:F,className:"h-8","aria-label":"Go to today",children:"Today"}),r.jsx("div",{className:"h-4 w-px bg-border mx-1"}),r.jsx(v.Button,{variant:"ghost",size:"icon","aria-label":"Previous period",onClick:V,className:"h-8 w-8",children:r.jsx(Q.ChevronLeftIcon,{className:"h-4 w-4"})}),r.jsx(v.Button,{variant:"ghost",size:"icon","aria-label":"Next period",onClick:x,className:"h-8 w-8",children:r.jsx(Q.ChevronRightIcon,{className:"h-4 w-4"})})]}),r.jsxs(v.Popover,{children:[r.jsx(v.PopoverTrigger,{asChild:!0,children:r.jsxs(v.Button,{variant:"ghost","aria-label":`Current date: ${_()}`,className:v.cn("text-xl font-semibold h-auto px-3 py-1 hover:bg-muted/50 transition-colors","flex items-center gap-2"),children:[r.jsx(Q.CalendarIcon,{className:"h-5 w-5 text-muted-foreground"}),r.jsx("span",{children:_()})]})}),r.jsx(v.PopoverContent,{className:"w-auto p-0",align:"start",children:r.jsx(v.Calendar,{mode:"single",selected:o,onSelect:Y,initialFocus:!0,fromYear:2e3,toYear:2050})})]})]}),r.jsxs("div",{className:"flex items-center gap-2",children:[r.jsxs(v.Select,{value:a,onValueChange:P,children:[r.jsx(v.SelectTrigger,{className:"w-32 bg-background",children:r.jsx(v.SelectValue,{})}),r.jsxs(v.SelectContent,{children:[r.jsx(v.SelectItem,{value:"day",children:"Day"}),r.jsx(v.SelectItem,{value:"week",children:"Week"}),r.jsx(v.SelectItem,{value:"month",children:"Month"})]})]}),h&&r.jsxs(v.Button,{onClick:h,size:"sm",className:"gap-1",children:[r.jsx(Q.PlusIcon,{className:"h-4 w-4"}),"New"]})]})]}),r.jsxs("div",{className:"flex-1 overflow-auto",onTouchStart:S,onTouchEnd:I,children:[a==="month"&&r.jsx(xe,{date:o,events:t,onEventClick:m,onDateClick:c,onEventDrop:d}),a==="week"&&r.jsx(De,{date:o,events:t,locale:s,onEventClick:m,onDateClick:c}),a==="day"&&r.jsx(ye,{date:o,events:t,onEventClick:m,onDateClick:c})]})]})}function de(t){const n=new Date(t),l=n.getDay(),s=n.getDate()-l;return n.setDate(s),n}function be(t){const n=t.getFullYear(),l=t.getMonth(),s=new Date(n,l,1),m=new Date(n,l+1,0),c=s.getDay(),g=[];for(let h=c-1;h>=0;h--){const d=new Date(s.getTime());d.setDate(d.getDate()-(h+1)),g.push(d)}for(let h=1;h<=m.getDate();h++)g.push(new Date(n,l,h));const u=42-g.length;for(let h=1;h<=u;h++){const d=new Date(m.getTime());d.setDate(d.getDate()+h),g.push(d)}return g}function ue(t,n){return t.getFullYear()===n.getFullYear()&&t.getMonth()===n.getMonth()&&t.getDate()===n.getDate()}function re(t,n){return n.filter(l=>{const s=new Date(l.start),m=l.end?new Date(l.end):new Date(s),c=new Date(t);c.setHours(0,0,0,0);const g=new Date(t);g.setHours(23,59,59,999);const u=new Date(s);u.setHours(0,0,0,0);const h=new Date(m);return h.setHours(23,59,59,999),c<=h&&g>=u})}function xe({date:t,events:n,onEventClick:l,onDateClick:s,onEventDrop:m}){const c=be(t),g=new Date,u=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],[h,d]=L.useState(null),[y,a]=L.useState(null),b=(x,F)=>{d(F.id),x.dataTransfer.effectAllowed="move",x.dataTransfer.setData("text/plain",String(F.id))},o=()=>{d(null),a(null)},N=(x,F)=>{x.preventDefault(),x.dataTransfer.dropEffect="move",a(F)},$=x=>{x.currentTarget.contains(x.relatedTarget)||a(null)},V=(x,F)=>{if(x.preventDefault(),a(null),d(null),!m)return;const P=x.dataTransfer.getData("text/plain"),_=n.find(j=>String(j.id)===P);if(!_)return;const M=new Date(_.start),S=new Date(M);S.setHours(0,0,0,0);const I=new Date(F);I.setHours(0,0,0,0);const Y=I.getTime()-S.getTime();if(Y===0)return;const i=new Date(M.getTime()+Y);let T;_.end&&(T=new Date(new Date(_.end).getTime()+Y)),m(_,i,T)};return r.jsxs("div",{className:"flex flex-col h-full",children:[r.jsx("div",{role:"row",className:"grid grid-cols-7 border-b",children:u.map(x=>r.jsx("div",{role:"columnheader",className:"p-2 text-center text-sm font-medium text-muted-foreground border-r last:border-r-0",children:x},x))}),r.jsx("div",{role:"grid","aria-label":"Calendar grid",className:"grid grid-cols-7 flex-1 auto-rows-fr",children:c.map((x,F)=>{const P=re(x,n),_=x.getMonth()===t.getMonth(),M=ue(x,g);return r.jsxs("div",{role:"gridcell","aria-label":`${x.toLocaleDateString("default",{weekday:"long",month:"long",day:"numeric",year:"numeric"})}${P.length>0?`, ${P.length} event${P.length>1?"s":""}`:""}`,className:v.cn("border-b border-r last:border-r-0 p-2 min-h-[100px] cursor-pointer hover:bg-accent/50",!_&&"bg-muted/30 text-muted-foreground",y===F&&"ring-2 ring-primary"),onClick:()=>s?.(x),onDragOver:S=>N(S,F),onDragLeave:$,onDrop:S=>V(S,x),children:[r.jsx("div",{className:v.cn("text-sm font-medium mb-1",M&&"inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground h-6 w-6"),...M?{"aria-current":"date"}:{},children:x.getDate()}),r.jsxs("div",{className:"space-y-1",children:[P.slice(0,3).map(S=>r.jsx("div",{role:"button","aria-label":S.title,draggable:!!m,onDragStart:I=>b(I,S),onDragEnd:o,className:v.cn("text-xs px-2 py-1 rounded truncate cursor-pointer hover:opacity-80",S.color||ee,h===S.id&&"opacity-50"),style:S.color&&S.color.startsWith("#")?{backgroundColor:S.color}:void 0,onClick:I=>{I.stopPropagation(),l?.(S)},children:S.title},S.id)),P.length>3&&r.jsxs("div",{className:"text-xs text-muted-foreground px-2",children:["+",P.length-3," more"]})]})]},F)})})]})}function De({date:t,events:n,locale:l="default",onEventClick:s,onDateClick:m}){const c=L.useRef(null),g=a=>{m&&(c.current=setTimeout(()=>{m(a)},500))},u=()=>{c.current&&(clearTimeout(c.current),c.current=null)},h=de(t),d=Array.from({length:7},(a,b)=>{const o=new Date(h);return o.setDate(o.getDate()+b),o}),y=new Date;return r.jsxs("div",{className:"flex flex-col h-full",children:[r.jsx("div",{className:"grid grid-cols-7 border-b",children:d.map(a=>{const b=ue(a,y);return r.jsxs("div",{className:"p-3 text-center border-r last:border-r-0",children:[r.jsx("div",{className:"text-sm font-medium text-muted-foreground",children:a.toLocaleDateString(l,{weekday:"short"})}),r.jsx("div",{className:v.cn("text-lg font-semibold mt-1",b&&"inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground h-8 w-8"),children:a.getDate()})]},a.toISOString())})}),r.jsx("div",{role:"grid",className:"grid grid-cols-7 flex-1",children:d.map(a=>{const b=re(a,n);return r.jsx("div",{role:"gridcell","aria-label":`${a.toLocaleDateString("default",{weekday:"long",month:"long",day:"numeric",year:"numeric"})}${b.length>0?`, ${b.length} event${b.length>1?"s":""}`:""}`,className:"border-r last:border-r-0 p-2 min-h-[400px] cursor-pointer hover:bg-accent/50",onClick:()=>m?.(a),onTouchStart:()=>g(a),onTouchEnd:u,children:r.jsx("div",{className:"space-y-2",children:b.map(o=>r.jsxs("div",{role:"button","aria-label":o.title,className:v.cn("text-xs sm:text-sm px-2 sm:px-3 py-1.5 sm:py-2 rounded cursor-pointer hover:opacity-80",o.color||ee),style:o.color&&o.color.startsWith("#")?{backgroundColor:o.color}:void 0,onClick:N=>{N.stopPropagation(),s?.(o)},children:[r.jsx("div",{className:"font-medium truncate",children:o.title}),!o.allDay&&r.jsx("div",{className:"text-xs opacity-90 mt-1",children:o.start.toLocaleTimeString("default",{hour:"numeric",minute:"2-digit"})})]},o.id))})},a.toISOString())})})]})}function ye({date:t,events:n,onEventClick:l,onDateClick:s}){const m=re(t,n),c=Array.from({length:24},(d,y)=>y),g=L.useRef(null),u=d=>{s&&(g.current=setTimeout(()=>{const y=new Date(t);y.setHours(d,0,0,0),s(y)},500))},h=()=>{g.current&&(clearTimeout(g.current),g.current=null)};return r.jsx("div",{className:"flex flex-col h-full",children:r.jsx("div",{role:"list",className:"flex-1 overflow-auto",children:c.map(d=>{const y=m.filter(a=>a.allDay?d===0:a.start.getHours()===d);return r.jsxs("div",{role:"listitem",className:"flex border-b min-h-[60px]",children:[r.jsx("div",{className:"w-20 p-2 text-sm text-muted-foreground border-r",children:d===0?"12 AM":d<12?`${d} AM`:d===12?"12 PM":`${d-12} PM`}),r.jsx("div",{className:"flex-1 p-2 space-y-2",onTouchStart:()=>u(d),onTouchEnd:h,children:y.map(a=>r.jsxs("div",{"aria-label":a.title,className:v.cn("px-2 sm:px-3 py-1.5 sm:py-2 rounded cursor-pointer hover:opacity-80",a.color||ee),style:a.color&&a.color.startsWith("#")?{backgroundColor:a.color}:void 0,onClick:()=>l?.(a),children:[r.jsx("div",{className:"font-medium truncate",children:a.title}),!a.allDay&&r.jsxs("div",{className:"text-xs opacity-90 mt-1",children:[a.start.toLocaleTimeString("default",{hour:"numeric",minute:"2-digit"}),a.end&&` - ${a.end.toLocaleTimeString("default",{hour:"numeric",minute:"2-digit"})}`]})]},a.id))})]},d)})})})}function ve(t){const{onRefresh:n,threshold:l=80,enabled:s=!0}=t,m=p.useRef(null),[c,g]=p.useState(!1),[u,h]=p.useState(0),d=p.useRef(0),y=p.useCallback(o=>{if(!s||c)return;const N=m.current;N&&N.scrollTop===0&&(d.current=o.touches[0].clientY)},[s,c]),a=p.useCallback(o=>{if(!s||c||!d.current)return;const $=o.touches[0].clientY-d.current;$>0&&h(Math.min($,l*1.5))},[s,c,l]),b=p.useCallback(async()=>{if(!(!s||c)){if(u>=l){g(!0);try{await n()}finally{g(!1)}}h(0),d.current=0}},[s,c,u,l,n]);return p.useEffect(()=>{const o=m.current;if(!(!o||!s))return o.addEventListener("touchstart",y,{passive:!0}),o.addEventListener("touchmove",a,{passive:!0}),o.addEventListener("touchend",b,{passive:!0}),()=>{o.removeEventListener("touchstart",y),o.removeEventListener("touchmove",a),o.removeEventListener("touchend",b)}},[y,a,b,s]),{ref:m,isRefreshing:c,pullDistance:u}}const je=p.createContext(null);je.displayName="MobileContext";function we(t){return"data"in t&&t.data?t.data:"staticData"in t&&t.staticData?{provider:"value",items:t.staticData}:t.objectName?{provider:"object",object:t.objectName}:null}function Se(t){if(t){if(typeof t=="string"){const n=t.split(" "),l=n[0],s=n[1]?.toLowerCase()==="desc"?"desc":"asc";return{[l]:s}}if(Array.isArray(t))return t.reduce((n,l)=>(l.field&&l.order&&(n[l.field]=l.order),n),{})}}function Ee(t){return"filter"in t&&t.filter&&typeof t.filter=="object"&&"calendar"in t.filter?t.filter.calendar:t.calendar?t.calendar:t.startDateField||t.dateField?{startDateField:t.startDateField||t.dateField,endDateField:t.endDateField||t.endField,titleField:t.titleField||"name",colorField:t.colorField,allDayField:t.allDayField}:null}const fe=({schema:t,dataSource:n,className:l,onEventClick:s,onRowClick:m,onDateClick:c,onNavigate:g,onViewChange:u,...h})=>{const[d,y]=p.useState([]),[a,b]=p.useState(!0),[o,N]=p.useState(null),[$,V]=p.useState(null),[x,F]=p.useState(new Date),[P,_]=p.useState("month"),[M,S]=p.useState(0),I=p.useCallback(async()=>{S(D=>D+1)},[]),{ref:Y,isRefreshing:i,pullDistance:T}=ve({onRefresh:I,enabled:!!n&&!!t.objectName}),j=p.useMemo(()=>we(t),[t.data,t.staticData,t.objectName]),W=p.useMemo(()=>Ee(t),[t.filter,t.calendar,t.dateField,t.endField,t.titleField,t.colorField]),q=j?.provider==="value";p.useEffect(()=>{let D=!0;return(async()=>{try{if(!D)return;if(b(!0),q&&j?.provider==="value"){D&&(y(j.items),b(!1));return}if(t.data||h.data){const k=t.data||h.data;if(Array.isArray(k)){y(k),b(!1);return}}if(!n)throw new Error("DataSource required for object/api providers");if(j?.provider==="object"){const k=j.object,R=await n.find(k,{$filter:t.filter,$orderby:Se(t.sort)});let e=[];Array.isArray(R)?e=R:R&&typeof R=="object"&&(Array.isArray(R.data)?e=R.data:Array.isArray(R.value)&&(e=R.value)),D&&y(e)}else j?.provider==="api"&&(console.warn("API provider not yet implemented for ObjectCalendar"),D&&y([]));D&&b(!1)}catch(k){console.error("[ObjectCalendar] Error fetching data:",k),D&&(N(k),b(!1))}})(),()=>{D=!1}},[j,n,q,t.filter,t.sort,M]),p.useEffect(()=>{!q&&n&&(async()=>{try{if(!n)return;const O=j?.provider==="object"?j.object:t.objectName;if(!O)return;const k=await n.getObjectSchema(O);V(k)}catch(O){console.error("Failed to fetch object schema:",O)}})()},[t.objectName,n,q,j]);const ne=p.useMemo(()=>{if(!W||!d.length)return[];const{startDateField:D,endDateField:O,titleField:k,colorField:R}=W;return d.map((e,f)=>{const w=e[D],E=O?e[O]:null,H=e[k]||"Untitled",X=R?e[R]:void 0;return{id:e.id||e._id||`event-${f}`,title:H,start:w?new Date(w):new Date,end:E?new Date(E):void 0,color:X,allDay:!E,data:e}}).filter(e=>!isNaN(e.start.getTime()))},[d,W]),G=p.useCallback(()=>{c?.(new Date)},[c]),U=oe.useNavigationOverlay({navigation:t.navigation,objectName:t.objectName,onRowClick:m});return a?r.jsx("div",{className:l,children:r.jsx("div",{className:"flex items-center justify-center h-96",children:r.jsx("div",{className:"text-muted-foreground",children:"Loading calendar..."})})}):o?r.jsx("div",{className:l,children:r.jsx("div",{className:"flex items-center justify-center h-96",children:r.jsxs("div",{className:"text-destructive",children:["Error: ",o.message]})})}):W?r.jsxs("div",{ref:Y,className:l,children:[T>0&&r.jsx("div",{className:"flex items-center justify-center text-xs text-muted-foreground",style:{height:T},children:i?"Refreshing…":"Pull to refresh"}),r.jsx("div",{className:"border rounded-lg bg-background h-[calc(100vh-120px)] sm:h-[calc(100vh-160px)] md:h-[calc(100vh-200px)] min-h-[400px] sm:min-h-[600px]",children:r.jsx(te,{events:ne,currentDate:x,view:t.defaultView||"month",onEventClick:D=>{U.handleClick(D.data),s?.(D.data)},onDateClick:c,onNavigate:D=>{F(D),g?.(D)},onViewChange:D=>{_(D),u?.(D)},onAddClick:G})}),U.isOverlay&&r.jsx(v.NavigationOverlay,{...U,title:"Event Details",children:D=>r.jsx("div",{className:"space-y-3",children:Object.entries(D).map(([O,k])=>r.jsxs("div",{className:"flex flex-col",children:[r.jsx("span",{className:"text-xs font-medium text-muted-foreground uppercase tracking-wide",children:O.replace(/_/g," ")}),r.jsx("span",{className:"text-sm",children:String(k??"—")})]},O))})})]}):r.jsx("div",{className:l,children:r.jsx("div",{className:"flex items-center justify-center h-96",children:r.jsx("div",{className:"text-muted-foreground",children:"Calendar configuration required. Please specify startDateField and titleField."})})})};K.ComponentRegistry.register("calendar-view",({schema:t,className:n,onAction:l,...s})=>{const m=p.useMemo(()=>!t.data||!Array.isArray(t.data)?[]:t.data.map((u,h)=>{const d=t.titleField||"title",y=t.startDateField||"start",a=t.endDateField||"end",b=t.colorField||"color",o=t.allDayField||"allDay";return{id:u._id||u.id||h,title:u[d]||"Untitled Event",start:new Date(u[y]),end:u[a]?new Date(u[a]):void 0,allDay:u[o],color:u[b],data:u}}),[t.data,t.titleField,t.startDateField,t.endDateField,t.colorField,t.allDayField]),c=u=>{t.onEventClick&&l?.({type:"event-click",payload:u})},g=()=>{l?.({type:"create",payload:{}})};return r.jsx(te,{className:n,events:m,onEventClick:c,onAddClick:g,...s})},{namespace:"plugin-calendar",label:"Calendar View",inputs:[{name:"data",type:"array",label:"Data",description:"Array of record objects to display as events"},{name:"titleField",type:"string",label:"Title Field",defaultValue:"title",description:"Field name to use for event title"},{name:"startDateField",type:"string",label:"Start Date Field",defaultValue:"start",description:"Field name for event start date"},{name:"endDateField",type:"string",label:"End Date Field",defaultValue:"end",description:"Field name for event end date (optional)"},{name:"allDayField",type:"string",label:"All Day Field",defaultValue:"allDay",description:"Field name for all-day flag"},{name:"colorField",type:"string",label:"Color Field",defaultValue:"color",description:"Field name for event color"},{name:"colorMapping",type:"object",label:"Color Mapping",description:'Map field values to colors (e.g., {meeting: "blue", deadline: "red"})'},{name:"view",type:"enum",enum:["month","week","day"],defaultValue:"month",label:"View Mode",description:"Calendar view mode (month, week, or day)"},{name:"currentDate",type:"string",label:"Current Date",description:"ISO date string for initial calendar date"},{name:"allowCreate",type:"boolean",label:"Allow Create",defaultValue:!1,description:"Allow creating events by clicking on dates"},{name:"className",type:"string",label:"CSS Class"}],defaultProps:{view:"month",titleField:"title",startDateField:"start",endDateField:"end",allDayField:"allDay",colorField:"color",allowCreate:!1,data:[{id:1,title:"Team Meeting",start:new Date(new Date().setHours(10,0,0,0)).toISOString(),end:new Date(new Date().setHours(11,0,0,0)).toISOString(),color:"#3b82f6",allDay:!1},{id:2,title:"Project Deadline",start:new Date(new Date().setDate(new Date().getDate()+3)).toISOString(),color:"#ef4444",allDay:!0},{id:3,title:"Conference",start:new Date(new Date().setDate(new Date().getDate()+7)).toISOString(),end:new Date(new Date().setDate(new Date().getDate()+9)).toISOString(),color:"#10b981",allDay:!0}],className:"h-[600px] border rounded-lg"}});const ae=({schema:t})=>{const{dataSource:n}=oe.useSchemaContext();return r.jsx(fe,{schema:t,dataSource:n})};K.ComponentRegistry.register("object-calendar",ae,{namespace:"plugin-calendar",label:"Object Calendar",category:"view",inputs:[{name:"objectName",type:"string",label:"Object Name",required:!0},{name:"calendar",type:"object",label:"Calendar Config",description:"startDateField, endDateField, titleField, colorField"}]}),K.ComponentRegistry.register("calendar",ae,{namespace:"view",label:"Calendar View",category:"view",inputs:[{name:"objectName",type:"string",label:"Object Name",required:!0},{name:"calendar",type:"object",label:"Calendar Config",description:"startDateField, endDateField, titleField, colorField"}]}),A.CalendarView=te,A.ObjectCalendar=fe,A.ObjectCalendarRenderer=ae,Object.defineProperty(A,Symbol.toStringTag,{value:"Module"})}));
|
|
6
|
+
<%s key={someKey} {...props} />`,k,R,W,R),$[R+k]=!0)}if(R=null,j!==void 0&&(n(j),R=""+j),d(x)&&(n(x.key),R=""+x.key),"key"in x){j={};for(var ce in x)ce!=="key"&&(j[ce]=x[ce])}else j=x;return R&&v(j,typeof t=="function"?t.displayName||t.name||"Unknown":t),p(t,R,j,i(),z,G)}function a(t){m(t)?t._store&&(t._store.validated=1):typeof t=="object"&&t!==null&&t.$$typeof===D&&(t._payload.status==="fulfilled"?m(t._payload.value)&&t._payload.value._store&&(t._payload.value._store.validated=1):t._store&&(t._store.validated=1))}function m(t){return typeof t=="object"&&t!==null&&t.$$typeof===h}var l=g,h=Symbol.for("react.transitional.element"),w=Symbol.for("react.portal"),A=Symbol.for("react.fragment"),F=Symbol.for("react.strict_mode"),M=Symbol.for("react.profiler"),Y=Symbol.for("react.consumer"),b=Symbol.for("react.context"),O=Symbol.for("react.forward_ref"),I=Symbol.for("react.suspense"),T=Symbol.for("react.suspense_list"),P=Symbol.for("react.memo"),D=Symbol.for("react.lazy"),f=Symbol.for("react.activity"),_=Symbol.for("react.client.reference"),u=l.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,S=Object.prototype.hasOwnProperty,L=Array.isArray,H=console.createTask?console.createTask:function(){return null};l={react_stack_bottom_frame:function(t){return t()}};var Q,re={},B=l.react_stack_bottom_frame.bind(l,o)(),N=H(c(o)),$={};K.Fragment=A,K.jsx=function(t,x,j){var k=1e4>u.recentlyCreatedOwnerStacks++;return E(t,x,j,!1,k?Error("react-stack-top-frame"):B,k?H(c(t)):N)},K.jsxs=function(t,x,j){var k=1e4>u.recentlyCreatedOwnerStacks++;return E(t,x,j,!0,k?Error("react-stack-top-frame"):B,k?H(c(t)):N)}})()),K}var ge;function Ce(){return ge||(ge=1,process.env.NODE_ENV==="production"?ee.exports=Ne():ee.exports=Oe()),ee.exports}var s=Ce();const Fe=(e,r,n,c)=>{const i=[n,{code:r,...c||{}}];if(e?.services?.logger?.forward)return e.services.logger.forward(i,"warn","react-i18next::",!0);q(i[0])&&(i[0]=`react-i18next:: ${i[0]}`),e?.services?.logger?.warn?e.services.logger.warn(...i):console?.warn&&console.warn(...i)},me={},pe=(e,r,n,c)=>{q(n)&&me[n]||(q(n)&&(me[n]=new Date),Fe(e,r,n,c))},he=(e,r)=>()=>{if(e.isInitialized)r();else{const n=()=>{setTimeout(()=>{e.off("initialized",n)},0),r()};e.on("initialized",n)}},ne=(e,r,n)=>{e.loadNamespaces(r,he(e,n))},ye=(e,r,n,c)=>{if(q(n)&&(n=[n]),e.options.preload&&e.options.preload.indexOf(r)>-1)return ne(e,n,c);n.forEach(i=>{e.options.ns.indexOf(i)<0&&e.options.ns.push(i)}),e.loadLanguages(r,he(e,c))},ke=(e,r,n={})=>!r.languages||!r.languages.length?(pe(r,"NO_LANGUAGES","i18n.languages were undefined or empty",{languages:r.languages}),!0):r.hasLoadedNamespace(e,{lng:n.lng,precheck:(c,i)=>{if(n.bindI18n&&n.bindI18n.indexOf("languageChanging")>-1&&c.services.backendConnector.backend&&c.isLanguageChangingTo&&!i(c.isLanguageChangingTo,e))return!1}}),q=e=>typeof e=="string",Le=e=>typeof e=="object"&&e!==null,Ae=/&(?:amp|#38|lt|#60|gt|#62|apos|#39|quot|#34|nbsp|#160|copy|#169|reg|#174|hellip|#8230|#x2F|#47);/g,Re={"&":"&","&":"&","<":"<","<":"<",">":">",">":">","'":"'","'":"'",""":'"',""":'"'," ":" "," ":" ","©":"©","©":"©","®":"®","®":"®","…":"…","…":"…","/":"/","/":"/"},Pe=e=>Re[e];let Ie={bindI18n:"languageChanged",bindI18nStore:"",transEmptyNodeValue:"",transSupportBasicHtmlNodes:!0,transWrapTextNodes:"",transKeepBasicHtmlNodesFor:["br","strong","i","p"],useSuspense:!0,unescape:e=>e.replace(Ae,Pe),transDefaultProps:void 0};const Me=()=>Ie;let $e;const Ve=()=>$e,Ye=g.createContext();class Ue{constructor(){this.usedNamespaces={}}addUsedNamespaces(r){r.forEach(n=>{this.usedNamespaces[n]||(this.usedNamespaces[n]=!0)})}getUsedNamespaces(){return Object.keys(this.usedNamespaces)}}var te={exports:{}},ae={};var xe;function He(){if(xe)return ae;xe=1;var e=g;function r(a,m){return a===m&&(a!==0||1/a===1/m)||a!==a&&m!==m}var n=typeof Object.is=="function"?Object.is:r,c=e.useState,i=e.useEffect,o=e.useLayoutEffect,d=e.useDebugValue;function v(a,m){var l=m(),h=c({inst:{value:l,getSnapshot:m}}),w=h[0].inst,A=h[1];return o(function(){w.value=l,w.getSnapshot=m,y(w)&&A({inst:w})},[a,l,m]),i(function(){return y(w)&&A({inst:w}),a(function(){y(w)&&A({inst:w})})},[a]),d(l),l}function y(a){var m=a.getSnapshot;a=a.value;try{var l=m();return!n(a,l)}catch{return!0}}function p(a,m){return m()}var E=typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"?p:v;return ae.useSyncExternalStore=e.useSyncExternalStore!==void 0?e.useSyncExternalStore:E,ae}var oe={};var be;function We(){return be||(be=1,process.env.NODE_ENV!=="production"&&(function(){function e(l,h){return l===h&&(l!==0||1/l===1/h)||l!==l&&h!==h}function r(l,h){E||i.startTransition===void 0||(E=!0,console.error("You are using an outdated, pre-release alpha of React 18 that does not support useSyncExternalStore. The use-sync-external-store shim will not work correctly. Upgrade to a newer pre-release."));var w=h();if(!a){var A=h();o(w,A)||(console.error("The result of getSnapshot should be cached to avoid an infinite loop"),a=!0)}A=d({inst:{value:w,getSnapshot:h}});var F=A[0].inst,M=A[1];return y(function(){F.value=w,F.getSnapshot=h,n(F)&&M({inst:F})},[l,w,h]),v(function(){return n(F)&&M({inst:F}),l(function(){n(F)&&M({inst:F})})},[l]),p(w),w}function n(l){var h=l.getSnapshot;l=l.value;try{var w=h();return!o(l,w)}catch{return!0}}function c(l,h){return h()}typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<"u"&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart=="function"&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());var i=g,o=typeof Object.is=="function"?Object.is:e,d=i.useState,v=i.useEffect,y=i.useLayoutEffect,p=i.useDebugValue,E=!1,a=!1,m=typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"?c:r;oe.useSyncExternalStore=i.useSyncExternalStore!==void 0?i.useSyncExternalStore:m,typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<"u"&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop=="function"&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error())})()),oe}var ve;function qe(){return ve||(ve=1,process.env.NODE_ENV==="production"?te.exports=He():te.exports=We()),te.exports}var ze=qe();const Ge={t:(e,r)=>q(r)?r:Le(r)&&q(r.defaultValue)?r.defaultValue:Array.isArray(e)?e[e.length-1]:e,ready:!1},Be=()=>()=>{},Je=(e,r={})=>{const{i18n:n}=r,{i18n:c,defaultNS:i}=g.useContext(Ye)||{},o=n||c||Ve();o&&!o.reportNamespaces&&(o.reportNamespaces=new Ue),o||pe(o,"NO_I18NEXT_INSTANCE","useTranslation: You will need to pass in an i18next instance by using initReactI18next");const d=g.useMemo(()=>({...Me(),...o?.options?.react,...r}),[o,r]),{useSuspense:v,keyPrefix:y}=d,p=i||o?.options?.defaultNS,E=q(p)?[p]:p||["translation"],a=g.useMemo(()=>E,E);o?.reportNamespaces?.addUsedNamespaces?.(a);const m=g.useRef(0),l=g.useCallback(D=>{if(!o)return Be;const{bindI18n:f,bindI18nStore:_}=d,u=()=>{m.current+=1,D()};return f&&o.on(f,u),_&&o.store.on(_,u),()=>{f&&f.split(" ").forEach(S=>o.off(S,u)),_&&_.split(" ").forEach(S=>o.store.off(S,u))}},[o,d]),h=g.useRef(),w=g.useCallback(()=>{if(!o)return Ge;const D=!!(o.isInitialized||o.initializedStoreOnce)&&a.every(H=>ke(H,o,d)),f=r.lng||o.language,_=m.current,u=h.current;if(u&&u.ready===D&&u.lng===f&&u.keyPrefix===y&&u.revision===_)return u;const L={t:o.getFixedT(f,d.nsMode==="fallback"?a:a[0],y),ready:D,lng:f,keyPrefix:y,revision:_};return h.current=L,L},[o,a,y,d,r.lng]),[A,F]=g.useState(0),{t:M,ready:Y}=ze.useSyncExternalStore(l,w,w);g.useEffect(()=>{if(o&&!Y&&!v){const D=()=>F(f=>f+1);r.lng?ye(o,r.lng,a,D):ne(o,a,D)}},[o,r.lng,a,Y,v,A]);const b=o||{},O=g.useRef(null),I=g.useRef(),T=D=>{const f=Object.getOwnPropertyDescriptors(D);f.__original&&delete f.__original;const _=Object.create(Object.getPrototypeOf(D),f);if(!Object.prototype.hasOwnProperty.call(_,"__original"))try{Object.defineProperty(_,"__original",{value:D,writable:!1,enumerable:!1,configurable:!1})}catch{}return _},P=g.useMemo(()=>{const D=b,f=D?.language;let _=D;D&&(O.current&&O.current.__original===D?I.current!==f?(_=T(D),O.current=_,I.current=f):_=O.current:(_=T(D),O.current=_,I.current=f));const u=[M,_,Y];return u.t=M,u.i18n=_,u.ready=Y,u},[M,b,Y,b.resolvedLanguage,b.language,b.languages]);if(o&&v&&!Y)throw new Promise(D=>{const f=()=>D();r.lng?ye(o,r.lng,a,f):ne(o,a,f)});return P},Xe=g.createContext(null);function Ke(e){const r=g.useContext(Xe),{t:n,i18n:c}=Je();return{t:n,language:r?.language||c.language||"en",changeLanguage:r?.changeLanguage||(async i=>{await c.changeLanguage(i)}),direction:r?.direction||"ltr",i18n:c}}const se="bg-blue-500 text-white",Qe=new Date,De={"calendar.today":"Today","calendar.month":"Month","calendar.week":"Week","calendar.day":"Day","calendar.newEvent":"New event","calendar.moreEvents":"+{{count}} more"};function we(){try{const e=Ke();return e.t("calendar.today")==="calendar.today"?{t:(n,c)=>{let i=De[n]||n;if(c)for(const[o,d]of Object.entries(c))i=i.replace(`{{${o}}}`,String(d));return i},language:"en"}:{t:e.t,language:e.language}}catch{return{t:(e,r)=>{let n=De[e]||e;if(r)for(const[c,i]of Object.entries(r))n=n.replace(`{{${c}}}`,String(i));return n},language:"en"}}}function le({events:e=[],view:r="month",currentDate:n=Qe,locale:c="default",onEventClick:i,onDateClick:o,onViewChange:d,onNavigate:v,onAddClick:y,onEventDrop:p,className:E}){const[a,m]=V.useState(r),[l,h]=V.useState(n),{t:w,language:A}=we(),F=c!=="default"?c:A;V.useEffect(()=>{h(n)},[n]),V.useEffect(()=>{m(r)},[r]);const M=V.useRef(d);M.current=d,V.useEffect(()=>{const u=window.matchMedia("(max-width: 639px)"),S=L=>{L.matches&&(m("day"),M.current?.("day"))};return S(u),u.addEventListener("change",S),()=>u.removeEventListener("change",S)},[]);const Y=()=>{const u=new Date(l);a==="month"?u.setMonth(u.getMonth()-1):a==="week"?u.setDate(u.getDate()-7):u.setDate(u.getDate()-1),h(u),v?.(u)},b=()=>{const u=new Date(l);a==="month"?u.setMonth(u.getMonth()+1):a==="week"?u.setDate(u.getDate()+7):u.setDate(u.getDate()+1),h(u),v?.(u)},O=()=>{const u=new Date;h(u),v?.(u)},I=u=>{m(u),d?.(u)},T=()=>{if(a==="month")return l.toLocaleDateString(F,{month:"long",year:"numeric"});if(a==="week"){const u=Se(l),S=new Date(u);return S.setDate(S.getDate()+6),`${u.toLocaleDateString(F,{month:"short",day:"numeric"})} - ${S.toLocaleDateString(F,{month:"short",day:"numeric",year:"numeric"})}`}else return l.toLocaleDateString(F,{weekday:"long",month:"long",day:"numeric",year:"numeric"})},P=V.useRef(0),D=u=>{P.current=u.touches[0].clientX},f=u=>{const S=P.current-u.changedTouches[0].clientX;if(Math.abs(S)>50){const L=new Date(l);a==="day"?L.setDate(L.getDate()+(S>0?1:-1)):a==="week"?L.setDate(L.getDate()+(S>0?7:-7)):L.setMonth(L.getMonth()+(S>0?1:-1)),h(L),v?.(L)}},_=u=>{u&&(h(u),v?.(u))};return s.jsxs("div",{role:"region","aria-label":"Calendar",className:C.cn("flex flex-col h-full bg-background min-w-0 overflow-hidden",E),children:[s.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-2 p-2 sm:p-4 border-b min-w-0",children:[s.jsxs("div",{className:"flex items-center gap-4",children:[s.jsxs("div",{className:"flex items-center bg-muted/50 rounded-lg p-1 gap-1",children:[s.jsx(C.Button,{variant:"ghost",size:"sm",onClick:O,className:"h-8","aria-label":"Go to today",children:w("calendar.today")}),s.jsx("div",{className:"h-4 w-px bg-border mx-1"}),s.jsx(C.Button,{variant:"ghost",size:"icon","aria-label":"Previous period",onClick:Y,className:"h-8 w-8",children:s.jsx(Z.ChevronLeftIcon,{className:"h-4 w-4"})}),s.jsx(C.Button,{variant:"ghost",size:"icon","aria-label":"Next period",onClick:b,className:"h-8 w-8",children:s.jsx(Z.ChevronRightIcon,{className:"h-4 w-4"})})]}),s.jsxs(C.Popover,{children:[s.jsx(C.PopoverTrigger,{asChild:!0,children:s.jsxs(C.Button,{variant:"ghost","aria-label":`Current date: ${T()}`,className:C.cn("text-base sm:text-xl font-semibold h-auto px-2 sm:px-3 py-1 hover:bg-muted/50 transition-colors","flex items-center gap-2"),children:[s.jsx(Z.CalendarIcon,{className:"h-5 w-5 text-muted-foreground"}),s.jsx("span",{children:T()})]})}),s.jsx(C.PopoverContent,{className:"w-auto p-0",align:"start",children:s.jsx(C.Calendar,{mode:"single",selected:l,onSelect:_,initialFocus:!0,fromYear:2e3,toYear:2050})})]})]}),s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsxs(C.Select,{value:a,onValueChange:I,children:[s.jsx(C.SelectTrigger,{className:"w-32 bg-background",children:s.jsx(C.SelectValue,{})}),s.jsxs(C.SelectContent,{children:[s.jsx(C.SelectItem,{value:"day",children:w("calendar.day")}),s.jsx(C.SelectItem,{value:"week",children:w("calendar.week")}),s.jsx(C.SelectItem,{value:"month",children:w("calendar.month")})]})]}),y&&s.jsxs(C.Button,{onClick:y,size:"sm",className:"gap-1",children:[s.jsx(Z.PlusIcon,{className:"h-4 w-4"}),w("calendar.newEvent")]})]})]}),s.jsxs("div",{className:"flex-1 overflow-auto",onTouchStart:D,onTouchEnd:f,children:[a==="month"&&s.jsx(et,{date:l,events:e,locale:F,onEventClick:i,onDateClick:o,onEventDrop:p}),a==="week"&&s.jsx(tt,{date:l,events:e,locale:F,onEventClick:i,onDateClick:o}),a==="day"&&s.jsx(rt,{date:l,events:e,onEventClick:i,onDateClick:o})]})]})}function Se(e){const r=new Date(e),n=r.getDay(),c=r.getDate()-n;return r.setDate(c),r}function Ze(e){const r=e.getFullYear(),n=e.getMonth(),c=new Date(r,n,1),i=new Date(r,n+1,0),o=c.getDay(),d=[];for(let y=o-1;y>=0;y--){const p=new Date(c.getTime());p.setDate(p.getDate()-(y+1)),d.push(p)}for(let y=1;y<=i.getDate();y++)d.push(new Date(r,n,y));const v=42-d.length;for(let y=1;y<=v;y++){const p=new Date(i.getTime());p.setDate(p.getDate()+y),d.push(p)}return d}function je(e,r){return e.getFullYear()===r.getFullYear()&&e.getMonth()===r.getMonth()&&e.getDate()===r.getDate()}function Ee(e,r){return r.filter(n=>{const c=new Date(n.start),i=n.end?new Date(n.end):new Date(c),o=new Date(e);o.setHours(0,0,0,0);const d=new Date(e);d.setHours(23,59,59,999);const v=new Date(c);v.setHours(0,0,0,0);const y=new Date(i);return y.setHours(23,59,59,999),o<=y&&d>=v})}function et({date:e,events:r,locale:n="default",onEventClick:c,onDateClick:i,onEventDrop:o}){const d=V.useMemo(()=>Ze(e),[e.getFullYear(),e.getMonth()]),v=V.useMemo(()=>new Date,[]),{t:y}=we(),p=V.useMemo(()=>{const b=new Date(2024,0,7);return Array.from({length:7},(O,I)=>{const T=new Date(b);return T.setDate(T.getDate()+I),T.toLocaleDateString(n,{weekday:"short"})})},[n]),[E,a]=V.useState(null),[m,l]=V.useState(null),h=V.useMemo(()=>{const b=new Map;for(const O of r){const I=new Date(O.start),T=O.end?new Date(O.end):new Date(I);I.setHours(0,0,0,0),T.setHours(0,0,0,0);const P=new Date(I);for(;P<=T;){const D=`${P.getFullYear()}-${P.getMonth()}-${P.getDate()}`,f=b.get(D);f?f.push(O):b.set(D,[O]),P.setDate(P.getDate()+1)}}return b},[r]),w=(b,O)=>{a(O.id),b.dataTransfer.effectAllowed="move",b.dataTransfer.setData("text/plain",String(O.id))},A=()=>{a(null),l(null)},F=(b,O)=>{b.preventDefault(),b.dataTransfer.dropEffect="move",l(O)},M=b=>{b.currentTarget.contains(b.relatedTarget)||l(null)},Y=(b,O)=>{if(b.preventDefault(),l(null),a(null),!o)return;const I=b.dataTransfer.getData("text/plain"),T=r.find(L=>String(L.id)===I);if(!T)return;const P=new Date(T.start),D=new Date(P);D.setHours(0,0,0,0);const f=new Date(O);f.setHours(0,0,0,0);const _=f.getTime()-D.getTime();if(_===0)return;const u=new Date(P.getTime()+_);let S;T.end&&(S=new Date(new Date(T.end).getTime()+_)),o(T,u,S)};return s.jsxs("div",{className:"flex flex-col h-full",children:[s.jsx("div",{role:"row",className:"grid grid-cols-7 border-b",children:p.map(b=>s.jsx("div",{role:"columnheader",className:"p-2 text-center text-sm font-medium text-muted-foreground border-r last:border-r-0",children:b},b))}),s.jsx("div",{role:"grid","aria-label":"Calendar grid",className:"grid grid-cols-7 flex-1 auto-rows-fr",children:d.map((b,O)=>{const I=`${b.getFullYear()}-${b.getMonth()}-${b.getDate()}`,T=h.get(I)||[],P=b.getMonth()===e.getMonth(),D=je(b,v);return s.jsxs("div",{role:"gridcell","aria-label":`${b.toLocaleDateString("default",{weekday:"long",month:"long",day:"numeric",year:"numeric"})}${T.length>0?`, ${T.length} event${T.length>1?"s":""}`:""}`,className:C.cn("border-b border-r last:border-r-0 p-2 min-h-[100px] cursor-pointer hover:bg-accent/50",!P&&"bg-muted/50 text-muted-foreground opacity-50",m===O&&"ring-2 ring-primary"),onClick:()=>i?.(b),onDragOver:f=>F(f,O),onDragLeave:M,onDrop:f=>Y(f,b),children:[s.jsx("div",{className:C.cn("text-sm font-medium mb-2",D&&"inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground h-6 w-6"),...D?{"aria-current":"date"}:{},children:b.getDate()}),s.jsxs("div",{className:"space-y-1",children:[T.slice(0,3).map(f=>s.jsx("div",{role:"button",title:f.title,"aria-label":f.title,draggable:!!o,onDragStart:_=>w(_,f),onDragEnd:A,className:C.cn("text-xs px-2 py-1 rounded truncate cursor-pointer hover:opacity-80",f.color?.startsWith("#")?"text-white":f.color||se,E===f.id&&"opacity-50"),style:f.color&&f.color.startsWith("#")?{backgroundColor:f.color}:void 0,onClick:_=>{_.stopPropagation(),c?.(f)},children:f.title},f.id)),T.length>3&&s.jsx("div",{className:"text-xs text-muted-foreground px-2",children:y("calendar.moreEvents",{count:T.length-3})})]})]},O)})})]})}function tt({date:e,events:r,locale:n="default",onEventClick:c,onDateClick:i}){const o=V.useRef(null),d=a=>{i&&(o.current=setTimeout(()=>{i(a)},500))},v=()=>{o.current&&(clearTimeout(o.current),o.current=null)},y=Se(e),p=Array.from({length:7},(a,m)=>{const l=new Date(y);return l.setDate(l.getDate()+m),l}),E=new Date;return s.jsxs("div",{className:"flex flex-col h-full",children:[s.jsx("div",{className:"grid grid-cols-7 border-b",children:p.map(a=>{const m=je(a,E);return s.jsxs("div",{className:"p-3 text-center border-r last:border-r-0",children:[s.jsx("div",{className:"text-sm font-medium text-muted-foreground",children:a.toLocaleDateString(n,{weekday:"short"})}),s.jsx("div",{className:C.cn("text-lg font-semibold mt-1",m&&"inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground h-8 w-8"),children:a.getDate()})]},a.toISOString())})}),s.jsx("div",{role:"grid",className:"grid grid-cols-7 flex-1",children:p.map(a=>{const m=Ee(a,r);return s.jsx("div",{role:"gridcell","aria-label":`${a.toLocaleDateString("default",{weekday:"long",month:"long",day:"numeric",year:"numeric"})}${m.length>0?`, ${m.length} event${m.length>1?"s":""}`:""}`,className:"border-r last:border-r-0 p-2 min-h-[400px] cursor-pointer hover:bg-accent/50",onClick:()=>i?.(a),onTouchStart:()=>d(a),onTouchEnd:v,children:s.jsx("div",{className:"space-y-2",children:m.map(l=>s.jsxs("div",{role:"button",title:l.title,"aria-label":l.title,className:C.cn("text-xs sm:text-sm px-2 sm:px-3 py-1.5 sm:py-2 rounded cursor-pointer hover:opacity-80",l.color?.startsWith("#")?"text-white":l.color||se),style:l.color&&l.color.startsWith("#")?{backgroundColor:l.color}:void 0,onClick:h=>{h.stopPropagation(),c?.(l)},children:[s.jsx("div",{className:"font-medium truncate",children:l.title}),!l.allDay&&s.jsx("div",{className:"text-xs opacity-90 mt-1",children:l.start.toLocaleTimeString("default",{hour:"numeric",minute:"2-digit"})})]},l.id))})},a.toISOString())})})]})}function rt({date:e,events:r,onEventClick:n,onDateClick:c}){const i=Ee(e,r),o=Array.from({length:24},(p,E)=>E),d=V.useRef(null),v=p=>{c&&(d.current=setTimeout(()=>{const E=new Date(e);E.setHours(p,0,0,0),c(E)},500))},y=()=>{d.current&&(clearTimeout(d.current),d.current=null)};return s.jsx("div",{className:"flex flex-col h-full",children:s.jsx("div",{role:"list",className:"flex-1 overflow-auto",children:o.map(p=>{const E=i.filter(a=>a.allDay?p===0:a.start.getHours()===p);return s.jsxs("div",{role:"listitem",className:"flex border-b min-h-[60px]",children:[s.jsx("div",{className:"w-20 p-2 text-sm text-muted-foreground border-r",children:p===0?"12 AM":p<12?`${p} AM`:p===12?"12 PM":`${p-12} PM`}),s.jsx("div",{className:"flex-1 p-2 space-y-2",onTouchStart:()=>v(p),onTouchEnd:y,children:E.map(a=>s.jsxs("div",{title:a.title,"aria-label":a.title,className:C.cn("px-2 sm:px-3 py-1.5 sm:py-2 rounded cursor-pointer hover:opacity-80",a.color?.startsWith("#")?"text-white":a.color||se),style:a.color&&a.color.startsWith("#")?{backgroundColor:a.color}:void 0,onClick:()=>n?.(a),children:[s.jsx("div",{className:"font-medium truncate",children:a.title}),!a.allDay&&s.jsxs("div",{className:"text-xs opacity-90 mt-1",children:[a.start.toLocaleTimeString("default",{hour:"numeric",minute:"2-digit"}),a.end&&` - ${a.end.toLocaleTimeString("default",{hour:"numeric",minute:"2-digit"})}`]})]},a.id))})]},p)})})})}function nt(e){const{onRefresh:r,threshold:n=80,enabled:c=!0}=e,i=g.useRef(null),[o,d]=g.useState(!1),[v,y]=g.useState(0),p=g.useRef(0),E=g.useCallback(l=>{if(!c||o)return;const h=i.current;h&&h.scrollTop===0&&(p.current=l.touches[0].clientY)},[c,o]),a=g.useCallback(l=>{if(!c||o||!p.current)return;const w=l.touches[0].clientY-p.current;w>0&&y(Math.min(w,n*1.5))},[c,o,n]),m=g.useCallback(async()=>{if(!c||o)return;const l=v;if(y(0),p.current=0,l>=n){d(!0);try{await r()}finally{d(!1)}}},[c,o,v,n,r]);return g.useEffect(()=>{const l=i.current;if(!(!l||!c))return l.addEventListener("touchstart",E,{passive:!0}),l.addEventListener("touchmove",a,{passive:!0}),l.addEventListener("touchend",m,{passive:!0}),()=>{l.removeEventListener("touchstart",E),l.removeEventListener("touchmove",a),l.removeEventListener("touchend",m)}},[E,a,m,c]),{ref:i,isRefreshing:o,pullDistance:v}}const at=g.createContext(null);at.displayName="MobileContext";function ot(e){return"data"in e&&e.data?e.data:"staticData"in e&&e.staticData?{provider:"value",items:e.staticData}:e.objectName?{provider:"object",object:e.objectName}:null}function st(e){if(e){if(typeof e=="string"){const r=e.split(" "),n=r[0],c=r[1]?.toLowerCase()==="desc"?"desc":"asc";return{[n]:c}}if(Array.isArray(e))return e.reduce((r,n)=>(n.field&&n.order&&(r[n.field]=n.order),r),{})}}function lt(e){return"filter"in e&&e.filter&&typeof e.filter=="object"&&"calendar"in e.filter?e.filter.calendar:e.calendar?e.calendar:e.startDateField||e.dateField?{startDateField:e.startDateField||e.dateField,endDateField:e.endDateField||e.endField,titleField:e.titleField||"name",colorField:e.colorField,allDayField:e.allDayField}:null}const _e=({schema:e,dataSource:r,className:n,onEventClick:c,onRowClick:i,onDateClick:o,onNavigate:d,onViewChange:v,onEventDrop:y,locale:p,...E})=>{const[a,m]=g.useState([]),[l,h]=g.useState(!0),[w,A]=g.useState(null),[F,M]=g.useState(null),[Y,b]=g.useState(new Date),[O,I]=g.useState("month"),[T,P]=g.useState(0),D=g.useCallback(async()=>{P(N=>N+1)},[]),{ref:f,isRefreshing:_,pullDistance:u}=nt({onRefresh:D,enabled:!!r&&!!e.objectName}),S=g.useMemo(()=>ot(e),[e.data,e.staticData,e.objectName]),L=g.useMemo(()=>lt(e),[e.filter,e.calendar,e.dateField,e.endField,e.titleField,e.colorField]),H=S?.provider==="value",Q=g.useRef(null);Q.current=F,g.useEffect(()=>{let N=!0;return(async()=>{try{if(!N)return;if(h(!0),H&&S?.provider==="value"){N&&(m(S.items),h(!1));return}if(e.data||E.data){const t=e.data||E.data;if(Array.isArray(t)){m(t),h(!1);return}}if(!r||typeof r.find!="function")throw new Error("DataSource required for object/api providers");if(S?.provider==="object"){const t=S.object,x=J.buildExpandFields(Q.current?.fields),j=await r.find(t,{$filter:e.filter,$orderby:st(e.sort),...x.length>0?{$expand:x}:{}});let k=J.extractRecords(j);N&&m(k)}else S?.provider==="api"&&(console.warn("API provider not yet implemented for ObjectCalendar"),N&&m([]));N&&h(!1)}catch(t){console.error("[ObjectCalendar] Error fetching data:",t),N&&(A(t),h(!1))}})(),()=>{N=!1}},[S,r,H,e.filter,e.sort,T]),g.useEffect(()=>{!H&&r&&(async()=>{try{if(!r)return;const $=S?.provider==="object"?S.object:e.objectName;if(!$)return;const t=await r.getObjectSchema($);M(t)}catch($){console.error("Failed to fetch object schema:",$)}})()},[e.objectName,r,H,S]);const re=g.useMemo(()=>{if(!L||!a.length)return[];const{startDateField:N,endDateField:$,titleField:t,colorField:x}=L;return a.map((j,k)=>{const z=j[N],G=$?j[$]:null,R=j[t]||"Untitled",W=x?j[x]:void 0;return{id:j.id||j._id||`event-${k}`,title:R,start:z?new Date(z):new Date,end:G?new Date(G):void 0,color:W,allDay:!G,data:j}}).filter(j=>!isNaN(j.start.getTime()))},[a,L]);g.useCallback(()=>{o?.(new Date)},[o]);const B=ue.useNavigationOverlay({navigation:e.navigation,objectName:e.objectName,onRowClick:i});return l?s.jsx("div",{className:n,children:s.jsx("div",{className:"flex items-center justify-center h-96",children:s.jsx("div",{className:"text-muted-foreground",children:"Loading calendar..."})})}):w?s.jsx("div",{className:n,children:s.jsx("div",{className:"flex items-center justify-center h-96",children:s.jsxs("div",{className:"text-destructive",children:["Error: ",w.message]})})}):L?s.jsxs("div",{ref:f,className:n,children:[u>0&&s.jsx("div",{className:"flex items-center justify-center text-xs text-muted-foreground",style:{height:u},children:_?"Refreshing…":"Pull to refresh"}),s.jsx("div",{className:"border rounded-lg bg-background h-[calc(100vh-120px)] sm:h-[calc(100vh-160px)] md:h-[calc(100vh-200px)] min-h-[400px] sm:min-h-[600px]",children:s.jsx(le,{events:re,currentDate:Y,view:e.defaultView||"month",locale:p,onEventClick:N=>{B.handleClick(N.data),c?.(N.data)},onDateClick:o,onNavigate:N=>{b(N),d?.(N)},onViewChange:N=>{I(N),v?.(N)},onAddClick:void 0,onEventDrop:y?(N,$,t)=>{y(N.data,$,t)}:void 0})}),B.isOverlay&&s.jsx(C.NavigationOverlay,{...B,title:"Event Details",children:N=>s.jsx("div",{className:"space-y-3",children:Object.entries(N).map(([$,t])=>s.jsxs("div",{className:"flex flex-col",children:[s.jsx("span",{className:"text-xs font-medium text-muted-foreground uppercase tracking-wide",children:$.replace(/_/g," ")}),s.jsx("span",{className:"text-sm",children:String(t??"—")})]},$))})})]}):s.jsx("div",{className:n,children:s.jsx("div",{className:"flex items-center justify-center h-96",children:s.jsx("div",{className:"text-muted-foreground",children:"Calendar configuration required. Please specify startDateField and titleField."})})})};J.ComponentRegistry.register("calendar-view",({schema:e,className:r,onAction:n,...c})=>{const i=g.useMemo(()=>!e.data||!Array.isArray(e.data)?[]:e.data.map((d,v)=>{const y=e.titleField||"title",p=e.startDateField||"start",E=e.endDateField||"end",a=e.colorField||"color",m=e.allDayField||"allDay";return{id:d._id||d.id||v,title:d[y]||"Untitled Event",start:new Date(d[p]),end:d[E]?new Date(d[E]):void 0,allDay:d[m],color:d[a],data:d}}),[e.data,e.titleField,e.startDateField,e.endDateField,e.colorField,e.allDayField]),o=d=>{n?.({type:"event-click",payload:d})};return s.jsx(le,{className:r,events:i,onEventClick:o,...c})},{namespace:"plugin-calendar",label:"Calendar View",inputs:[{name:"data",type:"array",label:"Data",description:"Array of record objects to display as events"},{name:"titleField",type:"string",label:"Title Field",defaultValue:"title",description:"Field name to use for event title"},{name:"startDateField",type:"string",label:"Start Date Field",defaultValue:"start",description:"Field name for event start date"},{name:"endDateField",type:"string",label:"End Date Field",defaultValue:"end",description:"Field name for event end date (optional)"},{name:"allDayField",type:"string",label:"All Day Field",defaultValue:"allDay",description:"Field name for all-day flag"},{name:"colorField",type:"string",label:"Color Field",defaultValue:"color",description:"Field name for event color"},{name:"colorMapping",type:"object",label:"Color Mapping",description:'Map field values to colors (e.g., {meeting: "blue", deadline: "red"})'},{name:"view",type:"enum",enum:["month","week","day"],defaultValue:"month",label:"View Mode",description:"Calendar view mode (month, week, or day)"},{name:"currentDate",type:"string",label:"Current Date",description:"ISO date string for initial calendar date"},{name:"allowCreate",type:"boolean",label:"Allow Create",defaultValue:!1,description:"Allow creating events by clicking on dates"},{name:"className",type:"string",label:"CSS Class"}],defaultProps:{view:"month",titleField:"title",startDateField:"start",endDateField:"end",allDayField:"allDay",colorField:"color",allowCreate:!1,data:[{id:1,title:"Team Meeting",start:new Date(new Date().setHours(10,0,0,0)).toISOString(),end:new Date(new Date().setHours(11,0,0,0)).toISOString(),color:"#3b82f6",allDay:!1},{id:2,title:"Project Deadline",start:new Date(new Date().setDate(new Date().getDate()+3)).toISOString(),color:"#ef4444",allDay:!0},{id:3,title:"Conference",start:new Date(new Date().setDate(new Date().getDate()+7)).toISOString(),end:new Date(new Date().setDate(new Date().getDate()+9)).toISOString(),color:"#10b981",allDay:!0}],className:"h-[600px] border rounded-lg"}});const ie=({schema:e,data:r,loading:n,...c})=>{const{dataSource:i}=ue.useSchemaContext()||{};return s.jsx(_e,{schema:e,dataSource:i,...c})};J.ComponentRegistry.register("object-calendar",ie,{namespace:"plugin-calendar",label:"Object Calendar",category:"view",inputs:[{name:"objectName",type:"string",label:"Object Name",required:!0},{name:"calendar",type:"object",label:"Calendar Config",description:"startDateField, endDateField, titleField, colorField"}]}),J.ComponentRegistry.register("calendar",ie,{namespace:"view",label:"Calendar View",category:"view",inputs:[{name:"objectName",type:"string",label:"Object Name",required:!0},{name:"calendar",type:"object",label:"Calendar Config",description:"startDateField, endDateField, titleField, colorField"}]}),U.CalendarView=le,U.ObjectCalendar=_e,U.ObjectCalendarRenderer=ie,Object.defineProperty(U,Symbol.toStringTag,{value:"Module"})}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CalendarView.d.ts","sourceRoot":"","sources":["../../src/CalendarView.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"CalendarView.d.ts","sourceRoot":"","sources":["../../src/CalendarView.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA2EH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,IAAI,CAAA;IACX,GAAG,CAAC,EAAE,IAAI,CAAA;IACV,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,GAAG,CAAA;CACX;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,aAAa,EAAE,CAAA;IACxB,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,KAAK,CAAA;IAC/B,WAAW,CAAC,EAAE,IAAI,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;IAC7C,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAA;IAClC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,KAAK,KAAK,IAAI,CAAA;IACvD,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAA;IACjC,UAAU,CAAC,EAAE,MAAM,IAAI,CAAA;IACvB,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,IAAI,KAAK,IAAI,CAAA;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,iBAAS,YAAY,CAAC,EACpB,MAAW,EACX,IAAc,EACd,WAAiC,EACjC,MAAkB,EAClB,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,UAAU,EACV,UAAU,EACV,WAAW,EACX,SAAS,GACV,EAAE,iBAAiB,2CAuOnB;AAwdD,OAAO,EAAE,YAAY,EAAE,CAAA"}
|
|
@@ -23,6 +23,8 @@ export interface ObjectCalendarProps {
|
|
|
23
23
|
onDelete?: (record: any) => void;
|
|
24
24
|
onNavigate?: (date: Date) => void;
|
|
25
25
|
onViewChange?: (view: 'month' | 'week' | 'day') => void;
|
|
26
|
+
onEventDrop?: (record: any, newStart: Date, newEnd?: Date) => void;
|
|
27
|
+
locale?: string;
|
|
26
28
|
}
|
|
27
29
|
export declare const ObjectCalendar: React.FC<ObjectCalendarProps>;
|
|
28
30
|
//# sourceMappingURL=ObjectCalendar.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ObjectCalendar.d.ts","sourceRoot":"","sources":["../../src/ObjectCalendar.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;;;GAcG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"ObjectCalendar.d.ts","sourceRoot":"","sources":["../../src/ObjectCalendar.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAA4D,MAAM,OAAO,CAAC;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAA4B,MAAM,kBAAkB,CAAC;AAO/F,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,UAAU,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,wBAAwB;IACxB,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;CACxC;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,gBAAgB,GAAG,cAAc,CAAC;IAC1C,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACrC,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACnC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IAC/B,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACjC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAClC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,KAAK,KAAK,IAAI,CAAC;IACxD,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,IAAI,KAAK,IAAI,CAAC;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAkFD,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAwQxD,CAAC"}
|
package/dist/src/index.d.ts
CHANGED
package/dist/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAG5D,OAAO,EAAE,cAAc,EAAE,CAAC;AAC1B,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAGpC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGvE,OAAO,0BAA0B,CAAC;AAGlC,eAAO,MAAM,sBAAsB,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,MAAM,EAAE,GAAG,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAG5D,OAAO,EAAE,cAAc,EAAE,CAAC;AAC1B,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAGpC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGvE,OAAO,0BAA0B,CAAC;AAGlC,eAAO,MAAM,sBAAsB,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,MAAM,EAAE,GAAG,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,CAGhF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@object-ui/plugin-calendar",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Calendar view plugins for Object UI - includes both ObjectQL-integrated and standalone calendar components",
|
|
@@ -24,26 +24,27 @@
|
|
|
24
24
|
}
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"lucide-react": "^0.
|
|
28
|
-
"@object-ui/components": "3.0
|
|
29
|
-
"@object-ui/core": "3.0
|
|
30
|
-
"@object-ui/fields": "3.0
|
|
31
|
-
"@object-ui/
|
|
32
|
-
"@object-ui/
|
|
33
|
-
"@object-ui/
|
|
27
|
+
"lucide-react": "^0.576.0",
|
|
28
|
+
"@object-ui/components": "3.1.0",
|
|
29
|
+
"@object-ui/core": "3.1.0",
|
|
30
|
+
"@object-ui/fields": "3.1.0",
|
|
31
|
+
"@object-ui/i18n": "3.1.0",
|
|
32
|
+
"@object-ui/mobile": "3.1.0",
|
|
33
|
+
"@object-ui/react": "3.1.0",
|
|
34
|
+
"@object-ui/types": "3.1.0"
|
|
34
35
|
},
|
|
35
36
|
"peerDependencies": {
|
|
36
37
|
"react": "^18.0.0 || ^19.0.0",
|
|
37
38
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
38
39
|
},
|
|
39
40
|
"devDependencies": {
|
|
40
|
-
"@types/react": "19.2.
|
|
41
|
+
"@types/react": "19.2.14",
|
|
41
42
|
"@types/react-dom": "19.2.3",
|
|
42
43
|
"@vitejs/plugin-react": "^5.1.4",
|
|
43
44
|
"typescript": "^5.9.3",
|
|
44
45
|
"vite": "^7.3.1",
|
|
45
46
|
"vite-plugin-dts": "^4.5.4",
|
|
46
|
-
"@object-ui/data-objectstack": "3.0
|
|
47
|
+
"@object-ui/data-objectstack": "3.1.0"
|
|
47
48
|
},
|
|
48
49
|
"scripts": {
|
|
49
50
|
"build": "vite build",
|
|
@@ -95,7 +95,7 @@ describe('CalendarView', () => {
|
|
|
95
95
|
|
|
96
96
|
const triggerButton = dateLabel.closest('button');
|
|
97
97
|
expect(triggerButton).toBeInTheDocument();
|
|
98
|
-
expect(triggerButton).toHaveClass('text-xl font-semibold');
|
|
98
|
+
expect(triggerButton).toHaveClass('text-base sm:text-xl font-semibold');
|
|
99
99
|
});
|
|
100
100
|
|
|
101
101
|
it('opens date picker on click', () => {
|
package/src/CalendarView.tsx
CHANGED
|
@@ -23,8 +23,61 @@ import {
|
|
|
23
23
|
PopoverContent,
|
|
24
24
|
PopoverTrigger
|
|
25
25
|
} from "@object-ui/components"
|
|
26
|
+
import { useObjectTranslation } from "@object-ui/i18n"
|
|
26
27
|
|
|
27
28
|
const DEFAULT_EVENT_COLOR = "bg-blue-500 text-white"
|
|
29
|
+
const STABLE_DEFAULT_DATE = new Date()
|
|
30
|
+
|
|
31
|
+
// Default English translations for fallback when I18nProvider is not available
|
|
32
|
+
const DEFAULT_TRANSLATIONS: Record<string, string> = {
|
|
33
|
+
'calendar.today': 'Today',
|
|
34
|
+
'calendar.month': 'Month',
|
|
35
|
+
'calendar.week': 'Week',
|
|
36
|
+
'calendar.day': 'Day',
|
|
37
|
+
'calendar.newEvent': 'New event',
|
|
38
|
+
'calendar.moreEvents': '+{{count}} more',
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Safe wrapper for useObjectTranslation that falls back to English defaults
|
|
43
|
+
* when I18nProvider is not available (e.g., standalone usage outside console).
|
|
44
|
+
*/
|
|
45
|
+
function useCalendarTranslation() {
|
|
46
|
+
try {
|
|
47
|
+
const result = useObjectTranslation()
|
|
48
|
+
// Check if i18n is properly initialized by testing a known key
|
|
49
|
+
const testValue = result.t('calendar.today')
|
|
50
|
+
if (testValue === 'calendar.today') {
|
|
51
|
+
// i18n returned the key itself — not initialized
|
|
52
|
+
return {
|
|
53
|
+
t: (key: string, options?: Record<string, unknown>) => {
|
|
54
|
+
let value = DEFAULT_TRANSLATIONS[key] || key
|
|
55
|
+
if (options) {
|
|
56
|
+
for (const [k, v] of Object.entries(options)) {
|
|
57
|
+
value = value.replace(`{{${k}}}`, String(v))
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return value
|
|
61
|
+
},
|
|
62
|
+
language: 'en',
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return { t: result.t, language: result.language }
|
|
66
|
+
} catch {
|
|
67
|
+
return {
|
|
68
|
+
t: (key: string, options?: Record<string, unknown>) => {
|
|
69
|
+
let value = DEFAULT_TRANSLATIONS[key] || key
|
|
70
|
+
if (options) {
|
|
71
|
+
for (const [k, v] of Object.entries(options)) {
|
|
72
|
+
value = value.replace(`{{${k}}}`, String(v))
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return value
|
|
76
|
+
},
|
|
77
|
+
language: 'en',
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
28
81
|
|
|
29
82
|
export interface CalendarEvent {
|
|
30
83
|
id: string | number
|
|
@@ -53,7 +106,7 @@ export interface CalendarViewProps {
|
|
|
53
106
|
function CalendarView({
|
|
54
107
|
events = [],
|
|
55
108
|
view = "month",
|
|
56
|
-
currentDate =
|
|
109
|
+
currentDate = STABLE_DEFAULT_DATE,
|
|
57
110
|
locale = "default",
|
|
58
111
|
onEventClick,
|
|
59
112
|
onDateClick,
|
|
@@ -65,6 +118,8 @@ function CalendarView({
|
|
|
65
118
|
}: CalendarViewProps) {
|
|
66
119
|
const [selectedView, setSelectedView] = React.useState(view)
|
|
67
120
|
const [selectedDate, setSelectedDate] = React.useState(currentDate)
|
|
121
|
+
const { t, language } = useCalendarTranslation()
|
|
122
|
+
const effectiveLocale = locale !== "default" ? locale : language
|
|
68
123
|
|
|
69
124
|
// Sync state if props change
|
|
70
125
|
React.useEffect(() => {
|
|
@@ -131,7 +186,7 @@ function CalendarView({
|
|
|
131
186
|
|
|
132
187
|
const getDateLabel = () => {
|
|
133
188
|
if (selectedView === "month") {
|
|
134
|
-
return selectedDate.toLocaleDateString(
|
|
189
|
+
return selectedDate.toLocaleDateString(effectiveLocale, {
|
|
135
190
|
month: "long",
|
|
136
191
|
year: "numeric",
|
|
137
192
|
})
|
|
@@ -139,16 +194,16 @@ function CalendarView({
|
|
|
139
194
|
const weekStart = getWeekStart(selectedDate)
|
|
140
195
|
const weekEnd = new Date(weekStart)
|
|
141
196
|
weekEnd.setDate(weekEnd.getDate() + 6)
|
|
142
|
-
return `${weekStart.toLocaleDateString(
|
|
197
|
+
return `${weekStart.toLocaleDateString(effectiveLocale, {
|
|
143
198
|
month: "short",
|
|
144
199
|
day: "numeric",
|
|
145
|
-
})} - ${weekEnd.toLocaleDateString(
|
|
200
|
+
})} - ${weekEnd.toLocaleDateString(effectiveLocale, {
|
|
146
201
|
month: "short",
|
|
147
202
|
day: "numeric",
|
|
148
203
|
year: "numeric",
|
|
149
204
|
})}`
|
|
150
205
|
} else {
|
|
151
|
-
return selectedDate.toLocaleDateString(
|
|
206
|
+
return selectedDate.toLocaleDateString(effectiveLocale, {
|
|
152
207
|
weekday: "long",
|
|
153
208
|
month: "long",
|
|
154
209
|
day: "numeric",
|
|
@@ -182,13 +237,13 @@ function CalendarView({
|
|
|
182
237
|
}
|
|
183
238
|
|
|
184
239
|
return (
|
|
185
|
-
<div role="region" aria-label="Calendar" className={cn("flex flex-col h-full bg-background", className)}>
|
|
240
|
+
<div role="region" aria-label="Calendar" className={cn("flex flex-col h-full bg-background min-w-0 overflow-hidden", className)}>
|
|
186
241
|
{/* Header */}
|
|
187
|
-
<div className="flex items-center justify-between p-4 border-b">
|
|
242
|
+
<div className="flex flex-wrap items-center justify-between gap-2 p-2 sm:p-4 border-b min-w-0">
|
|
188
243
|
<div className="flex items-center gap-4">
|
|
189
244
|
<div className="flex items-center bg-muted/50 rounded-lg p-1 gap-1">
|
|
190
245
|
<Button variant="ghost" size="sm" onClick={handleToday} className="h-8" aria-label="Go to today">
|
|
191
|
-
|
|
246
|
+
{t('calendar.today')}
|
|
192
247
|
</Button>
|
|
193
248
|
<div className="h-4 w-px bg-border mx-1" />
|
|
194
249
|
<Button
|
|
@@ -217,7 +272,7 @@ function CalendarView({
|
|
|
217
272
|
variant="ghost"
|
|
218
273
|
aria-label={`Current date: ${getDateLabel()}`}
|
|
219
274
|
className={cn(
|
|
220
|
-
"text-xl font-semibold h-auto px-3 py-1 hover:bg-muted/50 transition-colors",
|
|
275
|
+
"text-base sm:text-xl font-semibold h-auto px-2 sm:px-3 py-1 hover:bg-muted/50 transition-colors",
|
|
221
276
|
"flex items-center gap-2"
|
|
222
277
|
)}
|
|
223
278
|
>
|
|
@@ -244,16 +299,16 @@ function CalendarView({
|
|
|
244
299
|
<SelectValue />
|
|
245
300
|
</SelectTrigger>
|
|
246
301
|
<SelectContent>
|
|
247
|
-
<SelectItem value="day">
|
|
248
|
-
<SelectItem value="week">
|
|
249
|
-
<SelectItem value="month">
|
|
302
|
+
<SelectItem value="day">{t('calendar.day')}</SelectItem>
|
|
303
|
+
<SelectItem value="week">{t('calendar.week')}</SelectItem>
|
|
304
|
+
<SelectItem value="month">{t('calendar.month')}</SelectItem>
|
|
250
305
|
</SelectContent>
|
|
251
306
|
</Select>
|
|
252
307
|
|
|
253
308
|
{onAddClick && (
|
|
254
309
|
<Button onClick={onAddClick} size="sm" className="gap-1">
|
|
255
310
|
<PlusIcon className="h-4 w-4" />
|
|
256
|
-
|
|
311
|
+
{t('calendar.newEvent')}
|
|
257
312
|
</Button>
|
|
258
313
|
)}
|
|
259
314
|
</div>
|
|
@@ -265,6 +320,7 @@ function CalendarView({
|
|
|
265
320
|
<MonthView
|
|
266
321
|
date={selectedDate}
|
|
267
322
|
events={events}
|
|
323
|
+
locale={effectiveLocale}
|
|
268
324
|
onEventClick={onEventClick}
|
|
269
325
|
onDateClick={onDateClick}
|
|
270
326
|
onEventDrop={onEventDrop}
|
|
@@ -274,7 +330,7 @@ function CalendarView({
|
|
|
274
330
|
<WeekView
|
|
275
331
|
date={selectedDate}
|
|
276
332
|
events={events}
|
|
277
|
-
locale={
|
|
333
|
+
locale={effectiveLocale}
|
|
278
334
|
onEventClick={onEventClick}
|
|
279
335
|
onDateClick={onDateClick}
|
|
280
336
|
/>
|
|
@@ -362,18 +418,50 @@ function getEventsForDate(date: Date, events: CalendarEvent[]): CalendarEvent[]
|
|
|
362
418
|
interface MonthViewProps {
|
|
363
419
|
date: Date
|
|
364
420
|
events: CalendarEvent[]
|
|
421
|
+
locale?: string
|
|
365
422
|
onEventClick?: (event: CalendarEvent) => void
|
|
366
423
|
onDateClick?: (date: Date) => void
|
|
367
424
|
onEventDrop?: (event: CalendarEvent, newStart: Date, newEnd?: Date) => void
|
|
368
425
|
}
|
|
369
426
|
|
|
370
|
-
function MonthView({ date, events, onEventClick, onDateClick, onEventDrop }: MonthViewProps) {
|
|
371
|
-
const days = getMonthDays(date)
|
|
372
|
-
const today = new Date()
|
|
373
|
-
const
|
|
427
|
+
function MonthView({ date, events, locale = "default", onEventClick, onDateClick, onEventDrop }: MonthViewProps) {
|
|
428
|
+
const days = React.useMemo(() => getMonthDays(date), [date.getFullYear(), date.getMonth()])
|
|
429
|
+
const today = React.useMemo(() => new Date(), [])
|
|
430
|
+
const { t } = useCalendarTranslation()
|
|
431
|
+
const weekDays = React.useMemo(() => {
|
|
432
|
+
const refSunday = new Date(2024, 0, 7)
|
|
433
|
+
return Array.from({ length: 7 }, (_, i) => {
|
|
434
|
+
const d = new Date(refSunday)
|
|
435
|
+
d.setDate(d.getDate() + i)
|
|
436
|
+
return d.toLocaleDateString(locale, { weekday: "short" })
|
|
437
|
+
})
|
|
438
|
+
}, [locale])
|
|
374
439
|
const [draggedEventId, setDraggedEventId] = React.useState<string | number | null>(null)
|
|
375
440
|
const [dropTargetIndex, setDropTargetIndex] = React.useState<number | null>(null)
|
|
376
441
|
|
|
442
|
+
// Pre-build event index by date key for O(1) lookup per cell instead of O(N)
|
|
443
|
+
const eventsByDate = React.useMemo(() => {
|
|
444
|
+
const map = new Map<string, CalendarEvent[]>()
|
|
445
|
+
for (const event of events) {
|
|
446
|
+
const eventStart = new Date(event.start)
|
|
447
|
+
const eventEnd = event.end ? new Date(event.end) : new Date(eventStart)
|
|
448
|
+
eventStart.setHours(0, 0, 0, 0)
|
|
449
|
+
eventEnd.setHours(0, 0, 0, 0)
|
|
450
|
+
const cursor = new Date(eventStart)
|
|
451
|
+
while (cursor <= eventEnd) {
|
|
452
|
+
const key = `${cursor.getFullYear()}-${cursor.getMonth()}-${cursor.getDate()}`
|
|
453
|
+
const arr = map.get(key)
|
|
454
|
+
if (arr) {
|
|
455
|
+
arr.push(event)
|
|
456
|
+
} else {
|
|
457
|
+
map.set(key, [event])
|
|
458
|
+
}
|
|
459
|
+
cursor.setDate(cursor.getDate() + 1)
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
return map
|
|
463
|
+
}, [events])
|
|
464
|
+
|
|
377
465
|
const handleDragStart = (e: React.DragEvent, event: CalendarEvent) => {
|
|
378
466
|
setDraggedEventId(event.id)
|
|
379
467
|
e.dataTransfer.effectAllowed = "move"
|
|
@@ -447,7 +535,8 @@ function MonthView({ date, events, onEventClick, onDateClick, onEventDrop }: Mon
|
|
|
447
535
|
{/* Calendar days */}
|
|
448
536
|
<div role="grid" aria-label="Calendar grid" className="grid grid-cols-7 flex-1 auto-rows-fr">
|
|
449
537
|
{days.map((day, index) => {
|
|
450
|
-
const
|
|
538
|
+
const key = `${day.getFullYear()}-${day.getMonth()}-${day.getDate()}`
|
|
539
|
+
const dayEvents = eventsByDate.get(key) || []
|
|
451
540
|
const isCurrentMonth = day.getMonth() === date.getMonth()
|
|
452
541
|
const isToday = isSameDay(day, today)
|
|
453
542
|
|
|
@@ -458,7 +547,7 @@ function MonthView({ date, events, onEventClick, onDateClick, onEventDrop }: Mon
|
|
|
458
547
|
aria-label={`${day.toLocaleDateString("default", { weekday: "long", month: "long", day: "numeric", year: "numeric" })}${dayEvents.length > 0 ? `, ${dayEvents.length} event${dayEvents.length > 1 ? "s" : ""}` : ""}`}
|
|
459
548
|
className={cn(
|
|
460
549
|
"border-b border-r last:border-r-0 p-2 min-h-[100px] cursor-pointer hover:bg-accent/50",
|
|
461
|
-
!isCurrentMonth && "bg-muted/
|
|
550
|
+
!isCurrentMonth && "bg-muted/50 text-muted-foreground opacity-50",
|
|
462
551
|
dropTargetIndex === index && "ring-2 ring-primary"
|
|
463
552
|
)}
|
|
464
553
|
onClick={() => onDateClick?.(day)}
|
|
@@ -468,7 +557,7 @@ function MonthView({ date, events, onEventClick, onDateClick, onEventDrop }: Mon
|
|
|
468
557
|
>
|
|
469
558
|
<div
|
|
470
559
|
className={cn(
|
|
471
|
-
"text-sm font-medium mb-
|
|
560
|
+
"text-sm font-medium mb-2",
|
|
472
561
|
isToday &&
|
|
473
562
|
"inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground h-6 w-6"
|
|
474
563
|
)}
|
|
@@ -481,13 +570,14 @@ function MonthView({ date, events, onEventClick, onDateClick, onEventDrop }: Mon
|
|
|
481
570
|
<div
|
|
482
571
|
key={event.id}
|
|
483
572
|
role="button"
|
|
573
|
+
title={event.title}
|
|
484
574
|
aria-label={event.title}
|
|
485
575
|
draggable={!!onEventDrop}
|
|
486
576
|
onDragStart={(e) => handleDragStart(e, event)}
|
|
487
577
|
onDragEnd={handleDragEnd}
|
|
488
578
|
className={cn(
|
|
489
579
|
"text-xs px-2 py-1 rounded truncate cursor-pointer hover:opacity-80",
|
|
490
|
-
event.color || DEFAULT_EVENT_COLOR,
|
|
580
|
+
event.color?.startsWith("#") ? "text-white" : (event.color || DEFAULT_EVENT_COLOR),
|
|
491
581
|
draggedEventId === event.id && "opacity-50"
|
|
492
582
|
)}
|
|
493
583
|
style={
|
|
@@ -505,7 +595,7 @@ function MonthView({ date, events, onEventClick, onDateClick, onEventDrop }: Mon
|
|
|
505
595
|
))}
|
|
506
596
|
{dayEvents.length > 3 && (
|
|
507
597
|
<div className="text-xs text-muted-foreground px-2">
|
|
508
|
-
|
|
598
|
+
{t('calendar.moreEvents', { count: dayEvents.length - 3 })}
|
|
509
599
|
</div>
|
|
510
600
|
)}
|
|
511
601
|
</div>
|
|
@@ -597,10 +687,11 @@ function WeekView({ date, events, locale = "default", onEventClick, onDateClick
|
|
|
597
687
|
<div
|
|
598
688
|
key={event.id}
|
|
599
689
|
role="button"
|
|
690
|
+
title={event.title}
|
|
600
691
|
aria-label={event.title}
|
|
601
692
|
className={cn(
|
|
602
693
|
"text-xs sm:text-sm px-2 sm:px-3 py-1.5 sm:py-2 rounded cursor-pointer hover:opacity-80",
|
|
603
|
-
event.color || DEFAULT_EVENT_COLOR
|
|
694
|
+
event.color?.startsWith("#") ? "text-white" : (event.color || DEFAULT_EVENT_COLOR)
|
|
604
695
|
)}
|
|
605
696
|
style={
|
|
606
697
|
event.color && event.color.startsWith("#")
|
|
@@ -689,10 +780,11 @@ function DayView({ date, events, onEventClick, onDateClick }: DayViewProps) {
|
|
|
689
780
|
{hourEvents.map((event) => (
|
|
690
781
|
<div
|
|
691
782
|
key={event.id}
|
|
783
|
+
title={event.title}
|
|
692
784
|
aria-label={event.title}
|
|
693
785
|
className={cn(
|
|
694
786
|
"px-2 sm:px-3 py-1.5 sm:py-2 rounded cursor-pointer hover:opacity-80",
|
|
695
|
-
event.color || DEFAULT_EVENT_COLOR
|
|
787
|
+
event.color?.startsWith("#") ? "text-white" : (event.color || DEFAULT_EVENT_COLOR)
|
|
696
788
|
)}
|
|
697
789
|
style={
|
|
698
790
|
event.color && event.color.startsWith("#")
|