@object-ui/plugin-timeline 17.6.0 → 17.7.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.
@@ -1 +1 @@
1
- (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("react"),require("@object-ui/components"),require("react/jsx-runtime"),require("@object-ui/core"),require("@object-ui/i18n"),require("@object-ui/react"),require("@object-ui/mobile"),require("zod")):typeof define==`function`&&define.amd?define([`exports`,`react`,`@object-ui/components`,`react/jsx-runtime`,`@object-ui/core`,`@object-ui/i18n`,`@object-ui/react`,`@object-ui/mobile`,`zod`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.ObjectUIPluginTimeline={},e.React,e.ObjectUIComponents,e.react_jsx_runtime,e.ObjectUICore,e._object_ui_i18n,e.ObjectUIReact,e.ObjectUIMobile,e.zod))})(this,function(e,t,n,r,i,a,o,s,c){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var l=Object.create,u=Object.defineProperty,d=Object.getOwnPropertyDescriptor,f=Object.getOwnPropertyNames,p=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty,h=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=f(t),a=0,o=i.length,s;a<o;a++)s=i[a],!m.call(e,s)&&s!==n&&u(e,s,{get:(e=>t[e]).bind(null,s),enumerable:!(r=d(t,s))||r.enumerable});return e};t=((e,t,n)=>(n=e==null?{}:l(p(e)),h(t||!e||!e.__esModule||!m.call(e,`default`)?u(n,`default`,{value:e,enumerable:!0}):n,e)))(t,1);var g={"timeline.bucket.overdue":`Overdue`,"timeline.bucket.today":`Today`,"timeline.bucket.tomorrow":`Tomorrow`,"timeline.bucket.thisWeek":`This week`,"timeline.bucket.nextWeek":`Next week`,"timeline.bucket.later":`Later`,"timeline.bucket.noDate":`No date`,"timeline.bucket.unassigned":`Unassigned`,"timeline.relative.today":`Today`,"timeline.relative.tomorrow":`Tomorrow`,"timeline.relative.yesterday":`Yesterday`,"timeline.relative.inDays":`In {{n}} days`,"timeline.relative.daysAgo":`{{n}} days ago`,"timeline.scale.week":`Week {{n}}`,"timeline.scale.quarter":`Q{{quarter}} {{year}}`,"timeline.gantt.rowLabel":`Items`},_=`timeline.bucket.today`,v=(e,t)=>Object.entries(t??{}).reduce((e,[t,n])=>e.split(`{{${t}}}`).join(String(n)),g[e]||e),y=(0,a.createSafeTranslation)(g,_),b=new Set([`hour`,`day`,`week`,`month`,`quarter`,`year`]);function x(e){let t=e.scale??e.timeScale;return typeof t==`string`&&b.has(t)?t:`month`}function S(e,t,n,r=`en`,i=v){let a=[],o=new Date(t),s=new Date(n);if(Number.isNaN(o.getTime())||Number.isNaN(s.getTime())||o>s)return a;let c=new Date(o);switch(e){case`hour`:for(;c<=s;)a.push(c.toLocaleString(r,{month:`short`,day:`numeric`,hour:`numeric`})),c.setHours(c.getHours()+1);break;case`day`:for(;c<=s;)a.push(c.toLocaleDateString(r,{month:`short`,day:`numeric`})),c.setDate(c.getDate()+1);break;case`week`:{let e=1;for(;c<=s;)a.push(i(`timeline.scale.week`,{n:e++})),c.setDate(c.getDate()+7);break}case`quarter`:for(c.setMonth(Math.floor(c.getMonth()/3)*3,1);c<=s;)a.push(i(`timeline.scale.quarter`,{quarter:Math.floor(c.getMonth()/3)+1,year:c.getFullYear()})),c.setMonth(c.getMonth()+3);break;case`year`:for(c.setMonth(0,1);c<=s;)a.push(String(c.getFullYear())),c.setFullYear(c.getFullYear()+1);break;default:for(;c<=s;)a.push(c.toLocaleDateString(r,{month:`short`,year:`numeric`})),c.setMonth(c.getMonth()+1)}return a}function C(e){let t=e.flatMap(e=>(e.items||[]).flatMap(e=>[e.startDate,e.endDate])),n=Math.min(...t.map(e=>new Date(e).getTime())),r=Math.max(...t.map(e=>new Date(e).getTime()));return{minDate:new Date(n).toISOString().split(`T`)[0],maxDate:new Date(r).toISOString().split(`T`)[0]}}function w(e,t,n,r){let i=new Date(e).getTime(),a=new Date(t).getTime(),o=new Date(n).getTime(),s=new Date(r).getTime()-o,c=i-o,l=a-i;return{start:c/s*100,width:l/s*100}}function T(e,t,n){let r=new Date(e);return t===`short`?r.toLocaleDateString(n):t===`long`?r.toLocaleDateString(n,{year:`numeric`,month:`long`,day:`numeric`}):r.toISOString().split(`T`)[0]}function E({label:e,color:t}){let i=t?{backgroundColor:`${t}22`,color:t,borderColor:`${t}55`}:void 0;return(0,r.jsx)(`span`,{className:(0,n.cn)(`inline-flex items-center rounded-full border px-2 py-0.5 text-xs font-medium`,!t&&`bg-muted text-muted-foreground border-transparent`),style:i,children:e})}function D(e){let t=[];for(let n of e){let e=n.group==null?``:String(n.group),r=t[t.length-1];r&&r.key===e?r.items.push(n):t.push({key:e,items:[n]})}return t}var O=({schema:e,className:t,...i})=>{let{variant:o=`vertical`,items:s=[],dateFormat:c=`short`,onItemClick:l}=e,u=(0,a.useDisplayLocale)(),{t:d}=y();if(o===`vertical`){let e=D(s),a=e.some(e=>e.key!==``),o=(e,t)=>{let i=e.color?{backgroundColor:`${e.color}33`,borderColor:e.color}:void 0,a=e.time?T(e.time,c,u):e.startDate?T(e.startDate,c,u):``,o=e.endDate&&e.endDate!==e.startDate?T(e.endDate,c,u):``,s=Array.isArray(e.meta)?e.meta:[];return(0,r.jsxs)(P,{density:`compact`,className:(0,n.cn)(e.className,l&&`cursor-pointer`),onClick:()=>l?.(e),children:[(0,r.jsx)(I,{variant:e.color?`default`:e.variant||`default`,style:i,children:e.icon&&(0,r.jsx)(`span`,{className:`text-xs`,children:e.icon})}),(0,r.jsxs)(L,{children:[(a||o)&&(0,r.jsxs)(z,{dateTime:e.time||e.startDate,className:`!mb-1 text-xs`,children:[a,o&&(0,r.jsxs)(`span`,{className:`text-muted-foreground/70`,children:[` → `,o]})]}),e.title&&(0,r.jsx)(R,{className:`text-sm sm:text-base mb-1`,children:e.title}),s.length>0&&(0,r.jsx)(`div`,{className:`flex flex-wrap gap-1.5 mt-1 mb-1`,children:s.map(e=>(0,r.jsx)(E,{label:e.label,color:e.color},e.key))}),e.description&&(0,r.jsx)(B,{className:`text-sm text-muted-foreground line-clamp-2 sm:line-clamp-none`,children:e.description}),e.content&&(0,n.renderChildren)(e.content)]})]},t)};return a?(0,r.jsx)(`div`,{className:(0,n.cn)(`px-4 sm:px-6 py-2`,t),...i,children:e.map((e,t)=>(0,r.jsxs)(`section`,{className:`mb-4`,children:[(0,r.jsxs)(`header`,{className:`sticky top-0 z-10 -mx-4 sm:-mx-6 px-4 sm:px-6 py-1.5 backdrop-blur bg-background/90 text-xs font-semibold uppercase tracking-wide text-muted-foreground border-b`,children:[(0,r.jsx)(`span`,{children:e.key}),(0,r.jsx)(`span`,{className:`ml-2 text-muted-foreground/60 font-normal normal-case`,children:e.items.length})]}),(0,r.jsx)(M,{className:`mt-3`,children:e.items.map((e,n)=>o(e,`${t}-${n}`))})]},`${e.key}-${t}`))}):(0,r.jsx)(M,{className:t,...i,children:s.map((e,t)=>o(e,t))})}if(o===`horizontal`)return(0,r.jsx)(V,{className:(0,n.cn)(`overflow-x-auto [-webkit-overflow-scrolling:touch]`,t),...i,children:s.map((e,t)=>(0,r.jsxs)(H,{className:(0,n.cn)(e.className,l&&`cursor-pointer`),onClick:()=>l?.(e),children:[(0,r.jsxs)(`div`,{className:`flex flex-col items-center`,children:[(0,r.jsx)(I,{variant:e.variant||`default`,children:e.icon&&(0,r.jsx)(`span`,{className:`text-xs`,children:e.icon})}),(0,r.jsxs)(`div`,{className:`mt-4 text-center`,children:[e.time&&(0,r.jsx)(z,{dateTime:e.time,children:T(e.time,c,u)}),e.title&&(0,r.jsx)(R,{children:e.title}),e.description&&(0,r.jsx)(B,{className:`text-center line-clamp-2 sm:line-clamp-none`,children:e.description}),e.content&&(0,n.renderChildren)(e.content)]})]}),t<s.length-1&&(0,r.jsx)(`div`,{className:`absolute left-full w-16 border-t-2 border-gray-200 top-3`})]},t))});if(o===`gantt`){let a=C(s),o=e.minDate||a.minDate,f=e.maxDate||a.maxDate,p=S(x(e),o,f,u,d);return(0,r.jsxs)(U,{className:(0,n.cn)(`overflow-x-auto [-webkit-overflow-scrolling:touch]`,t),...i,children:[(0,r.jsxs)(W,{children:[(0,r.jsx)(G,{className:`flex items-center px-2 sm:px-4 py-2 sm:py-3`,children:(0,r.jsx)(`span`,{className:`font-semibold text-xs sm:text-sm`,children:e.rowLabel||d(`timeline.gantt.rowLabel`)})}),(0,r.jsx)(K,{children:(0,r.jsx)(`div`,{className:`flex h-full`,children:p.map((e,t)=>(0,r.jsx)(`div`,{className:`flex-1 px-1 sm:px-2 py-2 sm:py-3 border-r text-xs font-medium text-center`,children:e},t))})})]}),(0,r.jsx)(`div`,{children:(0,r.jsxs)(`div`,{className:`flex`,children:[(0,r.jsx)(G,{children:s.map((e,t)=>(0,r.jsx)(q,{children:(0,r.jsx)(J,{title:e.label,className:`truncate`,children:e.label})},t))}),(0,r.jsx)(K,{className:`relative`,children:s.map((e,t)=>(0,r.jsx)(q,{className:`relative`,children:(e.items||[]).map((n,i)=>{let a=w(n.startDate,n.endDate,o,f);return(0,r.jsx)(Y,{start:a.start,width:a.width,variant:n.variant||`default`,onClick:()=>l?.(n,e,t,i),title:`${n.title||``}\n${T(n.startDate,c,u)} - ${T(n.endDate,c,u)}`,children:(0,r.jsx)(X,{children:n.title})},i)})},t))})]})})]})}return null};i.ComponentRegistry.register(`timeline`,O,{namespace:`plugin-timeline`,label:`Timeline`,category:`data-display`,inputs:[{name:`variant`,type:`enum`,enum:[`vertical`,`horizontal`,`gantt`],label:`Timeline Variant`,defaultValue:`vertical`},{name:`items`,type:`array`,label:`Timeline Items`,description:`For vertical/horizontal: Array of { time, title, description, variant, icon, content }. For gantt: Array of { label, items: [{ title, startDate, endDate, variant }] }`},{name:`dateFormat`,type:`enum`,enum:[`short`,`long`,`iso`],label:`Date Format`,defaultValue:`short`},{name:`timeScale`,type:`enum`,enum:[`day`,`week`,`month`],label:`Time Scale (Gantt only)`,defaultValue:`month`},{name:`rowLabel`,type:`string`,label:`Row Label (Gantt only)`,defaultValue:`Items`},{name:`minDate`,type:`string`,label:`Min Date (Gantt only)`,description:`Override auto-calculated min date (YYYY-MM-DD)`},{name:`maxDate`,type:`string`,label:`Max Date (Gantt only)`,description:`Override auto-calculated max date (YYYY-MM-DD)`},{name:`className`,type:`string`,label:`CSS Class`}],defaultProps:{variant:`vertical`,dateFormat:`short`,items:[{time:`2024-01-15`,title:`Project Started`,description:`Kickoff meeting and initial planning`,variant:`success`,icon:`🚀`},{time:`2024-02-01`,title:`First Milestone`,description:`Completed initial design phase`,variant:`info`,icon:`🎨`},{time:`2024-03-15`,title:`Beta Release`,description:`Released beta version to testers`,variant:`warning`,icon:`⚡`},{time:`2024-04-01`,title:`Launch`,description:`Official product launch`,variant:`success`,icon:`🎉`}]},examples:{vertical:{variant:`vertical`,dateFormat:`long`,items:[{time:`2024-01-15`,title:`Project Started`,description:`Kickoff meeting and initial planning`,variant:`success`},{time:`2024-02-01`,title:`First Milestone`,description:`Completed initial design phase`,variant:`info`}]},horizontal:{variant:`horizontal`,dateFormat:`short`,items:[{time:`2024-01-01`,title:`Q1`,description:`First quarter`,variant:`default`},{time:`2024-04-01`,title:`Q2`,description:`Second quarter`,variant:`info`},{time:`2024-07-01`,title:`Q3`,description:`Third quarter`,variant:`warning`},{time:`2024-10-01`,title:`Q4`,description:`Fourth quarter`,variant:`success`}]},gantt:{variant:`gantt`,dateFormat:`short`,timeScale:`month`,rowLabel:`Projects`,items:[{label:`Backend Development`,items:[{title:`API Design`,startDate:`2024-01-01`,endDate:`2024-01-31`,variant:`success`},{title:`Implementation`,startDate:`2024-02-01`,endDate:`2024-03-31`,variant:`info`}]},{label:`Frontend Development`,items:[{title:`UI Design`,startDate:`2024-01-15`,endDate:`2024-02-15`,variant:`warning`},{title:`Component Dev`,startDate:`2024-02-15`,endDate:`2024-04-15`,variant:`default`}]},{label:`Testing`,items:[{title:`QA Phase`,startDate:`2024-03-01`,endDate:`2024-04-30`,variant:`danger`}]}]}}});var k=c.z.object({title:c.z.string().optional(),date:c.z.string().optional(),description:c.z.string().optional(),variant:c.z.string().optional()}),A=c.z.object({mapping:k.optional(),objectName:c.z.string().optional(),titleField:c.z.string().optional(),dateField:c.z.string().optional(),startDateField:c.z.string().optional(),endDateField:c.z.string().optional(),descriptionField:c.z.string().optional(),groupByField:c.z.string().optional(),colorField:c.z.string().optional(),scale:c.z.enum([`hour`,`day`,`week`,`month`,`quarter`,`year`]).optional()}),j=({schema:e,dataSource:a,className:c,onRowClick:l,onItemClick:u,...d})=>{let[f,p]=(0,t.useState)([]),[m,h]=(0,t.useState)(()=>{let t=Array.isArray(e.items)&&e.items.length>0,n=Array.isArray(d.data)&&d.data.length>0;return!t&&!n&&!!e.objectName}),[g,_]=(0,t.useState)(null),[v,b]=(0,t.useState)(0),[x,S]=(0,t.useState)(null),C=e.timeline;(0,t.useEffect)(()=>{let t=A.safeParse(e);t.success||console.warn(`[ObjectTimeline] Invalid timeline configuration:`,t.error.format())},[e]);let w=(0,o.useDataScope)(e.bind);(0,t.useEffect)(()=>{let t=!0;return(async()=>{if(!(!a||typeof a.getObjectSchema!=`function`||!e.objectName))try{let n=await a.getObjectSchema(e.objectName);t&&S(n)}catch(e){console.warn(`Failed to fetch object def for ObjectTimeline`,e)}})(),()=>{t=!1}},[e.objectName,a]);let T=JSON.stringify(e.filter??null),E=JSON.stringify(e.sort??null);(0,t.useEffect)(()=>{e.objectName&&!w&&!e.items&&!d.data?(async()=>{if(!a||typeof a.find!=`function`||!e.objectName){h(!1);return}h(!0);try{let t=(0,i.buildExpandFields)(x?.fields),n=await a.find(e.objectName,{$filter:e.filter,$orderby:(0,i.convertSortToQueryParams)(e.sort),$top:e.limit??100,...t.length>0?{$expand:t}:{}}),r=(0,i.extractRecords)(n);p(r)}catch(e){console.error(e),_(e)}finally{h(!1)}})():h(!1)},[e.objectName,a,w,e.items,d.data,v,x,T,E,e.limit]);let D=d.data||w||f,{t:k}=y(),{fieldOptionLabel:j}=(0,o.useSafeFieldLabel)(),M=C?.titleField??e.mapping?.title??e.titleField??`name`,N=C?.startDateField??C?.dateField??e.mapping?.date??e.startDateField??e.dateField??`date`,P=C?.endDateField??e.endDateField??N,F=e.mapping?.description??e.descriptionField??`description`,I=e.mapping?.variant??`variant`,L=C?.groupByField??e.groupByField,R=C?.colorField??e.colorField,z=(0,t.useMemo)(()=>{if(e.items)return e.items;if(!D||!Array.isArray(D))return[];let t=x?.fields??{},n=e.objectName||``,r=e=>{if(!e||!t[e]?.options)return{};let n={};for(let r of t[e].options)r&&r.value!=null&&(n[String(r.value)]=r);return n},i=r(R),a=Array.isArray(C?.metaFields)?C.metaFields.filter(e=>typeof e==`string`&&e):[`status`,`priority`].filter(e=>t[e]),o={};for(let e of a)o[e]=r(e);let s=e=>{if(e==null||e===``)return;let t=i[String(e)];if(t?.color)return String(t.color);let n=String(e);if(/^#([0-9a-f]{3}){1,2}$/i.test(n)||n.startsWith(`rgb`)||n.startsWith(`hsl`))return n},c=(e,t,r)=>{if(t==null||t===``)return null;let i=r[String(t)];return{label:i?.label?j(n,e,String(t),i.label):String(t),color:i?.color}},l=D.map(e=>{let t=e[N],r=e[P],i=R?e[R]:void 0,l=L?e[L]:void 0,u=[];if(n)for(let t of a){let n=c(t,e[t],o[t]||{});n&&u.push({key:t,label:n.label,color:n.color})}return{title:e[M],time:t,startDate:t,endDate:r,description:e[F],variant:e[I]||`default`,color:s(i),group:l,meta:u,_data:e}});l.sort((e,t)=>(e.startDate?new Date(e.startDate).getTime():1/0)-(t.startDate?new Date(t.startDate).getTime():1/0));let u=new Date,d=e=>new Date(e.getFullYear(),e.getMonth(),e.getDate()).getTime(),f=d(u),p=864e5,m=f-(u.getDay()+6)%7*p+7*p,h=m+7*p,g=e=>{if(!e)return k(`timeline.bucket.noDate`);let t=d(new Date(e));return Number.isNaN(t)?k(`timeline.bucket.noDate`):t<f?k(`timeline.bucket.overdue`):t===f?k(`timeline.bucket.today`):t===f+p?k(`timeline.bucket.tomorrow`):k(t<m?`timeline.bucket.thisWeek`:t<h?`timeline.bucket.nextWeek`:`timeline.bucket.later`)};if(L&&!l.every(e=>e.group==null||e.group===``)){let e=r(L);return l.map(t=>{let n=c(L,t.group,e);return{...t,group:n?n.label:t.group!=null&&t.group!==``?String(t.group):k(`timeline.bucket.unassigned`)}})}return l.map(e=>({...e,group:g(e.startDate)}))},[e.items,D,x,e.objectName,M,N,P,F,I,R,L,k,j]),B=(0,t.useCallback)(async()=>{b(e=>e+1)},[]),{ref:V,isRefreshing:H,pullDistance:U}=(0,s.usePullToRefresh)({onRefresh:B,enabled:!!e.objectName&&!!a}),W=(0,o.useNavigationOverlay)({navigation:e.navigation,objectName:e.objectName,onRowClick:l??u}),G=C?.scale??e.scale,K={...e,items:z||[],className:c||e.className,...G?{timeScale:G}:{},onItemClick:e=>{let t=e._data||e;W.handleClick(t),u?.(t)}};return g?(0,r.jsxs)(`div`,{className:`p-4 text-destructive`,"data-testid":`timeline-error`,role:`alert`,children:[`Error loading timeline: `,g.message]}):m&&(!z||z.length===0)?(0,r.jsxs)(`div`,{className:`flex flex-col h-full min-h-[200px] p-4 gap-3`,"data-testid":`timeline-loading`,role:`status`,"aria-live":`polite`,"aria-busy":`true`,children:[(0,r.jsx)(`span`,{className:`sr-only`,children:`Loading timeline…`}),[0,1,2,3].map(e=>(0,r.jsxs)(`div`,{className:`flex items-start gap-3`,style:{opacity:Math.max(.3,1-e*.18)},children:[(0,r.jsx)(`div`,{className:`h-3 w-3 rounded-full bg-muted/70 animate-pulse mt-1.5 shrink-0`}),(0,r.jsxs)(`div`,{className:`flex-1 space-y-2`,children:[(0,r.jsx)(`div`,{className:`h-4 w-1/3 rounded bg-muted/70 animate-pulse`}),(0,r.jsx)(`div`,{className:`h-3 w-2/3 rounded bg-muted/50 animate-pulse`})]})]},e))]}):(0,r.jsxs)(`div`,{ref:V,className:`relative overflow-auto h-full min-w-0`,children:[U>0&&(0,r.jsx)(`div`,{className:`flex items-center justify-center text-xs text-muted-foreground`,style:{height:U},children:H?`Refreshing…`:`Pull to refresh`}),(0,r.jsx)(O,{schema:K}),W.isOverlay&&(0,r.jsx)(n.NavigationOverlay,{...W,title:`Timeline Item`,children:e=>(0,r.jsx)(`div`,{className:`space-y-3`,children:Object.entries(e).map(([e,t])=>(0,r.jsxs)(`div`,{className:`flex flex-col`,children:[(0,r.jsx)(`span`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wide`,children:e.replace(/_/g,` `)}),(0,r.jsx)(`span`,{className:`text-sm`,children:String(t??`—`)})]},e))})})]})},M=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`ol`,{ref:i,className:(0,n.cn)(`relative ml-3 border-l border-gray-200`,e),...t}));M.displayName=`Timeline`;var N=(0,n.cva)(`ml-6`,{variants:{density:{default:`mb-10`,compact:`mb-3`,comfortable:`mb-6`}},defaultVariants:{density:`default`}}),P=t.forwardRef(({className:e,density:t,...i},a)=>(0,r.jsx)(`li`,{ref:a,className:(0,n.cn)(N({density:t}),e),...i}));P.displayName=`TimelineItem`;var F=(0,n.cva)(`absolute -left-3 w-6 h-6 rounded-full border-2 flex items-center justify-center`,{variants:{variant:{default:`bg-blue-200 border-blue-400`,success:`bg-emerald-200 border-emerald-500`,warning:`bg-amber-200 border-amber-500`,danger:`bg-red-200 border-red-500`,info:`bg-purple-200 border-purple-500`,todo:`bg-slate-200 border-slate-400`,"in-progress":`bg-blue-200 border-blue-500`,done:`bg-emerald-200 border-emerald-500`}},defaultVariants:{variant:`default`}}),I=t.forwardRef(({className:e,variant:t=`default`,...i},a)=>(0,r.jsx)(`div`,{ref:a,className:(0,n.cn)(F({variant:t}),e),...i}));I.displayName=`TimelineMarker`;var L=t.forwardRef(({className:e,...t},n)=>(0,r.jsx)(`div`,{ref:n,className:e,...t}));L.displayName=`TimelineContent`;var R=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`h3`,{ref:i,className:(0,n.cn)(`font-semibold text-lg mb-1`,e),...t}));R.displayName=`TimelineTitle`;var z=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`time`,{ref:i,className:(0,n.cn)(`text-sm font-normal text-gray-500 mb-2 block`,e),...t}));z.displayName=`TimelineTime`;var B=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`p`,{ref:i,className:(0,n.cn)(`text-base text-gray-700`,e),...t}));B.displayName=`TimelineDescription`;var V=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`div`,{ref:i,className:(0,n.cn)(`relative flex overflow-x-auto py-8`,e),...t}));V.displayName=`TimelineHorizontal`;var H=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`div`,{ref:i,className:(0,n.cn)(`shrink-0 w-64 relative`,e),...t}));H.displayName=`TimelineHorizontalItem`;var U=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`div`,{ref:i,className:(0,n.cn)(`relative w-full border rounded-lg overflow-hidden`,e),...t}));U.displayName=`TimelineGantt`;var W=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`div`,{ref:i,className:(0,n.cn)(`flex border-b bg-gray-50`,e),...t}));W.displayName=`TimelineGanttHeader`;var G=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`div`,{ref:i,className:(0,n.cn)(`w-48 border-r bg-white`,e),...t}));G.displayName=`TimelineGanttRowLabels`;var K=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`div`,{ref:i,className:(0,n.cn)(`flex-1 overflow-x-auto`,e),...t}));K.displayName=`TimelineGanttGrid`;var q=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`div`,{ref:i,className:(0,n.cn)(`flex items-center border-b min-h-12`,e),...t}));q.displayName=`TimelineGanttRow`;var J=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`div`,{ref:i,className:(0,n.cn)(`px-4 py-2 font-medium text-sm truncate`,e),...t}));J.displayName=`TimelineGanttLabel`;var Y=t.forwardRef(({className:e,start:t=0,width:i=100,variant:a=`default`,...o},s)=>(0,r.jsx)(`div`,{ref:s,className:(0,n.cn)(`absolute h-8 rounded-md transition-colors cursor-pointer`,{default:`bg-blue-500 hover:bg-blue-600`,success:`bg-green-500 hover:bg-green-600`,warning:`bg-yellow-500 hover:bg-yellow-600`,danger:`bg-red-500 hover:bg-red-600`,info:`bg-purple-500 hover:bg-purple-600`}[a],e),style:{left:`${t}%`,width:`${i}%`},...o}));Y.displayName=`TimelineGanttBar`;var X=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`div`,{ref:i,className:(0,n.cn)(`px-2 py-1 text-white text-xs font-medium truncate`,e),...t}));X.displayName=`TimelineGanttBarContent`;var Z={filter:!0,sort:!0,limit:`limit`},Q=({schema:e,...t})=>{let{dataSource:n}=(0,o.useSchemaContext)()||{};return(0,r.jsx)(o.ElementDataSourceGate,{schema:e,mapping:Z,dataSource:n,testId:`object-timeline`,errorTitle:`This timeline’s data source could not be resolved`,children:e=>(0,r.jsx)(j,{schema:e,dataSource:n,...t})})};i.ComponentRegistry.register(`object-timeline`,Q,{namespace:`plugin-timeline`,label:`Object Timeline`,category:`view`,inputs:[{name:`objectName`,type:`string`,label:`Object Name`,required:!0},{name:`variant`,type:`enum`,enum:[`vertical`,`horizontal`,`gantt`],defaultValue:`vertical`}]}),i.ComponentRegistry.register(`timeline`,Q,{namespace:`view`,label:`Timeline View`,category:`view`,inputs:[{name:`objectName`,type:`string`,label:`Object Name`,required:!0},{name:`variant`,type:`enum`,enum:[`vertical`,`horizontal`,`gantt`],defaultValue:`vertical`}]}),e.ObjectTimeline=j,e.ObjectTimelineRenderer=Q,e.TIMELINE_SCALES=b,e.Timeline=M,e.TimelineContent=L,e.TimelineDescription=B,e.TimelineGantt=U,e.TimelineGanttBar=Y,e.TimelineGanttBarContent=X,e.TimelineGanttGrid=K,e.TimelineGanttHeader=W,e.TimelineGanttLabel=J,e.TimelineGanttRow=q,e.TimelineGanttRowLabels=G,e.TimelineHorizontal=V,e.TimelineHorizontalItem=H,e.TimelineItem=P,e.TimelineMarker=I,e.TimelineRenderer=O,e.TimelineTime=z,e.TimelineTitle=R,e.generateTimeScaleHeaders=S,e.resolveTimelineScale=x,e.timelineItemVariants=N,e.timelineMarkerVariants=F});
1
+ (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("react"),require("@object-ui/components"),require("react/jsx-runtime"),require("@object-ui/core"),require("@object-ui/i18n"),require("@object-ui/react"),require("@object-ui/permissions"),require("@object-ui/mobile"),require("zod")):typeof define==`function`&&define.amd?define([`exports`,`react`,`@object-ui/components`,`react/jsx-runtime`,`@object-ui/core`,`@object-ui/i18n`,`@object-ui/react`,`@object-ui/permissions`,`@object-ui/mobile`,`zod`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.ObjectUIPluginTimeline={},e.React,e.ObjectUIComponents,e.react_jsx_runtime,e.ObjectUICore,e._object_ui_i18n,e.ObjectUIReact,e._object_ui_permissions,e.ObjectUIMobile,e.zod))})(this,function(e,t,n,r,i,a,o,s,c,l){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var u=Object.create,d=Object.defineProperty,f=Object.getOwnPropertyDescriptor,p=Object.getOwnPropertyNames,m=Object.getPrototypeOf,h=Object.prototype.hasOwnProperty,g=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=p(t),a=0,o=i.length,s;a<o;a++)s=i[a],!h.call(e,s)&&s!==n&&d(e,s,{get:(e=>t[e]).bind(null,s),enumerable:!(r=f(t,s))||r.enumerable});return e};t=((e,t,n)=>(n=e==null?{}:u(m(e)),g(t||!e||!e.__esModule||!h.call(e,`default`)?d(n,`default`,{value:e,enumerable:!0}):n,e)))(t,1);var _={"timeline.bucket.overdue":`Overdue`,"timeline.bucket.today":`Today`,"timeline.bucket.tomorrow":`Tomorrow`,"timeline.bucket.thisWeek":`This week`,"timeline.bucket.nextWeek":`Next week`,"timeline.bucket.later":`Later`,"timeline.bucket.noDate":`No date`,"timeline.bucket.unassigned":`Unassigned`,"timeline.scale.week":`Week {{n}}`,"timeline.scale.quarter":`Q{{quarter}} {{year}}`,"timeline.gantt.rowLabel":`Items`,"timeline.gantt.unusableRange.malformedDate":`Unusable gantt date range — {{path}} is {{value}}, which is not a valid date. Every gantt date has to parse: the startDate and endDate on every row item, plus any minDate / maxDate pinned on the schema.`,"timeline.gantt.unusableRange.inverted":`Unusable gantt date range — minDate {{minDate}} is after maxDate {{maxDate}}. A pinned minDate / maxDate overrides the range computed from the rows, so this axis has no columns and no bar can be placed on it; swap the two values.`,"timeline.gantt.unusableRange.malformedRow":`Unusable gantt rows — {{path}} is {{value}}, which is not a row shape. A gantt draws items as a list of rows, every row as an object with a label and its own items, and every row's items as a list of bars; a null, a number, a string or a plain object in any of those places cannot be drawn.`,"timeline.unsupported.objectBoundGantt":`Unsupported variant "gantt" — an object-bound timeline renders the feed variants ({{variants}}). Gantt needs literal rows, each with its own nested items, so the gantt axis (scale) has no effect here.`,"timeline.unconfigured.noDateAxis":`Timeline date axis required — this view declares no date field, and an object-bound timeline will not invent one. Declare one of: {{fields}}. The first is the spec spelling; the rest are legacy aliases.`},v=`timeline.bucket.today`,y=(e,t)=>Object.entries(t??{}).reduce((e,[t,n])=>e.split(`{{${t}}}`).join(String(n)),_[e]||e),ee=(0,a.createSafeTranslation)(_,v),b=new Set([`hour`,`day`,`week`,`month`,`quarter`,`year`]);function te(e){let t=e.scale;return typeof t==`string`&&b.has(t)?t:`month`}function x(e){return typeof e==`string`?(0,i.toDisplayDate)(e):new Date(e)}function S(e){let t=new Date(e);return t.setHours(0,0,0,0),t}var ne=36e5,C={floor:e=>{let t=new Date(e);return t.setMinutes(0,0,0),t},step:e=>{e.setTime(e.getTime()+ne)},label:(e,t,n)=>e.toLocaleString(n,{month:`short`,day:`numeric`,hour:`numeric`})},w={floor:S,step:e=>{e.setDate(e.getDate()+1)},label:(e,t,n)=>e.toLocaleDateString(n,{month:`short`,day:`numeric`})},re={floor:S,step:e=>{e.setDate(e.getDate()+7)},label:(e,t,n,r)=>r(`timeline.scale.week`,{n:t+1})},T={floor:e=>{let t=S(e);return t.setDate(1),t},step:e=>{e.setMonth(e.getMonth()+1)},label:(e,t,n)=>e.toLocaleDateString(n,{month:`short`,year:`numeric`})},ie={floor:e=>{let t=S(e);return t.setMonth(Math.floor(t.getMonth()/3)*3,1),t},step:e=>{e.setMonth(e.getMonth()+3)},label:(e,t,n,r)=>r(`timeline.scale.quarter`,{quarter:Math.floor(e.getMonth()/3)+1,year:e.getFullYear()})},ae={floor:e=>{let t=S(e);return t.setMonth(0,1),t},step:e=>{e.setFullYear(e.getFullYear()+1)},label:e=>String(e.getFullYear())};function E(e){switch(e){case`hour`:return C;case`day`:return w;case`week`:return re;case`quarter`:return ie;case`year`:return ae;default:return T}}function D(e){return typeof e==`string`?(0,i.toDisplayEndDate)(e):x(e)}function O(e,t,n,r,i,a){let o=x(t).getTime(),s=x(n).getTime();if(Number.isNaN(o)||Number.isNaN(s)||o>s)return;let c=a===void 0?s:Math.max(s,a),l=E(e),u=[],d=l.floor(new Date(o));for(;d.getTime()<=c;){let e=d.getTime(),t=l.label(new Date(e),u.length,r,i);l.step(d),u.push({start:e,end:d.getTime(),label:t})}return{start:u[0].start,end:u[u.length-1].end,units:u}}function k(e,t,n){let r=e.end-e.start;return{start:(t-e.start)/r*100,width:(n-t)/r*100}}function oe(e,t,n,r=`en`,i=y){let a=O(e,t,n,r,i);return a?a.units.map(e=>e.label):[]}function A(){let e=(0,i.toDateInputValue)(new Date);return{minDate:e,maxDate:e}}function j(e){if(!Array.isArray(e))return{ok:!1,path:`items`,value:e};let t=[];for(let n=0;n<e.length;n++){let r=e[n];if(typeof r!=`object`||!r||Array.isArray(r))return{ok:!1,path:`items[${n}]`,value:r};let i=r.items;if(i&&!Array.isArray(i))return{ok:!1,path:`items[${n}].items`,value:i};t.push({authored:r,label:r.label,items:i||[]})}return{ok:!0,rows:t}}function M(e){let t=e.flatMap(e=>e.items.flatMap(e=>[e.startDate,e.endDate]));if(t.length===0)return A();let n=Math.min(...t.map(e=>x(e).getTime())),r=Math.max(...t.map(e=>x(e).getTime())),a=Math.max(...e.flatMap(e=>e.items.map(e=>{let t=x(e.startDate).getTime(),n=D(e.endDate).getTime();return n>t?n-1:t})));return{minDate:(0,i.toDateInputValue)(new Date(n)),maxDate:(0,i.toDateInputValue)(new Date(r)),through:a}}var N=e=>{try{return Date.prototype.getTime.call(e),!0}catch{return!1}};function P(e){return typeof e==`string`?JSON.stringify(e):e===void 0?`undefined`:e===null?`null`:typeof e==`symbol`?e.toString():typeof e==`bigint`?`${e}n`:typeof e==`number`||typeof e==`boolean`?String(e):N(e)?Date.prototype.toString.call(e):Array.isArray(e)?`an array`:typeof e==`function`?`a function`:`an object`}var F=e=>typeof e==`string`||typeof e==`number`&&Number.isFinite(e)||N(e);function I(e,t,n){let r=e=>!F(e)||Number.isNaN(x(e).getTime());for(let t=0;t<e.length;t++){let n=e[t].items;for(let e=0;e<n.length;e++)for(let i of[`startDate`,`endDate`]){let a=n[e]?.[i];if(r(a))return{path:`items[${t}].items[${e}].${i}`,value:a}}}for(let[e,i]of[[`minDate`,t],[`maxDate`,n]])if(i&&r(i))return{path:e,value:i}}function L(e,t,n){return k(n,x(e).getTime(),D(t).getTime())}function R(e,t,n){let r=(0,i.toDisplayDate)(e);return t===`short`?r.toLocaleDateString(n):t===`long`?r.toLocaleDateString(n,{year:`numeric`,month:`long`,day:`numeric`}):Number.isNaN(r.getTime())?String(e):(0,i.isRealCalendarDate)(e)?(0,i.toDateInputValue)(r):r.toISOString().split(`T`)[0]}function se({label:e,color:t}){let i=t?{backgroundColor:`${t}22`,color:t,borderColor:`${t}55`}:void 0;return(0,r.jsx)(`span`,{className:(0,n.cn)(`inline-flex items-center rounded-full border px-2 py-0.5 text-xs font-medium`,!t&&`bg-muted text-muted-foreground border-transparent`),style:i,children:e})}function ce(e){let t=[];for(let n of e){let e=n.group==null?``:String(n.group),r=t[t.length-1];r&&r.key===e?r.items.push(n):t.push({key:e,items:[n]})}return t}var z=({schema:e,className:t,style:o,...s})=>{let{variant:c=`vertical`,items:l=[],dateFormat:u=`short`,onItemClick:d}=e,f=(0,a.useDisplayLocale)(),{t:p}=ee();if(c===`vertical`){let e=ce(l),a=e.some(e=>e.key!==``),c=(e,t)=>{let i=e.color?{backgroundColor:`${e.color}33`,borderColor:e.color}:void 0,a=e.time?R(e.time,u,f):e.startDate?R(e.startDate,u,f):``,o=e.endDate&&e.endDate!==e.startDate?R(e.endDate,u,f):``,s=Array.isArray(e.meta)?e.meta:[];return(0,r.jsxs)(G,{density:`compact`,className:(0,n.cn)(e.className,d&&`cursor-pointer`),onClick:()=>d?.(e),children:[(0,r.jsx)(K,{variant:e.color?`default`:e.variant||`default`,style:i,children:e.icon&&(0,r.jsx)(`span`,{className:`text-xs`,children:e.icon})}),(0,r.jsxs)(q,{children:[(a||o)&&(0,r.jsxs)(Y,{dateTime:e.time||e.startDate,className:`!mb-1 text-xs`,children:[a,o&&(0,r.jsxs)(`span`,{className:`text-muted-foreground/70`,children:[` → `,o]})]}),e.title&&(0,r.jsx)(J,{className:`text-sm sm:text-base mb-1`,children:e.title}),s.length>0&&(0,r.jsx)(`div`,{className:`flex flex-wrap gap-1.5 mt-1 mb-1`,children:s.map(e=>(0,r.jsx)(se,{label:e.label,color:e.color},e.key))}),e.description&&(0,r.jsx)(X,{className:`text-sm text-muted-foreground line-clamp-2 sm:line-clamp-none`,children:e.description}),(0,n.renderChildren)(e.content)]})]},t)};return a?(0,r.jsx)(`div`,{...(0,i.toDomProps)(s),className:(0,n.cn)(`px-4 sm:px-6 py-2`,t),style:o,children:e.map((e,t)=>(0,r.jsxs)(`section`,{className:`mb-4`,children:[(0,r.jsxs)(`header`,{className:`sticky top-0 z-10 -mx-4 sm:-mx-6 px-4 sm:px-6 py-1.5 backdrop-blur bg-background/90 text-xs font-semibold uppercase tracking-wide text-muted-foreground border-b`,children:[(0,r.jsx)(`span`,{children:e.key}),(0,r.jsx)(`span`,{className:`ml-2 text-muted-foreground/60 font-normal normal-case`,children:e.items.length})]}),(0,r.jsx)(U,{className:`mt-3`,children:e.items.map((e,n)=>c(e,`${t}-${n}`))})]},`${e.key}-${t}`))}):(0,r.jsx)(U,{...(0,i.toDomProps)(s),className:t,style:o,children:l.map((e,t)=>c(e,t))})}if(c===`horizontal`)return(0,r.jsx)(he,{...(0,i.toDomProps)(s),className:(0,n.cn)(`overflow-x-auto [-webkit-overflow-scrolling:touch]`,t),style:o,children:l.map((e,t)=>(0,r.jsxs)(ge,{className:(0,n.cn)(e.className,d&&`cursor-pointer`),onClick:()=>d?.(e),children:[(0,r.jsxs)(`div`,{className:`flex flex-col items-center`,children:[(0,r.jsx)(K,{variant:e.variant||`default`,children:e.icon&&(0,r.jsx)(`span`,{className:`text-xs`,children:e.icon})}),(0,r.jsxs)(`div`,{className:`mt-4 text-center`,children:[e.time&&(0,r.jsx)(Y,{dateTime:e.time,children:R(e.time,u,f)}),e.title&&(0,r.jsx)(J,{children:e.title}),e.description&&(0,r.jsx)(X,{className:`text-center line-clamp-2 sm:line-clamp-none`,children:e.description}),(0,n.renderChildren)(e.content)]})]}),t<l.length-1&&(0,r.jsx)(`div`,{className:`absolute left-full w-16 border-t-2 border-gray-200 top-3`})]},t))});if(c===`gantt`){let a=j(l);if(!a.ok)return(0,r.jsx)(`div`,{className:`p-4 text-destructive`,"data-testid":`timeline-unusable-date-range`,role:`alert`,children:p(`timeline.gantt.unusableRange.malformedRow`,{path:a.path,value:P(a.value)})});let c=a.rows,m=I(c,e.minDate,e.maxDate);if(m)return(0,r.jsx)(`div`,{className:`p-4 text-destructive`,"data-testid":`timeline-unusable-date-range`,role:`alert`,children:p(`timeline.gantt.unusableRange.malformedDate`,{path:m.path,value:P(m.value)})});let h=M(c),g=e.minDate||h.minDate,_=e.maxDate||h.maxDate,v=O(te(e),g,_,f,p,e.maxDate?void 0:h.through);return v?(0,r.jsxs)(_e,{...(0,i.toDomProps)(s),className:(0,n.cn)(`overflow-x-auto [-webkit-overflow-scrolling:touch]`,t),style:o,children:[(0,r.jsxs)(ve,{children:[(0,r.jsx)(Z,{className:`flex items-center px-2 sm:px-4 py-2 sm:py-3`,children:(0,r.jsx)(`span`,{className:`font-semibold text-xs sm:text-sm`,children:e.rowLabel||p(`timeline.gantt.rowLabel`)})}),(0,r.jsx)(Q,{children:(0,r.jsx)(`div`,{className:`flex h-full`,children:v.units.map((e,t)=>(0,r.jsx)(`div`,{className:`shrink-0 min-w-0 overflow-hidden px-1 sm:px-2 py-2 sm:py-3 border-r text-xs font-medium text-center`,style:{width:`${k(v,e.start,e.end).width}%`},children:e.label},t))})})]}),(0,r.jsx)(`div`,{children:(0,r.jsxs)(`div`,{className:`flex`,children:[(0,r.jsx)(Z,{children:c.map((e,t)=>(0,r.jsx)($,{children:(0,r.jsx)(ye,{title:e.label,className:`truncate`,children:e.label})},t))}),(0,r.jsx)(Q,{className:`relative`,children:c.map((e,t)=>(0,r.jsx)($,{className:`relative`,children:e.items.map((n,i)=>{let a=L(n.startDate,n.endDate,v);return(0,r.jsx)(be,{start:a.start,width:a.width,variant:n.variant||`default`,onClick:()=>d?.(n,e.authored,t,i),title:`${n.title||``}\n${R(n.startDate,u,f)} - ${R(n.endDate,u,f)}`,children:(0,r.jsx)(xe,{children:n.title})},i)})},t))})]})})]}):(0,r.jsx)(`div`,{className:`p-4 text-destructive`,"data-testid":`timeline-unusable-date-range`,role:`alert`,children:p(`timeline.gantt.unusableRange.inverted`,{minDate:P(g),maxDate:P(_)})})}return null};i.ComponentRegistry.register(`timeline`,z,{namespace:`plugin-timeline`,skipFallback:!0,label:`Timeline`,category:`data-display`,inputs:[{name:`variant`,type:`enum`,enum:[`vertical`,`horizontal`,`gantt`]},{name:`items`,type:`array`,description:`For vertical/horizontal: Array of { time, title, description, variant, icon, content }. For gantt: Array of { label, items: [{ title, startDate, endDate, variant }] }`},{name:`dateFormat`,type:`enum`,enum:[`short`,`long`,`iso`]},{name:`scale`,type:`enum`,enum:[...b]},{name:`rowLabel`,type:`string`},{name:`minDate`,type:`string`,description:`Override auto-calculated min date (YYYY-MM-DD)`},{name:`maxDate`,type:`string`,description:`Override auto-calculated max date (YYYY-MM-DD)`},{name:`className`,type:`string`}],defaultProps:{variant:`vertical`,dateFormat:`short`,items:[{time:`2024-01-15`,title:`Project Started`,description:`Kickoff meeting and initial planning`,variant:`success`,icon:`🚀`},{time:`2024-02-01`,title:`First Milestone`,description:`Completed initial design phase`,variant:`info`,icon:`🎨`},{time:`2024-03-15`,title:`Beta Release`,description:`Released beta version to testers`,variant:`warning`,icon:`⚡`},{time:`2024-04-01`,title:`Launch`,description:`Official product launch`,variant:`success`,icon:`🎉`}]},examples:{vertical:{variant:`vertical`,dateFormat:`long`,items:[{time:`2024-01-15`,title:`Project Started`,description:`Kickoff meeting and initial planning`,variant:`success`},{time:`2024-02-01`,title:`First Milestone`,description:`Completed initial design phase`,variant:`info`}]},horizontal:{variant:`horizontal`,dateFormat:`short`,items:[{time:`2024-01-01`,title:`Q1`,description:`First quarter`,variant:`default`},{time:`2024-04-01`,title:`Q2`,description:`Second quarter`,variant:`info`},{time:`2024-07-01`,title:`Q3`,description:`Third quarter`,variant:`warning`},{time:`2024-10-01`,title:`Q4`,description:`Fourth quarter`,variant:`success`}]},gantt:{variant:`gantt`,dateFormat:`short`,scale:`month`,rowLabel:`Projects`,items:[{label:`Backend Development`,items:[{title:`API Design`,startDate:`2024-01-01`,endDate:`2024-01-31`,variant:`success`},{title:`Implementation`,startDate:`2024-02-01`,endDate:`2024-03-31`,variant:`info`}]},{label:`Frontend Development`,items:[{title:`UI Design`,startDate:`2024-01-15`,endDate:`2024-02-15`,variant:`warning`},{title:`Component Dev`,startDate:`2024-02-15`,endDate:`2024-04-15`,variant:`default`}]},{label:`Testing`,items:[{title:`QA Phase`,startDate:`2024-03-01`,endDate:`2024-04-30`,variant:`danger`}]}]}}});function B(e){return typeof e==`number`&&Number.isInteger(e)&&e>0}function le(e,t){return B(e)?e:t}function ue(e,t){return e==null||B(e)?null:`[ObjectUI] ObjectTimeline row cap: ${typeof t==`string`&&t?`object-timeline on ${t}`:`object-timeline`} declared limit: ${String(e)}, which is not a positive integer. A row cap must be a positive integer (the spec refuses zero and negative values), so it was ignored and this timeline fell back to its default row cap (100).`}var de=[`vertical`,`horizontal`],fe=[`timeline.startDateField`,`timeline.dateField`,`mapping.date`,`startDateField`,`dateField`],V=l.z.object({title:l.z.string().optional(),date:l.z.string().optional(),description:l.z.string().optional(),variant:l.z.string().optional()}),pe=l.z.object({mapping:V.optional(),objectName:l.z.string().optional(),titleField:l.z.string().optional(),dateField:l.z.string().optional(),startDateField:l.z.string().optional(),endDateField:l.z.string().optional(),descriptionField:l.z.string().optional(),groupByField:l.z.string().optional(),colorField:l.z.string().optional(),scale:l.z.enum([`hour`,`day`,`week`,`month`,`quarter`,`year`]).optional()}),H=({schema:e,dataSource:a,className:l,onRowClick:u,onItemClick:d,...f})=>{let[p,m]=(0,t.useState)([]),[h,g]=(0,t.useState)(()=>{let t=Array.isArray(e.items)&&e.items.length>0,n=Array.isArray(f.data)&&f.data.length>0;return!t&&!n&&!!e.objectName}),[_,v]=(0,t.useState)(null),y=(0,t.useRef)(0),[b,te]=(0,t.useState)(0),x=e.timeline;(0,t.useEffect)(()=>{let t=pe.safeParse(e);t.success||console.warn(`[ObjectTimeline] Invalid timeline configuration:`,t.error.format())},[e]),(0,t.useEffect)(()=>{let t=ue(e.limit,e.objectName);t&&console.warn(t)},[e.limit,e.objectName]);let S=(0,o.useDataScope)(e.bind),{ready:ne,def:C}=(0,o.useSettledSchema)(e.objectName??``,a),w=(0,s.usePermissions)(),re=(0,o.useFilterScope)(),T=(0,o.useResolvedFilter)(e.filter,re),ie=JSON.stringify(T??null),ae=JSON.stringify(e.sort??null),E=!!e.objectName&&!S&&!e.items&&!f.data,D=(0,o.useDataInvalidation)(E?e.objectName:void 0);(0,t.useEffect)(()=>{let t=++y.current,n=()=>y.current===t,r=async()=>{if(!a||typeof a.find!=`function`||!e.objectName){g(!1);return}g(!0);try{let t=(0,i.buildExpandFields)(C?.fields),r=w?.isLoaded?t.filter(t=>w.checkField(e.objectName,t,`read`)):t,o=await a.find(e.objectName,{$filter:T,$orderby:(0,i.convertSortToQueryParams)(e.sort),$top:le(e.limit,100),...r.length>0?{$expand:r}:{}}),s=(0,i.extractRecords)(o);n()&&(m(s),v(null))}catch(e){console.error(e),n()&&v(e)}finally{n()&&g(!1)}};if(E){if(!ne)return;r()}else g(!1)},[e.objectName,a,S,e.items,f.data,b,ne,C,ie,ae,e.limit,w,D]);let O=f.data||S||p,{t:k}=ee(),{fieldOptionLabel:oe}=(0,o.useSafeFieldLabel)(),A=x?.titleField??e.mapping?.title??e.titleField??`name`,j=x?.startDateField??x?.dateField??e.mapping?.date??e.startDateField??e.dateField,M=x?.endDateField??e.endDateField??j,N=e.mapping?.description??e.descriptionField??`description`,P=e.mapping?.variant??`variant`,F=x?.groupByField??e.groupByField,I=x?.colorField??e.colorField,L=(0,t.useMemo)(()=>{if(e.items)return e.items;if(!O||!Array.isArray(O)||!j)return[];let t=j,n=M??j,r=C?.fields??{},a=e.objectName||``,o=e=>{if(!e||!r[e]?.options)return{};let t={};for(let n of r[e].options)n&&n.value!=null&&(t[String(n.value)]=n);return t},s=[`status`,`priority`].filter(e=>r[e]),c={};for(let e of s)c[e]=o(e);let l=(0,i.createFieldColorResolver)(r[I??``]),u=(e,t,n)=>{if(t==null||t===``)return null;let r=n[String(t)];return{label:r?.label?oe(a,e,String(t),r.label):String(t),color:r?.color}},d=O.map(e=>{let r=e[t],o=e[n],d=I?e[I]:void 0,f=F?e[F]:void 0,p=[];if(a)for(let t of s){let n=u(t,e[t],c[t]||{});n&&p.push({key:t,label:n.label,color:n.color})}return{title:(0,i.recordDisplayValueAt)(e,A),time:r,startDate:r,endDate:o,description:(0,i.recordDisplayValueAt)(e,N),variant:e[P]||`default`,color:l(d),group:f,meta:p,_data:e}}),f=e=>{if(!e)return 1/0;let t=(0,i.toDisplayDate)(e).getTime();return Number.isNaN(t)?1/0:t};d.sort((e,t)=>f(e.startDate)-f(t.startDate));let p=new Date,m=e=>new Date(e.getFullYear(),e.getMonth(),e.getDate()).getTime(),h=m(p),g=864e5,_=h-(p.getDay()+6)%7*g+7*g,v=_+7*g,y=e=>{if(!e)return k(`timeline.bucket.noDate`);let t=m((0,i.toDisplayDate)(e));return Number.isNaN(t)?k(`timeline.bucket.noDate`):t<h?k(`timeline.bucket.overdue`):t===h?k(`timeline.bucket.today`):t===h+g?k(`timeline.bucket.tomorrow`):k(t<_?`timeline.bucket.thisWeek`:t<v?`timeline.bucket.nextWeek`:`timeline.bucket.later`)};if(F&&!d.every(e=>e.group==null||e.group===``)){let e=o(F);return d.map(t=>{let n=u(F,t.group,e);return{...t,group:n?n.label:t.group!=null&&t.group!==``?String(t.group):k(`timeline.bucket.unassigned`)}})}return d.map(e=>({...e,group:y(e.startDate)}))},[e.items,O,C,e.objectName,A,j,M,N,P,I,F,k,oe]),R=(0,t.useCallback)(async()=>{te(e=>e+1)},[]),{ref:se,isRefreshing:ce,pullDistance:B}=(0,c.usePullToRefresh)({onRefresh:R,enabled:!!e.objectName&&!!a}),V=(0,o.useNavigationOverlay)({navigation:e.navigation,objectName:e.objectName,onRowClick:u??d}),H=x?.scale??e.scale,U=!!e.items;if(!U&&e.variant===`gantt`)return(0,r.jsx)(`div`,{className:`p-4 text-destructive`,"data-testid":`timeline-unsupported-variant`,role:`alert`,children:k(`timeline.unsupported.objectBoundGantt`,{variants:de.join(`, `)})});if(!U&&!j)return(0,r.jsx)(`div`,{className:`p-4 text-destructive`,"data-testid":`timeline-missing-date-axis`,role:`alert`,children:k(`timeline.unconfigured.noDateAxis`,{fields:fe.join(`, `)})});let W={...e,items:L||[],className:l||e.className,...H?{scale:H}:{},onItemClick:e=>{let t=e._data||e;V.handleClick(t),d?.(t)}};return _?(0,r.jsxs)(`div`,{className:`p-4 text-destructive`,"data-testid":`timeline-error`,role:`alert`,children:[`Error loading timeline: `,_.message]}):h&&(!L||L.length===0)?(0,r.jsxs)(`div`,{className:`flex flex-col h-full min-h-[200px] p-4 gap-3`,"data-testid":`timeline-loading`,role:`status`,"aria-live":`polite`,"aria-busy":`true`,children:[(0,r.jsx)(`span`,{className:`sr-only`,children:`Loading timeline…`}),[0,1,2,3].map(e=>(0,r.jsxs)(`div`,{className:`flex items-start gap-3`,style:{opacity:Math.max(.3,1-e*.18)},children:[(0,r.jsx)(`div`,{className:`h-3 w-3 rounded-full bg-muted/70 animate-pulse mt-1.5 shrink-0`}),(0,r.jsxs)(`div`,{className:`flex-1 space-y-2`,children:[(0,r.jsx)(`div`,{className:`h-4 w-1/3 rounded bg-muted/70 animate-pulse`}),(0,r.jsx)(`div`,{className:`h-3 w-2/3 rounded bg-muted/50 animate-pulse`})]})]},e))]}):(0,r.jsxs)(`div`,{ref:se,className:`relative overflow-auto h-full min-w-0`,"data-testid":`timeline-canvas`,children:[B>0&&(0,r.jsx)(`div`,{className:`flex items-center justify-center text-xs text-muted-foreground`,style:{height:B},children:ce?`Refreshing…`:`Pull to refresh`}),(0,r.jsx)(z,{schema:W}),V.isOverlay&&(0,r.jsx)(n.NavigationOverlay,{...V,title:`Timeline Item`,children:e=>(0,r.jsx)(`div`,{className:`space-y-3`,children:Object.entries(e).map(([e,t])=>(0,r.jsxs)(`div`,{className:`flex flex-col`,children:[(0,r.jsx)(`span`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wide`,children:e.replace(/_/g,` `)}),(0,r.jsx)(`span`,{className:`text-sm`,children:String(t??`—`)})]},e))})})]})},U=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`ol`,{ref:i,className:(0,n.cn)(`relative ml-3 border-l border-gray-200`,e),...t}));U.displayName=`Timeline`;var W=(0,n.cva)(`ml-6`,{variants:{density:{default:`mb-10`,compact:`mb-3`,comfortable:`mb-6`}},defaultVariants:{density:`default`}}),G=t.forwardRef(({className:e,density:t,...i},a)=>(0,r.jsx)(`li`,{ref:a,className:(0,n.cn)(W({density:t}),e),...i}));G.displayName=`TimelineItem`;var me=(0,n.cva)(`absolute -left-3 w-6 h-6 rounded-full border-2 flex items-center justify-center`,{variants:{variant:{default:`bg-blue-200 border-blue-400`,success:`bg-emerald-200 border-emerald-500`,warning:`bg-amber-200 border-amber-500`,danger:`bg-red-200 border-red-500`,info:`bg-purple-200 border-purple-500`,todo:`bg-slate-200 border-slate-400`,"in-progress":`bg-blue-200 border-blue-500`,done:`bg-emerald-200 border-emerald-500`}},defaultVariants:{variant:`default`}}),K=t.forwardRef(({className:e,variant:t=`default`,...i},a)=>(0,r.jsx)(`div`,{ref:a,className:(0,n.cn)(me({variant:t}),e),...i}));K.displayName=`TimelineMarker`;var q=t.forwardRef(({className:e,...t},n)=>(0,r.jsx)(`div`,{ref:n,className:e,...t}));q.displayName=`TimelineContent`;var J=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`h3`,{ref:i,className:(0,n.cn)(`font-semibold text-lg mb-1`,e),...t}));J.displayName=`TimelineTitle`;var Y=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`time`,{ref:i,className:(0,n.cn)(`text-sm font-normal text-gray-500 mb-2 block`,e),...t}));Y.displayName=`TimelineTime`;var X=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`p`,{ref:i,className:(0,n.cn)(`text-base text-gray-700`,e),...t}));X.displayName=`TimelineDescription`;var he=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`div`,{ref:i,className:(0,n.cn)(`relative flex overflow-x-auto py-8`,e),...t}));he.displayName=`TimelineHorizontal`;var ge=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`div`,{ref:i,className:(0,n.cn)(`shrink-0 w-64 relative`,e),...t}));ge.displayName=`TimelineHorizontalItem`;var _e=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`div`,{ref:i,className:(0,n.cn)(`relative w-full border rounded-lg overflow-hidden`,e),...t}));_e.displayName=`TimelineGantt`;var ve=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`div`,{ref:i,className:(0,n.cn)(`flex border-b bg-gray-50`,e),...t}));ve.displayName=`TimelineGanttHeader`;var Z=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`div`,{ref:i,className:(0,n.cn)(`w-48 border-r bg-white`,e),...t}));Z.displayName=`TimelineGanttRowLabels`;var Q=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`div`,{ref:i,className:(0,n.cn)(`flex-1 overflow-x-auto`,e),...t}));Q.displayName=`TimelineGanttGrid`;var $=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`div`,{ref:i,className:(0,n.cn)(`flex items-center border-b min-h-12`,e),...t}));$.displayName=`TimelineGanttRow`;var ye=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`div`,{ref:i,className:(0,n.cn)(`px-4 py-2 font-medium text-sm truncate`,e),...t}));ye.displayName=`TimelineGanttLabel`;var be=t.forwardRef(({className:e,start:t=0,width:i=100,variant:a=`default`,...o},s)=>(0,r.jsx)(`div`,{ref:s,className:(0,n.cn)(`absolute h-8 rounded-md transition-colors cursor-pointer`,{default:`bg-blue-500 hover:bg-blue-600`,success:`bg-green-500 hover:bg-green-600`,warning:`bg-yellow-500 hover:bg-yellow-600`,danger:`bg-red-500 hover:bg-red-600`,info:`bg-purple-500 hover:bg-purple-600`}[a],e),style:{left:`${t}%`,width:`${i}%`},...o}));be.displayName=`TimelineGanttBar`;var xe=t.forwardRef(({className:e,...t},i)=>(0,r.jsx)(`div`,{ref:i,className:(0,n.cn)(`px-2 py-1 text-white text-xs font-medium truncate`,e),...t}));xe.displayName=`TimelineGanttBarContent`;var Se={filter:!0,sort:!0,limit:`limit`},Ce=(0,i.elementDataSourceBlock)(({schema:e,...t})=>{let{dataSource:n}=(0,o.useSchemaContext)()||{};return(0,r.jsx)(o.ElementDataSourceGate,{schema:e,mapping:Se,dataSource:n,testId:`object-timeline`,errorTitle:`This timeline’s data source could not be resolved`,children:e=>(0,r.jsx)(H,{schema:e,dataSource:n,...t})})}),we=[{name:`objectName`,type:`string`,description:"Object this timeline binds to. Optional because the component-level `dataSource` binding can supply the object instead — this block registers through `ElementDataSourceGate`, which lowers the binding onto this key before the renderer sees the node. A timeline drawn from `items`, `data` or a `bind` path issues no query and needs none to draw, but `navigation` still reads it: without it `page` opens nothing and `new_window` / `openNewTab` open no record page."},{name:`variant`,type:`enum`,enum:[`vertical`,`horizontal`,`gantt`]},{name:`filter`,type:`array`,description:"Base query filter in the rule-array form `[{ field, operator, value }, ...]`, narrowing the records the timeline fetches. Context tokens such as `{current_user_id}` are resolved first, then the filter is lowered to `$filter` on the query. Authored `items` or `data` suppress that query, so the key then narrows nothing. The MongoDB-style record form is not this key’s shape."},{name:`sort`,type:`array`,description:"Order of the records the timeline fetches, in `[{ field, order }]` form, lowered to `$orderby` on the same query. The rail draws entries composed from records by their start date, earliest first, whatever this order. Authored `items` or `data` suppress the query, so the key then orders nothing."},{name:`navigation`,type:`object`,description:"What an entry click opens — the `{ mode, size, openNewTab, preventNavigation }` block a list view declares. With the key ABSENT a click opens nothing: this renderer supplies no drawer default. `mode` is an overlay (`drawer`, `modal`, `split`, `popover`), `new_window`, `page` or `none`, and a block written without `mode` takes the spec’s `page` default. `drawer`, `modal` and `popover` open the entry’s record in that overlay, but `split` opens nothing, because the timeline hands the split shell no main panel; `new_window` opens the record page in a new tab; `none` opens nothing. `page` opens the record page of the timeline’s `objectName` through the record navigator the host publishes (the console publishes one on its custom pages, record pages and list views); under a host that publishes none, such as an embedded renderer, or on a timeline that names no `objectName`, there is no record page to open and the click opens nothing. `preventNavigation: true` opens nothing whatever the mode, `openNewTab: true` opens the record page in a new tab and outranks every mode except `none`, and `size` sets the overlay width. On a timeline that names no `objectName`, `new_window` and `openNewTab` open no record page either: the new tab’s address is a slash and the entry’s `id` alone (its `_id` when it has no `id`, `undefined` when it has neither). A click handler from a parent view outranks the whole key."},{name:`timeline`,type:`object`,description:"Timeline configuration, the author face — the same block `ListViewSchema.timeline` declares: { startDateField, endDateField, titleField, groupByField, colorField, scale }. The flat top-level spellings beside it are the runtime handoff, not a second authoring spelling. On entries composed from records, `startDateField` is the entry’s date, `endDateField` the end printed after it, `titleField` the title, `groupByField` the field whose value heads each group (without it, entries group into date buckets), and `colorField` the field whose option colour, or the value itself when it is a colour literal, paints the marker. Each outranks the flat key of the same binding, and `titleField` / `startDateField` outrank `mapping`’s `title` / `date`. `scale` sets the axis unit of the gantt branch, which on this block draws authored `items` only."},{name:`limit`,type:`number`,description:"Maximum number of records loaded onto the rail (row cap); lowered to the query's top-level `$top` (renderer default 100). A timeline renders one rail with no pagination control, so this is the author's window rather than a page size. A value that is not a positive integer is ignored with a console warning, and the default cap applies."},{name:`data`,type:`array`,description:"Pre-fetched records — read FIRST as the rail's row source, ahead of the data-scope binding and the fetch, and composed into entries through the same `timeline` field bindings a fetched row takes; authoring it suppresses the object query entirely. Distinct from `items`, which is the already-composed entry shape and wins over this key when both are written."},{name:`items`,type:`array`,description:"Static inline entries — read ahead of every record source, `data` above included, and bypasses the object query entirely (the renderer becomes a pass-through). Each element is objectui's declared timeline element, `@object-ui/types`'s `TimelineFeedItem` (`variant` absent / `vertical` / `horizontal`) or `TimelineGanttItem` (`variant: 'gantt'`), the arm this node's `variant` selects. They are drawn as written: the `timeline` block’s field bindings, `mapping` and `descriptionField` do not apply to them."},{name:`dateFormat`,type:`enum`,enum:[`short`,`long`,`iso`],description:"How each entry's date is rendered (renderer default `short`): `short` / `long` are locale-formatted, `iso` is the locale-free machine form."},{name:`rowLabel`,type:`string`,description:"Header label for the gantt row column — read by the gantt branch only, which on this block needs authored `items`. Without it the header shows the default label."},{name:`minDate`,type:`string`,description:"Pin the gantt axis start (ISO `yyyy-mm-dd`) instead of deriving it from the rows; only a non-empty value is honoured. A value that is not a date, or a `minDate` after `maxDate`, refuses the chart with a diagnostic naming it."},{name:`maxDate`,type:`string`,description:"Pin the gantt axis end (ISO `yyyy-mm-dd`) instead of deriving it from the rows; only a non-empty value is honoured. A value that is not a date, or a `maxDate` before `minDate`, refuses the chart with a diagnostic naming it."},{name:`descriptionField`,type:`string`,description:"Field rendered as each entry's description (renderer default `description`). It is declared flat because the `timeline` block has no member for it, and `mapping.description` outranks it when both are written."},{name:`mapping`,type:`object`,description:"Record-to-entry field mapping ({ title, date, description, variant }) — the objectui-side binding record read BETWEEN the `timeline` block and the flat fallbacks. Its `variant` member (the field whose value picks each marker colour, renderer default `variant`) is the only spelling that binding has. On the vertical rail a colour that `timeline.colorField` resolves for an entry outranks that marker colour."}];i.ComponentRegistry.register(`object-timeline`,Ce,{namespace:`plugin-timeline`,label:`Object Timeline`,category:`view`,inputs:[...we]}),i.ComponentRegistry.register(`timeline`,Ce,{namespace:`view`,label:`Timeline View`,category:`view`,inputs:[...we]}),e.ObjectTimeline=H,e.ObjectTimelineRenderer=Ce,e.TIMELINE_SCALES=b,e.Timeline=U,e.TimelineContent=q,e.TimelineDescription=X,e.TimelineGantt=_e,e.TimelineGanttBar=be,e.TimelineGanttBarContent=xe,e.TimelineGanttGrid=Q,e.TimelineGanttHeader=ve,e.TimelineGanttLabel=ye,e.TimelineGanttRow=$,e.TimelineGanttRowLabels=Z,e.TimelineHorizontal=he,e.TimelineHorizontalItem=ge,e.TimelineItem=G,e.TimelineMarker=K,e.TimelineRenderer=z,e.TimelineTime=Y,e.TimelineTitle=J,e.generateTimeScaleHeaders=oe,e.resolveTimelineScale=te,e.timelineItemVariants=W,e.timelineMarkerVariants=me});
@@ -0,0 +1,50 @@
1
+ import { TimelineFeedItem, TimelineGanttItem, TimelineSchema } from '@object-ui/types';
2
+ /** One inline chip beside an item's title — a record's status / priority option. */
3
+ export interface TimelineRenderMetaChip {
4
+ key: string;
5
+ label: string;
6
+ color?: string;
7
+ }
8
+ /**
9
+ * A feed item as the renderer receives it: an authored {@link TimelineFeedItem},
10
+ * or one `ObjectTimeline` composed from a record.
11
+ *
12
+ * Three authored keys are WIDER here because the composer fills them from
13
+ * record values rather than from an author: `title` may be absent (a record
14
+ * with no display value), `time` is the record's raw start value, and
15
+ * `variant` is the record's own value — which is why the marker primitive
16
+ * paints `todo` / `in-progress` / `done` besides the five authoring colours.
17
+ */
18
+ export interface TimelineRenderFeedItem extends Omit<TimelineFeedItem, 'title' | 'time' | 'variant'> {
19
+ title?: string;
20
+ time?: unknown;
21
+ variant?: string;
22
+ /** Marker colour, from the record's colour field. Vertical branch only. */
23
+ color?: string;
24
+ /** Sticky bucket header this item sits under. Vertical branch only. */
25
+ group?: string | null;
26
+ /** Status / priority chips beside the title. Vertical branch only. */
27
+ meta?: TimelineRenderMetaChip[];
28
+ /** The record's raw start value; drawn when `time` is absent. Vertical branch only. */
29
+ startDate?: unknown;
30
+ /** The record's raw end value; drawn as `start → end`. Vertical branch only. */
31
+ endDate?: unknown;
32
+ /** The record itself, handed back to the click handler. */
33
+ _data?: unknown;
34
+ }
35
+ /**
36
+ * `TimelineSchema` with every declared member kept and `items` widened to the
37
+ * handoff element.
38
+ *
39
+ * Spelled as a key-remapping mapped type and ⛔ not as `Omit`: `TimelineSchema`
40
+ * inherits `BaseSchema`'s string index signature, so `keyof` resolves to
41
+ * `string` and `Omit` collapses the whole interface into that signature,
42
+ * dropping every declared member. A homomorphic mapped type maps the declared
43
+ * members and the index signature separately, so only `items` leaves.
44
+ */
45
+ export type TimelineRenderSchema = {
46
+ [K in keyof TimelineSchema as K extends 'items' ? never : K]: TimelineSchema[K];
47
+ } & {
48
+ items?: Array<TimelineRenderFeedItem | TimelineGanttItem>;
49
+ };
50
+ //# sourceMappingURL=renderHandoff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderHandoff.d.ts","sourceRoot":"","sources":["../src/renderHandoff.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAE5F,oFAAoF;AACpF,MAAM,WAAW,sBAAsB;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,sBAAuB,SAAQ,IAAI,CAAC,gBAAgB,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;IAClG,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,sEAAsE;IACtE,IAAI,CAAC,EAAE,sBAAsB,EAAE,CAAC;IAChC,uFAAuF;IACvF,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gFAAgF;IAChF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2DAA2D;IAC3D,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,oBAAoB,GAAG;KAChC,CAAC,IAAI,MAAM,cAAc,IAAI,CAAC,SAAS,OAAO,GAAG,KAAK,GAAG,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC;CAChF,GAAG;IACF,KAAK,CAAC,EAAE,KAAK,CAAC,sBAAsB,GAAG,iBAAiB,CAAC,CAAC;CAC3D,CAAC"}
@@ -1,5 +1,5 @@
1
- import { TimelineSchema } from '@object-ui/types';
2
- import { TimelineTranslate } from './useTimelineTranslation';
1
+ import { TimelineRenderSchema } from './renderHandoff.js';
2
+ import { TimelineTranslate } from './useTimelineTranslation.js';
3
3
  /**
4
4
  * ObjectUI
5
5
  * Copyright (c) 2024-present ObjectStack Inc.
@@ -14,28 +14,42 @@ import * as React from 'react';
14
14
  */
15
15
  export declare const TIMELINE_SCALES: ReadonlySet<string>;
16
16
  /**
17
- * Resolve the axis scale for the gantt variant. The spec key is `scale`;
18
- * `timeScale` is this renderer's pre-spec dialect, kept for stored JSON —
19
- * before #2942 ONLY `timeScale` was read, so every spec-authored `scale`
20
- * (all six values) was silently ignored. An absent/unknown value keeps the
21
- * renderer's historical `month` default. The `vertical` / `horizontal`
22
- * variants are sequential event feeds with no time axis, so `scale` has
23
- * nothing to bucket there by construction.
17
+ * Resolve the axis scale for the gantt variant. `scale` is the ONLY axis key —
18
+ * it is `@objectstack/spec` `ui/TimelineConfig.json`'s spelling.
19
+ *
20
+ * The `timeScale` alias this used to fall back to (`scale ?? timeScale`) is
21
+ * RETIRED (objectui#6355, maintainer ruling 2026-08-27: immediate retirement,
22
+ * no phased window, while the project is at startup stage). It was this
23
+ * renderer's pre-spec dialect: before #2942 ONLY `timeScale` was read, so every
24
+ * spec-authored `scale` was silently ignored — this function was the fix, and
25
+ * dropping the alias half completes it.
26
+ *
27
+ * A document that still spells `timeScale` no longer reaches this function with
28
+ * an axis, and would fall to the `month` default below. That reversion is NOT
29
+ * left silent: `@object-ui/types` tombstones the key on both halves
30
+ * (`TimelineSchema.timeScale?: never` and the Zod twin's `z.never()`), so the
31
+ * retired spelling is refused at the authoring boundary rather than quietly
32
+ * re-bucketing the chart. The tombstone is why this deletion is safe; the two
33
+ * ship together.
34
+ *
35
+ * An absent/unknown value keeps the renderer's historical `month` default. The
36
+ * `vertical` / `horizontal` variants are sequential event feeds with no time
37
+ * axis, so `scale` has nothing to bucket there by construction.
24
38
  */
25
39
  export declare function resolveTimelineScale(schema: {
26
40
  scale?: unknown;
27
- timeScale?: unknown;
28
41
  }): string;
29
42
  /**
30
- * Gantt header labels for one scale across [minDate, maxDate]. Every spec
31
- * scale produces a non-empty header row — `hour` / `quarter` / `year` used to
32
- * fall through the month/week/day chain and return `[]`, blanking the axis
33
- * (#2942). Exported for the spec-parity test.
43
+ * Gantt header labels for one scale across [minDate, maxDate]: the labels of
44
+ * the one axis, `timelineAxis`, in order. Every spec scale produces a
45
+ * non-empty header row — `hour` / `quarter` / `year` used to fall through the
46
+ * month/week/day chain and return `[]`, blanking the axis (#2942). Exported
47
+ * for the spec-parity test.
34
48
  *
35
49
  * `locale` is threaded in rather than read here: this is a pure function, and
36
50
  * the session's locale lives behind a hook (#4513). The three `Intl` branches
37
- * below used to pass a literal `'en-US'`, so a fully Chinese timeline rendered
38
- * an English axis. The default is `'en'` — the same concrete last resort
51
+ * used to pass a literal `'en-US'`, so a fully Chinese timeline rendered an
52
+ * English axis. The default is `'en'` — the same concrete last resort
39
53
  * `useDisplayLocale()` falls back to, and byte-identical to the retired
40
54
  * `'en-US'` at all three sites — so the existing 3-argument call sites keep
41
55
  * producing exactly what they produced before.
@@ -43,15 +57,105 @@ export declare function resolveTimelineScale(schema: {
43
57
  * `t` is threaded on the same seam and for the same reason (#4520). The two are
44
58
  * different kinds of dependency and each covers what the other cannot: a locale
45
59
  * TAG formats a date, a TRANSLATION spells a word. The `week` and `quarter`
46
- * branches never touched `Intl`, so #4513 left them reading `Week 1` / `Q3
60
+ * units never touched `Intl`, so #4513 left them reading `Week 1` / `Q3
47
61
  * 2026` on an axis that had just become Chinese. Its default is the package's
48
62
  * own defaults table, which is what the channel serves with no `I18nProvider`
49
63
  * mounted, so 3- and 4-argument call sites keep producing byte-identical
50
64
  * English.
65
+ *
66
+ * ## Each unit starts on its unit boundary (objectui#11079)
67
+ *
68
+ * The first header is the unit that CONTAINS `minDate`, snapped to its start,
69
+ * and the walk ends on the unit that contains `maxDate`. The walk used to step
70
+ * from `minDate` itself, so a `month` axis from January 15th to April 10th
71
+ * stopped at March (April 15th is past the end), and one from January 31st
72
+ * skipped February (January 31st plus a month rolls into March). The labels
73
+ * of a range that starts on a unit boundary are unchanged.
74
+ *
75
+ * ## The empty/degenerate range — the second of #6750's three sites
76
+ *
77
+ * objectui#6750 asked the same empty-list question at all three stops on the
78
+ * gantt branch, so that fixing the one `throw` did not just move the crash two
79
+ * stations down. A DEGENERATE range (`minDate === maxDate`, which is what
80
+ * `emptyGanttDateRange` hands it) is not inverted — `min > max` is false when
81
+ * they are equal — so the axis is the one unit that contains that date, and
82
+ * every scale emits exactly one bucket. Measured on b76ca6764, min = max =
83
+ * '2026-03-15': hour `["Mar 15, 12 AM"]`, day `["Mar 15"]`, week
84
+ * `["Week 1"]`, month `["Mar 2026"]`, quarter `["Q1 2026"]`, year `["2026"]`.
85
+ *
86
+ * So the empty gantt gets a real one-column axis, not a header row with zero
87
+ * cells. That composition is what
88
+ * `./__tests__/timeline-gantt-empty-items.test.tsx` pins — separately from the
89
+ * other two sites, so a later change that fixes one and not the others goes
90
+ * red.
91
+ *
92
+ * ## The refusal is NOT dead code (objectui#6759)
93
+ *
94
+ * An unparseable or inverted range has no axis, so this returns NO headers.
95
+ * The gantt branch refuses such a range before it draws: the unparseable one
96
+ * by name in `findUnusableGanttDate`, and the inverted one when
97
+ * `timelineAxis` answers `undefined`, which is the same read this function
98
+ * makes. A `zero-column axis` is exactly what #6759's case 2 rendered its
99
+ * negative-width bar under, and the fix was to refuse above rather than to
100
+ * relax the refusal here.
101
+ *
102
+ * It stays because it is EXPORTED and called directly, including by
103
+ * `timeline-gantt-empty-items.test.tsx`'s pin 5a, which holds these exact
104
+ * inputs (`'2030-01-01'` / `'2026-03-15'`, and `''` / `''`) returning `[]`.
105
+ *
106
+ * ## The two ends are read as days (objectui#10866, slice 3)
107
+ *
108
+ * Both ends are read by `readGanttDate` inside `timelineAxis`, so a date-only
109
+ * end is local midnight of the day it names and the walk, which moves and
110
+ * prints with LOCAL setters and getters, starts on that day in every zone. A
111
+ * value with a time part keeps its instant, and the walk starts at the local
112
+ * start of the unit that contains it.
51
113
  */
52
114
  export declare function generateTimeScaleHeaders(scale: string, minDate: string, maxDate: string, locale?: string, t?: TimelineTranslate): string[];
53
- export declare const TimelineRenderer: ({ schema, className, ...props }: {
54
- schema: TimelineSchema;
115
+ /**
116
+ * `schema` is the renderer-internal handoff shape (`./renderHandoff`), not the
117
+ * authored `TimelineSchema`: every authored timeline is one, and so is the
118
+ * composed schema `ObjectTimeline` hands down, whose feed items carry the keys
119
+ * objectui#6356 ruled renderer-internal (`color`, `group`, `meta`,
120
+ * `startDate`, `endDate`, `_data`).
121
+ *
122
+ * ## The root's DOM channels (objectui#10841)
123
+ *
124
+ * Registered as `plugin-timeline:timeline`, this renderer is created by
125
+ * `SchemaRenderer`, which hands it, as React props, every node key its
126
+ * metadata strip leaves (`items`, `variant`, `dateFormat`, `scale`,
127
+ * `rowLabel`, `minDate`, `maxDate`, and so on) beside the attributes it mints
128
+ * for the DOM. The renderer reads the authored keys off `schema`, never off its
129
+ * props. Spread onto the root of every variant, that props copy serialized the
130
+ * schema into the DOM (`items="[object Object]"`, `variant="vertical"`,
131
+ * `dateformat="long"`) and set off React's unknown-prop warnings.
132
+ *
133
+ * The root now takes the converged route, the `container.tsx` /
134
+ * `header-bar.tsx` shape: `toDomProps(hostProps)` plus `style` by name.
135
+ * `toDomProps` executes the SDUI widget contract's DOM pass-through from
136
+ * `@object-ui/core` (`utils/dom-props.ts`, objectui#4425 phase 2), and that file
137
+ * owns the set and the reason for each member. It is what carries the
138
+ * `data-obj-id` / `data-obj-type` locator, the `data-testid` an authored
139
+ * `testId` promises (objectui#8268) and the resolved `aria-*` / `role`.
140
+ * `style` is the `BaseSchema` member an author writes for the DOM, forwarded
141
+ * by name as the converged renderers do. ⛔ No local list: a renderer-private
142
+ * allowlist is a second judge of the same contract, and it drifts from it.
143
+ *
144
+ * What the contract drops that used to land here:
145
+ *
146
+ * - every authored schema key;
147
+ * - `disabled`, the verdict `SchemaRenderer` forwards on a disabled node (the
148
+ * rail has no disabled state to apply it to);
149
+ * - `name` / `label`, declared `BaseSchema` members with no effect on an
150
+ * `ol` / `div`;
151
+ * - an authored `title`, which neither `BaseSchema` nor `TimelineSchema`
152
+ * declares. It is a global HTML attribute, so it used to give the root a
153
+ * native tooltip.
154
+ *
155
+ * `ObjectTimeline`, the other caller, passes `schema` alone.
156
+ */
157
+ export declare const TimelineRenderer: ({ schema, className, style, ...hostProps }: {
158
+ schema: TimelineRenderSchema;
55
159
  className?: string;
56
160
  [key: string]: any;
57
161
  }) => React.JSX.Element | null;
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAsBvD,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,0BAA0B,CAAC;AAGlC;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,MAAM,CAE9C,CAAC;AAEH;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,CAG7F;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,MAAa,EACrB,CAAC,GAAE,iBAA4C,GAC9C,MAAM,EAAE,CAyDV;AAsGD,eAAO,MAAM,gBAAgB,GAAI,iCAAiC;IAAE,MAAM,EAAE,cAAc,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,6BAsPjI,CAAC"}
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAsB5D,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,0BAA0B,CAAC;AAGlC;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,MAAM,CAE9C,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,CAGxE;AA2RD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,MAAa,EACrB,CAAC,GAAE,iBAA4C,GAC9C,MAAM,EAAE,CAGV;AA6jCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,eAAO,MAAM,gBAAgB,GAAI,4CAA4C;IAAE,MAAM,EAAE,oBAAoB,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,6BAmXlJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"useTimelineTranslation.d.ts","sourceRoot":"","sources":["../src/useTimelineTranslation.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAuBhE,CAAC;AAIF;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC;AAE1F;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,wBAAwB,EAAE,iBAIpC,CAAC;AAEJ;;;;GAIG;AACH,eAAO,MAAM,sBAAsB;4BA1ElC,CAAC;;;;;CA6ED,CAAC"}
1
+ {"version":3,"file":"useTimelineTranslation.d.ts","sourceRoot":"","sources":["../src/useTimelineTranslation.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA+EhE,CAAC;AAIF;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC;AAE1F;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,wBAAwB,EAAE,iBAIpC,CAAC;AAEJ;;;;GAIG;AACH,eAAO,MAAM,sBAAsB;4BAlIlC,CAAC;;;;;CAqID,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@object-ui/plugin-timeline",
3
- "version": "17.6.0",
3
+ "version": "17.7.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Timeline component plugin for Object UI",
@@ -27,12 +27,13 @@
27
27
  "@objectstack/spec": "^17.0.0",
28
28
  "class-variance-authority": "^0.7.1",
29
29
  "zod": "^4.4.3",
30
- "@object-ui/components": "17.6.0",
31
- "@object-ui/core": "17.6.0",
32
- "@object-ui/i18n": "17.6.0",
33
- "@object-ui/mobile": "17.6.0",
34
- "@object-ui/react": "17.6.0",
35
- "@object-ui/types": "17.6.0"
30
+ "@object-ui/components": "17.7.0",
31
+ "@object-ui/core": "17.7.0",
32
+ "@object-ui/i18n": "17.7.0",
33
+ "@object-ui/mobile": "17.7.0",
34
+ "@object-ui/permissions": "17.7.0",
35
+ "@object-ui/react": "17.7.0",
36
+ "@object-ui/types": "17.7.0"
36
37
  },
37
38
  "peerDependencies": {
38
39
  "react": "^18.0.0 || ^19.0.0",
@@ -45,7 +46,9 @@
45
46
  "typescript": "^6.0.3",
46
47
  "vite": "^8.2.1",
47
48
  "vite-plugin-dts": "^5.0.3",
48
- "@object-ui/data-objectstack": "17.6.0"
49
+ "@object-ui/data-objectstack": "17.7.0",
50
+ "@object-ui/sdui-parser": "17.7.0",
51
+ "@object-ui/test-support": "17.4.0"
49
52
  },
50
53
  "keywords": [
51
54
  "objectui",
@@ -72,8 +75,8 @@
72
75
  ],
73
76
  "scripts": {
74
77
  "build": "vite build",
75
- "test": "vitest run",
76
- "test:watch": "vitest",
78
+ "test": "vitest run --root ../.. packages/plugin-timeline/",
79
+ "test:watch": "vitest --root ../.. packages/plugin-timeline/",
77
80
  "type-check": "tsc --noEmit && tsc -p tsconfig.test.json",
78
81
  "lint": "eslint ."
79
82
  }