@evotecit/canopyx 0.1.3 → 0.2.1

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.
Files changed (85) hide show
  1. package/CanopyX.Html/Assets/canopyx-calendar-edit.js +114 -0
  2. package/CanopyX.Html/Assets/canopyx-calendar-ics.js +87 -0
  3. package/CanopyX.Html/Assets/canopyx-calendar-recurrence.js +36 -0
  4. package/CanopyX.Html/Assets/canopyx-calendar.css +279 -0
  5. package/CanopyX.Html/Assets/canopyx-calendar.js +307 -0
  6. package/CanopyX.Html/Assets/canopyx-cell-range.css +38 -0
  7. package/CanopyX.Html/Assets/canopyx-cell-range.js +141 -0
  8. package/CanopyX.Html/Assets/canopyx-column-groups.css +18 -0
  9. package/CanopyX.Html/Assets/canopyx-column-groups.js +51 -0
  10. package/CanopyX.Html/Assets/canopyx-data.js +14 -0
  11. package/CanopyX.Html/Assets/canopyx-detail-rows.css +18 -0
  12. package/CanopyX.Html/Assets/canopyx-detail-rows.js +51 -0
  13. package/CanopyX.Html/Assets/canopyx-editing.css +44 -0
  14. package/CanopyX.Html/Assets/canopyx-editing.js +134 -0
  15. package/CanopyX.Html/Assets/canopyx-enhance.js +126 -0
  16. package/CanopyX.Html/Assets/canopyx-export.js +18 -0
  17. package/CanopyX.Html/Assets/canopyx-facets.css +86 -0
  18. package/CanopyX.Html/Assets/canopyx-facets.js +65 -0
  19. package/CanopyX.Html/Assets/canopyx-filter-editor.css +15 -18
  20. package/CanopyX.Html/Assets/canopyx-filter-editor.js +23 -17
  21. package/CanopyX.Html/Assets/canopyx-format-editor.css +77 -0
  22. package/CanopyX.Html/Assets/canopyx-format-editor.js +30 -0
  23. package/CanopyX.Html/Assets/canopyx-formatting.css +40 -0
  24. package/CanopyX.Html/Assets/canopyx-formatting.js +101 -0
  25. package/CanopyX.Html/Assets/canopyx-grid-module.mjs +352 -246
  26. package/CanopyX.Html/Assets/canopyx-grid.css +139 -117
  27. package/CanopyX.Html/Assets/canopyx-grid.js +352 -246
  28. package/CanopyX.Html/Assets/canopyx-grouping.css +39 -0
  29. package/CanopyX.Html/Assets/canopyx-grouping.js +85 -0
  30. package/CanopyX.Html/Assets/canopyx-highlight.css +34 -0
  31. package/CanopyX.Html/Assets/canopyx-highlight.js +80 -0
  32. package/CanopyX.Html/Assets/canopyx-history.js +13 -0
  33. package/CanopyX.Html/Assets/canopyx-interactive.css +18 -6
  34. package/CanopyX.Html/Assets/canopyx-interactive.js +179 -100
  35. package/CanopyX.Html/Assets/canopyx-labels-de.js +304 -0
  36. package/CanopyX.Html/Assets/canopyx-labels-es.js +304 -0
  37. package/CanopyX.Html/Assets/canopyx-labels-fr.js +529 -0
  38. package/CanopyX.Html/Assets/canopyx-labels-it.js +529 -0
  39. package/CanopyX.Html/Assets/canopyx-labels-pl.js +304 -0
  40. package/CanopyX.Html/Assets/canopyx-layouts.css +48 -0
  41. package/CanopyX.Html/Assets/canopyx-layouts.js +39 -0
  42. package/CanopyX.Html/Assets/canopyx-link.css +19 -0
  43. package/CanopyX.Html/Assets/canopyx-link.js +38 -0
  44. package/CanopyX.Html/Assets/canopyx-links.js +14 -0
  45. package/CanopyX.Html/Assets/canopyx-live.css +24 -0
  46. package/CanopyX.Html/Assets/canopyx-live.js +88 -0
  47. package/CanopyX.Html/Assets/canopyx-module.mjs +180 -100
  48. package/CanopyX.Html/Assets/canopyx-pager.css +10 -0
  49. package/CanopyX.Html/Assets/canopyx-pager.js +14 -0
  50. package/CanopyX.Html/Assets/canopyx-record-panel.css +111 -0
  51. package/CanopyX.Html/Assets/canopyx-record-panel.js +178 -0
  52. package/CanopyX.Html/Assets/canopyx-reporting-module.mjs +406 -342
  53. package/CanopyX.Html/Assets/canopyx-reporting.css +140 -135
  54. package/CanopyX.Html/Assets/canopyx-reporting.js +406 -342
  55. package/CanopyX.Html/Assets/canopyx-search.js +32 -0
  56. package/CanopyX.Html/Assets/canopyx-timeline.css +80 -0
  57. package/CanopyX.Html/Assets/canopyx-timeline.js +88 -0
  58. package/CanopyX.Html/Assets/canopyx-tree-tools.css +103 -0
  59. package/CanopyX.Html/Assets/canopyx-tree-tools.js +92 -0
  60. package/CanopyX.Html/Assets/canopyx.css +17 -5
  61. package/CanopyX.Html/Assets/canopyx.js +175 -96
  62. package/JavaScript/calendar.d.ts +362 -0
  63. package/JavaScript/cell-ranges.d.ts +76 -0
  64. package/JavaScript/column-groups.d.ts +32 -0
  65. package/JavaScript/editing.d.ts +257 -0
  66. package/JavaScript/enhance.d.ts +202 -0
  67. package/JavaScript/facets.d.ts +58 -0
  68. package/JavaScript/formatting.d.ts +88 -0
  69. package/JavaScript/grid.d.ts +409 -56
  70. package/JavaScript/hosts.d.ts +177 -2
  71. package/JavaScript/index.d.ts +53 -4
  72. package/JavaScript/live.d.ts +115 -0
  73. package/JavaScript/locales/de.mjs +304 -0
  74. package/JavaScript/locales/es.mjs +304 -0
  75. package/JavaScript/locales/fr.d.ts +6 -0
  76. package/JavaScript/locales/fr.mjs +527 -0
  77. package/JavaScript/locales/it.d.ts +6 -0
  78. package/JavaScript/locales/it.mjs +527 -0
  79. package/JavaScript/locales/pl.mjs +304 -0
  80. package/JavaScript/plugins.d.ts +113 -0
  81. package/JavaScript/protocol.d.ts +139 -6
  82. package/JavaScript/records.d.ts +136 -0
  83. package/README.md +61 -9
  84. package/README.nuget.md +1 -1
  85. package/package.json +99 -3
@@ -0,0 +1,32 @@
1
+ (function(global){"use strict";const installed=new WeakSet();const part={version:"521eebd6e1bbbd35",install(context){if(installed.has(context.SEARCH_IMPL))return;const{SEARCH_IMPL,checkDocument,badIndex,isCount,isIdentifier,recentCache,packBytes,shardKey,foldText,trimSeparators,rankHits,validateSearchHit,PACK_CACHE,PACK_CACHE_BYTES,SHARD_CACHE,ENTRY_CACHE,ENTRY_BATCH,SEARCH_CANDIDATES}=context;function resolveShards(shards,keys,word){const bases=keys.filter((key)=>!/\.\d+$/.test(key));
2
+ const parts=(selected)=>selected.flatMap((key)=>[key].concat(keys.filter((part)=>part.startsWith(key+"."))
3
+ .sort((a,b)=>Number(a.slice(a.lastIndexOf(".")+ 1))- Number(b.slice(b.lastIndexOf(".")+ 1)))));for(let length=Math.min(2,word.length);length<=word.length;length++){const key=shardKey(word.slice(0,length));if(Object.hasOwn(shards,key))return parts([key]);const deeper=bases.filter((k)=>k.length>key.length&&k.startsWith(key));if(!deeper.length)return[];if(length===word.length)return parts(deeper)}
4
+ return[]}
5
+ function checkShard(doc,key,count,entryCount){checkDocument(doc,"searchShard");if(doc.key!==key)throw badIndex("shard key");if(!Array.isArray(doc.words)||!Array.isArray(doc.postings)||doc.words.length!==doc.postings.length)throw badIndex("shard");let total=0;doc.postings.forEach((list,i)=>{if(typeof doc.words[i]!=="string"||!Array.isArray(list)||!isCount(list[0]))throw badIndex("shard");let last=list[0];for(let j=1;j<list.length;j++){if(!Number.isInteger(list[j])||!list[j])throw badIndex("shard");last +=Math.abs(list[j]);total +=list[j]<0?-list[j]- 1:0}
6
+ total +=list.length;if(last>=entryCount)throw badIndex("shard")});if(total!==count)throw badIndex("shard posting count");return doc}
7
+ function mergePostings(lists){const out=[];let ascending=true;for(const list of lists){let value=0;list.forEach((step,i)=>{for(let n=i&&step<0?-step:1;n>0;n--){value=i?value +(step<0?1:step):step;if(out.length&&value<=out[out.length-1])ascending=false;out.push(value)}})}
8
+ if(ascending)return out;out.sort((a,b)=>a-b);return out.filter((value,i)=>!i||value!==out[i-1])}
9
+ function intersectPostings(a,b){let j=0;return a.filter((value)=>{while(j<b.length&&b[j]<value)j++;return b[j]===value})}
10
+ function labelToken(folded){let hash=2166136261;for(let i=0;i<folded.length;i++){hash=Math.imul(hash^folded.charCodeAt(i),16777619)}
11
+ return "\u0000" +("0000000" +(hash>>>0).toString(16)).slice(-8)}
12
+ function entryReference(value){return value===undefined||value===null||isIdentifier(value)}
13
+ function entryFile(doc,first,count){checkDocument(doc,"searchEntries");if(doc.first!==first||!Array.isArray(doc.stem)||!Array.isArray(doc.entries)||doc.entries.length!==count)throw badIndex("entry file");const stem=new Map(doc.stem.map((item)=>(Array.isArray(item)?[item[0],item.slice(1)]:[])));const records=new Map();const raw=(n)=>{const item=n>=first&&n<first+count?doc.entries[n-first]:stem.get(n);if(!Array.isArray(item)||item.length<5||item.length>8||!Number.isInteger(item[0])||item[0]<-1||item[0]>=n||
14
+ !isCount(item[1])||typeof item[2]!=="string"||!isCount(item[3])||typeof item[4]!=="string"||
15
+ (item[5]!=null&&!isCount(item[5]))||!entryReference(item[6])||!(item[7]===undefined||isIdentifier(item[7]))){throw badIndex("entry "+n)}
16
+ return item};return(n)=>{const pending=[];for(let k=n;k>=0&&!records.has(k);k=raw(k)[0])pending.push(k);while(pending.length){const number=pending.pop();const item=raw(number);const parent=item[0]<0?null:records.get(item[0]);const base=parent?parent.id:"";if(item[1]+ item[3]>base.length)throw badIndex("entry "+number);records.set(number,{parent,id:base.slice(0,item[1])+ item[2]+ base.slice(base.length-item[3]),label:item[4],kind:item[5]==null?undefined:item[5],ref:item[6]||null,at:item[7]||null})}
17
+ return records.get(n)}}
18
+ function entryHit(record,kinds){const path=[];for(let r=record;r;r=r.parent)path.unshift(r.id);const hit={path,label:record.label};if(record.kind!==undefined){if(record.kind>=kinds.length)throw badIndex("entry kind");hit.kind=kinds[record.kind]}
19
+ const parent=record.parent;if(parent)hit.context=parent.parent?parent.parent.label+" / "+parent.label:parent.label;validateSearchHit(hit);return hit}
20
+ function entryFileOf(starts,n){let low=0;let high=starts.length-1;while(low<high){const mid=(low+high+1)>>1;if(starts[mid]<=n)low=mid;else high=mid-1}
21
+ return low}
22
+ function sidecarSearch(load,manifest,hints){const index=async()=>(await manifest()).search;const loadPack=recentCache(PACK_CACHE,async(number)=>{const doc=checkDocument(await load("q/"+number),"pack");if(!Array.isArray(doc.pages)||doc.pages.some(text=>typeof text!=="string"))throw badIndex("pack");return doc.pages},PACK_CACHE_BYTES,packBytes);const sortedKeys=new WeakMap();const packed=async(pack,slot)=>{const text=(await loadPack(pack))[slot];if(typeof text!=="string")throw badIndex("pack");return JSON.parse(text)};const loadIndexDoc=async(search,kind,name)=>{if(!search.entryPacks)return load(kind==="e"?"e/"+name:"s/k-"+name);if(kind==="e"){const pack=entryFileOf(search.entryPacks,name);return packed(pack,name-search.entryPacks[pack])}
23
+ let keys=sortedKeys.get(search);if(!keys)sortedKeys.set(search,keys=Object.keys(search.shards).sort());let pack=0;while(pack+1<search.shardPacks.length&&search.shardPacks[pack+1]<=name)pack++;return packed(search.entryPacks.length+pack,keys.indexOf(name)- keys.indexOf(search.shardPacks[pack]))};const loadShard=recentCache(SHARD_CACHE,async(key)=>{const search=await index();return checkShard(await loadIndexDoc(search,"s",key),key,search.shards[key],search.entryCount)});const loadEntries=recentCache(ENTRY_CACHE,async(file)=>{const search=await index();const first=search.entryFiles[file];const end=file+1<search.entryFiles.length?search.entryFiles[file+1]:search.entryCount;return entryFile(await loadIndexDoc(search,"e",file),first,end-first)});async function postingsOf(search,keys,word){const lists=[];for(const shard of await Promise.all(resolveShards(search.shards,keys,word).map(loadShard))){shard.words.forEach((indexed,i)=>indexed.startsWith(word)&&lists.push(shard.postings[i]))}
24
+ return mergePostings(lists)}
25
+ async function run(query,queryWords,limit,sequence){const search=await index();if(!search){return{hits:[],total:0,truncated:false}}
26
+ const keyWords=queryWords.filter((word,i)=>queryWords.indexOf(word)===i&&
27
+ !queryWords.some((other)=>other.length>word.length&&other.startsWith(word)));const keys=Object.keys(search.shards);const folded=trimSeparators(foldText(query));const[exact,lists]=await Promise.all([postingsOf(search,keys,labelToken(folded)),Promise.all(keyWords.map((word)=>postingsOf(search,keys,word)))]);const candidates=lists.sort((a,b)=>a.length-b.length).reduce(intersectPostings);const order=exact.concat(candidates);const wanted=limit*SEARCH_CANDIDATES;const taken=new Set();const hits=[];const records=new Map();let next=0;while(next<order.length&&hits.length<limit){const files=[];let end=next;for(;end<order.length&&hits.length+end-next<wanted;end++){const file=entryFileOf(search.entryFiles,order[end]);if(files.indexOf(file)<0){if(files.length>=ENTRY_BATCH&&hits.length+end-next>=limit)break;files.push(file)}}
28
+ const loaded=await Promise.all(files.map(loadEntries));for(;next<end;next++){const number=order[next];if(taken.has(number))continue;const record=loaded[files.indexOf(entryFileOf(search.entryFiles,number))](number);if(next>=exact.length||trimSeparators(foldText(record.label))===folded){taken.add(number);const hit=entryHit(record,search.kinds);records.set(hit,record);hits.push(hit)}}}
29
+ const ranked=rankHits(hits,query,limit);ranked.total=candidates.length;ranked.truncated=candidates.length>ranked.hits.length;if(sequence===latest){hints.clear();ranked.hits.forEach((hit)=>{for(let r=records.get(hit);r;r=r.parent)hints.set(r.id,r)})}
30
+ return ranked}
31
+ let latest=0;return(query,queryWords,limit)=>run(query,queryWords,limit,++latest).catch((err)=>{loadShard.clear();loadEntries.clear();loadPack.clear();throw err})}
32
+ SEARCH_IMPL.create=sidecarSearch;installed.add(context.SEARCH_IMPL)}};(global.CanopyXParts||=[]).push(["search",part])})(typeof window!=="undefined"?window:globalThis);
@@ -0,0 +1,80 @@
1
+ /* Resource timeline: the resource tree at the start,the time header and lanes after it,sharing rows. */
2
+ .cx-tl{--cx-tl-side-w:var(--cx-tl-side,280px);display:grid;grid-template-columns:var(--cx-tl-side-w) minmax(0,1fr);height:100%;min-height:0;}
3
+ .cx-tl.cx-tl-solo{grid-template-columns:minmax(0,1fr);}
4
+ .cx-tl-side{display:flex;flex-direction:column;min-width:0;min-height:0;border-inline-end:var(--cx-size-1px) solid var(--cx-line);}
5
+ .cx-tl-side > .cx-tl-tree.cx-host{flex:1 1 auto;height:auto;min-height:0;border:0;border-radius:0;--cx-head-h:var(--cx-tl-head-h,57px);}
6
+ .cx-tl-tree.cx-host > .cx-grid{overflow-y:hidden;overflow-x:scroll;border:0;border-radius:0;}
7
+ .cx-tl-tree .cx-head{display:flex;flex-direction:column;justify-content:flex-end;box-sizing:border-box;height:var(--cx-tl-head-h,57px);}
8
+ .cx-tl-tree .cx-tl-agg{justify-content:flex-end;font-variant-numeric:tabular-nums;color:var(--cx-text-2);}
9
+ .cx-tl-main{position:relative;min-width:0;min-height:0;overflow:scroll;overscroll-behavior:contain;}
10
+ .cx-tl-head{position:sticky;top:0;z-index:7;height:var(--cx-tl-head-h,57px);background:var(--cx-head-bg);border-bottom:var(--cx-size-1px) solid var(--cx-line);}
11
+ .cx-tl-hrow{position:relative;height:var(--cx-size-28px);}
12
+ .cx-tl-upper{border-bottom:var(--cx-size-1px) solid var(--cx-line);}
13
+ .cx-tl-hcell{position:absolute;top:0;height:100%;display:flex;align-items:center;padding:0 var(--cx-size-6px);border-inline-start:var(--cx-size-1px) solid var(--cx-line);font-size:var(--cx-size-12px);color:var(--cx-text-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-variant-numeric:tabular-nums;}
14
+ .cx-tl-hcell.cx-tl-hupper{overflow:visible;font-size:var(--cx-size-13px);font-weight:600;color:var(--cx-text);}
15
+ .cx-tl-hupper > .cx-tl-hlabel{position:sticky;inset-inline-start:var(--cx-size-6px);max-width:100%;overflow:hidden;text-overflow:ellipsis;}
16
+ .cx-tl-hcell > .cx-tl-hlabel{min-width:0;overflow:hidden;text-overflow:ellipsis;}
17
+ .cx-tl-hcell.cx-tl-weekend{background:color-mix(in srgb,var(--cx-text) 5%,transparent);}
18
+ .cx-tl-range-labels{position:relative;height:var(--cx-size-20px);border-top:var(--cx-size-1px) solid var(--cx-line);}
19
+ .cx-tl-head:not(.cx-tl-has-ranges) > .cx-tl-range-labels{display:none;}
20
+ .cx-tl-range-label{position:absolute;top:var(--cx-size-2px);height:var(--cx-size-16px);padding:0 var(--cx-size-6px);border-radius:var(--cx-radius-sm);background:color-mix(in srgb,var(--cx-tone-info) 14%,var(--cx-surface));font-size:var(--cx-size-11d5px);line-height:var(--cx-size-16px);color:var(--cx-text-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
21
+ .cx-tl-canvas{position:relative;}
22
+ .cx-tl-layer{position:absolute;inset-inline-start:0;top:0;width:100%;pointer-events:none;}
23
+ .cx-tl-weekend-col{position:absolute;top:0;bottom:0;background:color-mix(in srgb,var(--cx-text) 3.5%,transparent);}
24
+ .cx-tl-range{position:absolute;top:0;bottom:0;background:color-mix(in srgb,var(--cx-bg-tone) 9%,transparent);box-shadow:inset var(--cx-size-2px) 0 0 color-mix(in srgb,var(--cx-bg-tone) 50%,transparent);}
25
+ :where(.cx-cal-rtl) .cx-tl-range{box-shadow:inset calc(-1 * var(--cx-size-2px)) 0 0 color-mix(in srgb,var(--cx-bg-tone) 50%,transparent);}
26
+ .cx-tl-now{position:absolute;top:0;bottom:0;width:var(--cx-size-2px);margin-inline-start:calc(-1 * var(--cx-size-1px));background:var(--cx-tone-danger);z-index:1;}
27
+ .cx-tl-lane{position:absolute;inset-inline-start:0;inset-inline-end:0;border-bottom:var(--cx-size-1px) solid color-mix(in srgb,var(--cx-line) 70%,transparent);}
28
+ .cx-tl-lane.cx-tl-group{background:color-mix(in srgb,var(--cx-text) 2.5%,transparent);}
29
+ .cx-tl-cell{position:absolute;top:0;bottom:0;pointer-events:none;outline:none;}
30
+ .cx-tl-cell:focus-visible{outline:var(--cx-size-2px) solid var(--cx-accent);outline-offset:calc(-1 * var(--cx-size-2px));z-index:5;}
31
+ .cx-tl-cell[aria-selected="true"]{background:var(--cx-selected-bg);}
32
+ .cx-tl-lane .cx-cal-ev-lane{position:absolute;z-index:2;pointer-events:auto;padding:0 var(--cx-size-6px);font-size:var(--cx-size-12px);line-height:1.2;}
33
+ .cx-tl-lane .cx-cal-ev-lane > .cx-cal-ev-sub{display:none;}
34
+ .cx-tl-lane .cx-cal-ev-lane.cx-tl-thin{font-size:var(--cx-size-11px);padding:0 var(--cx-size-4px);}
35
+ .cx-tl-lane .cx-cal-ev-lane.cx-tl-narrow{padding:0;justify-content:center;}
36
+ .cx-tl-lane .cx-cal-ev-lane.cx-tl-narrow > *{display:none;}
37
+ .cx-tl-lane .cx-cal-ev-lane.cx-tl-tiny{background:var(--cx-ev);box-shadow:none;}
38
+ .cx-tl-lane .cx-cal-ev-lane.cx-tl-point{width:auto!important;max-width:var(--cx-size-180px);padding-inline-start:var(--cx-size-14px);margin-inline-start:calc(-1 * var(--cx-size-6px));background:transparent;box-shadow:none;overflow:visible;}
39
+ .cx-tl-lane .cx-cal-ev-lane.cx-tl-point::before{content:"";position:absolute;inset-inline-start:var(--cx-size-2px);top:50%;width:var(--cx-size-8px);height:var(--cx-size-8px);margin-top:calc(-1 * var(--cx-size-4px));transform:rotate(45deg);background:var(--cx-ev);border-radius:var(--cx-size-1px);}
40
+ .cx-tl-lane .cx-cal-ev-lane.cx-tl-point > *{display:none;}
41
+ .cx-tl-lane .cx-cal-ev-lane.cx-tl-point > .cx-cal-ev-title{display:block;overflow:hidden;text-overflow:ellipsis;}
42
+ .cx-tl-lane .cx-cal-ev-lane.cx-tl-point.cx-tl-bare{width:var(--cx-size-14px)!important;padding-inline-start:0;}
43
+ .cx-tl-lane .cx-cal-ev-lane.cx-tl-point.cx-tl-bare > .cx-cal-ev-title{display:none;}
44
+ .cx-tl-shade{position:absolute;top:0;bottom:0;pointer-events:none;overflow:hidden;overflow:clip;}
45
+ .cx-tl-shade > span{position:sticky;inset-inline-start:0;display:block;width:max-content;max-width:100%;box-sizing:border-box;padding:var(--cx-size-2px) var(--cx-size-6px);font-size:var(--cx-size-11px);color:var(--cx-text-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
46
+ .cx-tl-shade.cx-tl-off{background:color-mix(in srgb,var(--cx-text) 4.5%,transparent);}
47
+ :is(.cx-tl-shade,.cx-tl-range).cx-tl-unavailable{background:repeating-linear-gradient(135deg,color-mix(in srgb,var(--cx-text) 9%,transparent) 0 var(--cx-size-6px),transparent var(--cx-size-6px) var(--cx-size-12px));box-shadow:none;}
48
+ .cx-tl-shade.cx-tl-bg{background:color-mix(in srgb,var(--cx-bg-tone) 12%,transparent);box-shadow:inset var(--cx-size-2px) 0 0 color-mix(in srgb,var(--cx-bg-tone) 55%,transparent);}
49
+ :where(.cx-cal-rtl) .cx-tl-shade.cx-tl-bg{box-shadow:inset calc(-1 * var(--cx-size-2px)) 0 0 color-mix(in srgb,var(--cx-bg-tone) 55%,transparent);}
50
+ .cx-tl-heat{position:absolute;z-index:2;background:var(--cx-surface);top:var(--cx-size-5px);bottom:var(--cx-size-5px);display:grid;place-items:center;border-radius:var(--cx-radius-sm);font-size:var(--cx-size-11d5px);font-weight:600;color:var(--cx-text);font-variant-numeric:tabular-nums;overflow:hidden;isolation:isolate;}
51
+ .cx-tl-heat::before{content:"";position:absolute;inset:0 var(--cx-size-1px);z-index:-1;border-radius:inherit;background:var(--cx-bg-tone,var(--cx-accent));opacity:calc(.12 + var(--cx-heat,0) * .38);}
52
+ .cx-tl-heat[data-cx-tone]::before{opacity:calc(.28 + var(--cx-heat,0) * .42);}
53
+ .cx-tl-lane > .cx-tl-ghost{top:var(--cx-size-3px);bottom:var(--cx-size-3px);padding:0;overflow:visible;}
54
+ .cx-tl-ghost > .cx-tl-ghost-label{position:absolute;inset-inline-start:calc(100% + var(--cx-size-6px));top:50%;transform:translateY(-50%);padding:var(--cx-size-2px) var(--cx-size-6px);border:var(--cx-size-1px) solid currentColor;border-radius:var(--cx-radius-sm);background:var(--cx-surface);white-space:nowrap;box-shadow:var(--cx-shadow-1,0 1px 3px rgb(0 0 0 / 18%));}
55
+ .cx-tl-print{display:none;}
56
+ .cx-cal-phone .cx-tl{--cx-tl-side-w:176px;}
57
+ .cx-cal-phone .cx-tl-tree .cx-hidden-fields{display:none;}
58
+ @media (forced-colors:active){
59
+ .cx-tl-heat{forced-color-adjust:none;border:var(--cx-size-1px) solid CanvasText;background:Canvas;color:CanvasText;}
60
+ .cx-tl-heat::before{display:none;}
61
+ .cx-tl-heat[data-cx-tone]{border-width:var(--cx-size-2px);font-weight:700;}
62
+ .cx-tl-now{forced-color-adjust:none;background:Highlight;}
63
+ .cx-tl-cell[aria-selected="true"]{forced-color-adjust:none;background:Highlight;}
64
+ .cx-tl-lane .cx-cal-ev-lane.cx-tl-point::before,.cx-tl-lane .cx-cal-ev-lane.cx-tl-tiny{forced-color-adjust:none;background:CanvasText;}
65
+ }
66
+ @media print{
67
+ .cx-tl > :is(.cx-tl-side,.cx-tl-main){display:none!important;}
68
+ .cx-tl{display:block;height:auto;}
69
+ .cx-tl-print{display:block;font-size:10px;}
70
+ .cx-tl-print-row{display:grid;grid-template-columns:24% 1fr;align-items:stretch;min-height:18px;border-bottom:var(--cx-size-1px) solid var(--cx-line);break-inside:avoid;}
71
+ .cx-tl-print-head{font-weight:700;border-bottom-width:var(--cx-size-2px);}
72
+ .cx-tl-print-group{background:color-mix(in srgb,var(--cx-text) 4%,transparent);font-weight:600;}
73
+ .cx-tl-print-name{padding:var(--cx-size-2px) var(--cx-size-4px);overflow:hidden;white-space:nowrap;text-overflow:ellipsis;}
74
+ .cx-tl-print-lane{position:relative;min-height:18px;}
75
+ .cx-tl-print-unit,.cx-tl-print-heat{position:absolute;top:0;bottom:0;padding:0 var(--cx-size-2px);border-inline-start:var(--cx-size-1px) solid var(--cx-line);overflow:hidden;white-space:nowrap;}
76
+ .cx-tl-print-bar.cx-tl-print-tiny{background:var(--cx-ev,var(--cx-accent));box-shadow:none;}
77
+ .cx-tl-print-bar{position:absolute;top:var(--cx-size-2px);bottom:var(--cx-size-2px);padding:0 var(--cx-size-2px);border-radius:var(--cx-size-2px);background:color-mix(in srgb,var(--cx-ev,var(--cx-accent)) 22%,#fff);box-shadow:inset var(--cx-size-2px) 0 0 var(--cx-ev,var(--cx-accent));overflow:hidden;white-space:nowrap;-webkit-print-color-adjust:exact;print-color-adjust:exact;}
78
+ :where(.cx-cal-rtl) .cx-tl-print-bar{box-shadow:inset calc(-1 * var(--cx-size-2px)) 0 0 var(--cx-ev,var(--cx-accent));}
79
+ }
80
+ @media (forced-colors:active){.cx-tl-ghost > .cx-tl-ghost-label{background:Canvas;color:CanvasText;border-color:CanvasText;}}
@@ -0,0 +1,88 @@
1
+ (function(global){"use strict";const installed=new WeakSet();const part={version:"3f04ba99401e9ebd",requires:["calendar"],install(context){if(installed.has(context.DataGrid.prototype))return;const{DataGrid,TreeGrid,h,setText,fill,numberFormat}=context;const{CAL_DAY,CAL_HOUR,CAL_MINUTE,calAddMonths,calCount,calDayNumber,calDayParts,calDow,calMonthStart,calWeekStart}=DataGrid.prototype.calKit;const TL_ZOOMS={hour:{width:56,unit:"hour"},day:{width:44,unit:"day"},week:{width:92,unit:"week"},month:{width:112,unit:"month"},quarter:{width:150,unit:"quarter"}};function tlSpan(zoom,date,firstDay){if(zoom==="hour")return{firstDay:date,lastDay:date};if(zoom==="day"){const month=calMonthStart(date);return{firstDay:month,lastDay:calAddMonths(month,1)- 1}}
2
+ if(zoom==="week"){const parts=calDayParts(date),quarter=calDayNumber(parts.y,Math.floor((parts.m-1)/ 3) * 3 + 1, 1);
3
+ return{firstDay:calWeekStart(quarter,firstDay),lastDay:calWeekStart(calAddMonths(quarter,3)- 1,firstDay)+ 6}}
4
+ const parts=calDayParts(date);if(zoom==="month")return{firstDay:calDayNumber(parts.y,1,1),lastDay:calDayNumber(parts.y+1,1,1)- 1};return{firstDay:calDayNumber(parts.y,1,1),lastDay:calDayNumber(parts.y+3,1,1)- 1}}
5
+ function tlCustomSpan(span,date,firstDay){if(span.unit==="day")return{firstDay:date,lastDay:date+span.count-1};if(span.unit==="week"){const first=calWeekStart(date,firstDay);return{firstDay:first,lastDay:first+7*span.count-1}}
6
+ const month=calMonthStart(date);return{firstDay:month,lastDay:calAddMonths(month,span.count)- 1}}
7
+ function tlCustomStep(span,date,direction){return span.unit==="month"?calAddMonths(date,span.count*direction):date +(span.unit==="week"?7:1)*span.count*direction}
8
+ function tlStep(zoom,date,direction){if(zoom==="hour")return date+direction;if(zoom==="day")return calAddMonths(date,direction);if(zoom==="week")return calAddMonths(date,3*direction);return calAddMonths(date,(zoom==="month"?12:36)*direction)}
9
+ function tlUnits(zoom,span,zone,firstDay){const units=[],width=TL_ZOOMS[zoom].width;const push=(first,last,start,end)=>units.push({first,last,start,end,x:units.length*width});if(zoom==="hour"){for(let at=zone.start(span.firstDay),end=zone.start(span.lastDay+1);at<end;at +=CAL_HOUR){const day=zone.day(at);push(day,day,at,Math.min(at+CAL_HOUR,end))}}else if(zoom==="day"){for(let day=span.firstDay;day<=span.lastDay;day++)push(day,day,zone.start(day),zone.start(day+1))}else if(zoom==="week"){for(let day=calWeekStart(span.firstDay,firstDay);day<=span.lastDay;day +=7)push(day,day+6,zone.start(day),zone.start(day+7))}else{const months=zoom==="month"?1:3;for(let day=span.firstDay;day<=span.lastDay;day=calAddMonths(day,months)){const next=calAddMonths(day,months);push(day,next-1,zone.start(day),zone.start(next))}}
10
+ return units}
11
+ function tlAxis(zoom,span,zone,firstDay){const units=tlUnits(zoom,span,zone,firstDay),width=TL_ZOOMS[zoom].width,total=units.length*width;const unitOf=time=>{let low=0,high=units.length-1;while(low<high){const mid=(low+high+1)>>1;if(units[mid].start<=time)low=mid;else high=mid-1}
12
+ return low};return{zoom,units,width,total,from:units[0].start,to:units[units.length-1].end,x(time){if(time<=this.from)return 0;if(time>=this.to)return total;const unit=units[unitOf(time)];return unit.x +(time-unit.start)/ (unit.end - unit.start) * width;
13
+ },time(x){const index=Math.max(0,Math.min(units.length-1,Math.floor(x / width))), unit = units[index];
14
+ return unit.start+Math.max(0,Math.min(1,(x-unit.x)/ width)) * (unit.end - unit.start);
15
+ },unitOf}}
16
+ function tlHeader(view,axis){const fmt=view.calFmt,upper=[],lower=[],zoom=axis.zoom;const group=(key,text,label,unit)=>{const last=upper[upper.length-1];if(last&&last.key===key)last.width +=axis.width;else upper.push({key,x:unit.x,width:axis.width,text,label})};for(const unit of axis.units){let text,label;if(zoom==="hour"){const minutes=view.calZone.parts(unit.start).minutes;text=fmt.hour(minutes);label=fmt.longDay(unit.first)+ " "+fmt.clock(minutes);group(unit.first,fmt.longDay(unit.first),fmt.longDay(unit.first),unit)}
17
+ else if(zoom==="day"){text=fmt.dayNumber(unit.first);label=fmt.longDay(unit.first);group(calMonthStart(unit.first),fmt.monthTitle(unit.first),fmt.monthTitle(unit.first),unit)}
18
+ else if(zoom==="week"){text=fmt.shortDay(unit.first);label=fmt.dayRange(unit.first,unit.last);group(calMonthStart(unit.first),fmt.monthTitle(unit.first),fmt.monthTitle(unit.first),unit)}
19
+ else if(zoom==="month"){text=fmt.monthShort(unit.first);label=fmt.monthTitle(unit.first);group(calDayParts(unit.first).y,fmt.year(unit.first),fmt.year(unit.first),unit)}
20
+ else{text=fmt.range({month:"short"},unit.first,unit.last);label=fmt.monthRange(unit.first,unit.last);group(calDayParts(unit.first).y,fmt.year(unit.first),fmt.year(unit.first),unit)}
21
+ const dow=calDow(unit.first),off=view.cal.working?!view.cal.working.days.has(dow):dow===0||dow===6;lower.push({x:unit.x,width:axis.width,text,label,weekend:zoom==="day"&&off,unit})}
22
+ return{upper,lower}}
23
+ Object.assign(DataGrid.prototype,{startTimeline(){if(this.tl)return;const resources=this.cal.resources;this.tl={names:new Map(),parent:new Map(),children:new Map(),order:[],learned:new Set(),stats:null,heat:new Map()};this.tlSolo=!resources;if(this.tlSolo){this.tlInline=true;return}
24
+ const inline=!resources.view.source||resources.view.source.kind==="inline";if(inline)this.tlLearnNodes(resources.view.roots||[],null);this.tlInline=inline},tlLearnNodes(nodes,parent){const stack=nodes.map(node=>[node,parent]).reverse();while(stack.length){const[node,owner]=stack.pop();if(!node||typeof node.id!=="string"||this.tl.learned.has(node.id))continue;this.tl.learned.add(node.id);this.tl.names.set(node.id,node.label??node.id);this.tl.parent.set(node.id,owner);this.tl.order.push(node.id);if(owner!==null){if(!this.tl.children.has(owner))this.tl.children.set(owner,[]);this.tl.children.get(owner).push(node.id)}
25
+ if(Array.isArray(node.children))for(let i=node.children.length-1;i>=0;i--)stack.push([node.children[i],node.id])}},calResourceName(id){return this.tl?.names.get(id)??id},calResourceColumns(){if(!this.tl||!this.tlInline)return null;const leaves=this.tl.order.filter(id=>!this.tl.children.has(id));if(!leaves.length||leaves.length>24)return null;return leaves.map(id=>({id,label:this.calResourceName(id),group:this.tl.parent.get(id)==null?null:this.calResourceName(this.tl.parent.get(id))}))},calHoursFor(resource,dow){const list=this.cal.availability;if(!list.length)return undefined;let own=resource==null?[]:list.filter(item=>item.resource===resource);for(let parent=this.tl?.parent.get(resource);!own.length&&parent!=null;parent=this.tl.parent.get(parent))own=list.filter(item=>item.resource===parent);const entries=own.length?own:list.filter(item=>item.resource==null);return entries.length?entries.filter(item=>item.days.has(dow)):undefined},calResourceStep(resource,sign){if(this.tlSolo)return resource;const rows=this.tlTree?this.tlTree.rows.filter(row=>!row.status&&!this.tl.children.has(row.key)).map(row=>row.key):this.tl.order.filter(id=>!this.tl.children.has(id));const at=rows.indexOf(resource);return rows[Math.max(0,Math.min(rows.length-1,(at<0?0:at)+ sign))]??resource},calResourceWindow(){if(this.calView!=="timeline"||this.tlSolo||this.view.source.kind==="inline"&&!this.opts.source)return null;this.tlEnsure();if(!this.tlTree?.rows?.length)return null;const range=this.tlMain.clientHeight?this.tlVisibleRows(40):{first:0,last:Math.min(this.tlTree.rows.length-1,80)},ids=new Set();for(let i=range.first;i<=range.last&&ids.size<1000;i++){const row=this.tlTree.rows[i];if(!row||row.status)continue;const stack=[row.key];while(stack.length&&ids.size<1000){const id=stack.pop();if(ids.has(id))continue;ids.add(id);const children=this.tl.children.get(id)||[];for(let at=children.length-1;at>=0;at--)stack.push(children[at])}}
26
+ const window=[...ids];return window.length?window:null},tlCheckWindow(){if(this.view.source.kind==="inline"&&!this.opts.source)return;clearTimeout(this.tlWindowTimer);this.tlWindowTimer=setTimeout(()=>{if(this.destroyed||this.calView!=="timeline")return;const wanted=this.calResourceWindow(),loaded=JSON.parse(this.calWindowKey||"null"),known=new Set(loaded||[]);if(wanted&&(!loaded||wanted.some(id=>!known.has(id))))this.calReload({keep:true})},250)},calResourcesReady(){if(this.calView!=="timeline"||this.view.source.kind==="inline"&&!this.opts.source)return null;this.tlEnsure();return this.tlTree.ready?.catch(()=>{})},calTimelineRange(date){return this.cal.span?tlCustomSpan(this.cal.span,date,this.cal.firstDay):tlSpan(this.calZoom,date,this.cal.firstDay)},calTimelineStep(date,direction){return this.cal.span?tlCustomStep(this.cal.span,date,direction):tlStep(this.calZoom,date,direction)},calTimelineTitle(){const range=this.calRange,fmt=this.calFmt;if(this.cal.span)return range.firstDay===range.lastDay?fmt.longDay(range.firstDay):fmt.dayRange(range.firstDay,range.lastDay);if(this.calZoom==="hour")return fmt.longDay(range.firstDay);if(this.calZoom==="day")return fmt.monthTitle(range.firstDay);if(this.calZoom==="week")return fmt.monthRange(range.firstDay,range.lastDay);return range.lastDay-range.firstDay>400?fmt.year(range.firstDay)+ " – "+fmt.year(range.lastDay):fmt.year(range.firstDay)},calTimelineHasNow(){const now=Date.now();return this.tlAxis?now>=this.tlAxis.from&&now<this.tlAxis.to:false},tlEnsure(){if(this.tlRoot)return;const resources=this.cal.resources,root=this.tlRoot=h("div","cx-tl" +(this.tlSolo?" cx-tl-solo":"")),side=h("div","cx-tl-side"),host=this.tlTreeHost=h("div","cx-tl-tree");const main=this.tlMain=h("div","cx-tl-main"),head=this.tlHead=h("div","cx-tl-head"),canvas=this.tlCanvas=h("div","cx-tl-canvas");head.setAttribute("aria-hidden","true");const upper=this.tlUpper=h("div","cx-tl-hrow cx-tl-upper"),lower=this.tlLower=h("div","cx-tl-hrow cx-tl-lower");head.append(upper,lower);canvas.setAttribute("role","grid");canvas.setAttribute("aria-labelledby",this.calTitle.id);canvas.setAttribute("aria-readonly",String(!this.cal.editable));if(this.tlSolo){root.append(main);main.append(head,canvas);const signal=this.lifetime.signal;this.tlTree={rows:[],tops:[0],rowH:this.rowH||34,version:0,destroyed:false,ready:Promise.resolve(),grid:side,scheduleRender:()=>this.tlScheduleLanes(),setState:()=>Promise.resolve(),destroy(){this.destroyed=true}};main.addEventListener("scroll",()=>this.tlScheduleLanes(),{passive:true,signal});return}
27
+ root.style.setProperty("--cx-tl-side",resources.width+"px");main.append(head,canvas);side.appendChild(host);root.append(side,main);host.setAttribute("data-cx-theme",this.host.getAttribute("data-cx-theme")||"auto");const aggregates=resources.aggregates,renderers={};for(const[column,kind]of Object.entries(aggregates))renderers[column]=(node,element)=>{setText(element,this.tlAggregateText(node.id,kind));element.classList.add("cx-tl-agg");return true};const view={...resources.view,rowHeight:resources.view.rowHeight||this.rowH,labels:{...this.view.labels,...resources.view.labels}};const tree=this.tlTree=new TreeGrid(host,{view,toolbar:false,renderers,labels:this.opts.labels});tree.emit=(name,detail)=>{if(!tree.destroyed)host.dispatchEvent(new CustomEvent("canopyx:"+name,{detail}))};const render=tree.render.bind(tree);tree.render=()=>{const result=render();if(!this.tlRows||this.tlRows!==tree.rows.length+":"+tree.version){this.tlLearnLoaded()}this.tlPaintLanes();this.tlCheckWindow();return result};const signal=this.lifetime.signal;let syncing=false;main.addEventListener("scroll",()=>{if(!syncing&&tree.grid.scrollTop!==main.scrollTop){syncing=true;tree.grid.scrollTop=main.scrollTop;syncing=false}
28
+ this.tlScheduleLanes();this.tlCheckWindow()},{passive:true,signal});tree.grid.addEventListener("scroll",()=>{if(!syncing&&Math.abs(tree.grid.scrollTop-main.scrollTop)>1){syncing=true;main.scrollTop=tree.grid.scrollTop;syncing=false}},{passive:true,signal});host.addEventListener("wheel",event=>{if(!event.deltaY||event.ctrlKey)return;event.preventDefault();main.scrollTop +=event.deltaY*(event.deltaMode===1?tree.rowH:event.deltaMode===2?main.clientHeight:1)},{passive:false,signal});host.addEventListener("canopyx:toggle",event=>{const node=event.detail.node;if(event.detail.expanded)this.calCollapsed.delete(node.id);else this.calCollapsed.add(node.id);this.stateChanged()},{signal});host.addEventListener("canopyx:select",event=>{const node=event.detail.node;if(!node){this.clearCalendarSelection();return}
29
+ const zone=this.calZone,range=this.calRange,ids=new Set([node.id,...this.tlDescendants(node.id)]);this.calSelection={first:range.firstDay,last:range.lastDay,from:zone.start(range.firstDay),to:zone.start(range.lastDay+1),resource:node.id};const events=this.calEvents.filter(item=>!item.background&&ids.has(item.resource));this.calAnnounce(fill(this.calLabels.calendarSelected,{range:this.calResourceName(node.id)}));this.calEmitLink("select",events,this.calResourceName(node.id),this.calSelection)},{signal});signal.addEventListener("abort",()=>{clearTimeout(this.tlWindowTimer);tree.destroy()},{once:true});tree.ready.then(()=>{if(!this.destroyed){this.calApplyCollapsed();this.tlPaintLanes()}},error=>this.emit("error",{error}))},tlLearnLoaded(){const tree=this.tlTree;this.tlRows=tree.rows.length+":"+tree.version;for(const row of tree.rows)if(!row.status&&row.key!=null&&!this.tl.learned.has(row.key)){this.tl.learned.add(row.key);this.tl.names.set(row.key,row.h.label??row.key);this.tl.order.push(row.key);const parent=row.parent?.key??null;this.tl.parent.set(row.key,parent);if(parent!==null){if(!this.tl.children.has(parent))this.tl.children.set(parent,[]);this.tl.children.get(parent).push(row.key)}
30
+ if(row.h.hasChildren&&!this.tl.children.has(row.key))this.tl.children.set(row.key,[])}},tlDescendants(id){const out=[],stack=[...(this.tl.children.get(id)||[])];while(stack.length&&out.length<100000){const next=stack.pop();out.push(next);stack.push(...(this.tl.children.get(next)||[]))}
31
+ return out},calApplyCollapsed(){const tree=this.tlTree;if(!tree||this.destroyed)return;const expanded=[];if(this.tlInline){const walk=(id,path)=>{if(!this.tl.children.has(id)||this.calCollapsed.has(id))return;expanded.push(path);for(const child of this.tl.children.get(id))walk(child,path.concat(child))};for(const id of this.tl.order)if(this.tl.parent.get(id)===null)walk(id,[id]);tree.setState({expanded}).catch?.(()=>{})}},calPaintTimeline(){this.tlEnsure();const span=this.calRange,axis=this.tlAxis=tlAxis(this.calZoom,span,this.calZone,this.cal.firstDay);this.tlIndex=this.tlIndexEvents();this.tl.heat.clear();if(this.tlRoot.parentNode!==this.calBody)this.calBody.replaceChildren(this.tlRoot);this.tlCanvas.style.width=axis.total+"px";this.tlHead.style.width=axis.total+"px";const header=tlHeader(this,axis),paint=(row,cells,cls)=>{row.replaceChildren(...cells.map(cell=>{const element=h("div",cls +(cell.weekend?" cx-tl-weekend":"")),text=h("span","cx-tl-hlabel");element.style.insetInlineStart=cell.x+"px";element.style.width=cell.width+"px";setText(text,cell.text);element.appendChild(text);element.title=cell.label;return element}))};paint(this.tlUpper,header.upper,"cx-tl-hcell cx-tl-hupper");paint(this.tlLower,header.lower,"cx-tl-hcell");this.tlHeader=header;this.calGrid=this.tlCanvas;if(this.tlScrolledFor!==this.calZoom+":"+span.firstDay){this.tlScrolledFor=this.calZoom+":"+span.firstDay;const now=Date.now(),target=now>=axis.from&&now<axis.to?axis.x(now)- this.tlMain.clientWidth / 3 : 0;
32
+ this.tlScrollTo(Math.max(0,target))}
33
+ this.tlTree.version++;this.tlTree.scheduleRender();this.tlPaintLanes()},tlScrollX(){return Math.abs(this.tlMain.scrollLeft)},tlScrollTo(x){this.tlMain.scrollLeft=this.calRtl?-x:x},calTimelineScroll(){return this.tlMain?{timeline:true,top:this.tlMain.scrollTop,left:this.tlScrollX(),view:"timeline",date:this.calDate,zoom:this.calZoom}:null},calRestoreTimelineScroll(state){if(state.zoom!==this.calZoom||state.date!==this.calDate)return false;this.tlMain.scrollTop=state.top;this.tlScrollTo(state.left);return true}});const TL_MARGIN=480,TL_STACK=4,TL_MIN_BAR=8,TL_SOLID_BAR=16;Object.assign(DataGrid.prototype,{tlIndexEvents(){const byResource=new Map(),backgrounds=new Map();for(const event of this.calEvents){const span=this.calDisplaySpan(event);event.tlStart=span.start;event.tlEnd=span.end}
34
+ if(this.tlSolo)return this.tlIndexSolo(backgrounds);for(const event of this.calEvents){const target=event.background?backgrounds:byResource,key=event.resource??"";if(!target.has(key))target.set(key,[]);target.get(key).push(event)}
35
+ for(const list of byResource.values()){list.sort((a,b)=>a.tlStart-b.tlStart||b.tlEnd-a.tlEnd);const ends=[];for(const event of list){let lane=ends.findIndex(end=>end<=event.tlStart);if(lane<0){lane=ends.length;ends.push(0)}
36
+ ends[lane]=Math.max(event.tlEnd,event.tlStart+1);event.tlLane=lane}
37
+ list.lanes=Math.max(1,ends.length)}
38
+ this.tl.stats=null;return{byResource,backgrounds}},tlIndexSolo(backgrounds){const byResource=new Map(),ends=[],tree=this.tlTree,events=this.calEvents.filter(event=>!event.background).sort((a,b)=>a.tlStart-b.tlStart||b.tlEnd-a.tlEnd);for(const event of this.calEvents)if(event.background){if(!backgrounds.has(""))backgrounds.set("",[]);backgrounds.get("").push(event)}
39
+ for(const event of events){let lane=ends.findIndex(end=>end<=event.tlStart);if(lane<0){lane=ends.length;ends.push(0)}
40
+ ends[lane]=Math.max(event.tlEnd,event.tlStart+1);const key="lane-"+lane;event.tlLane=0;event.tlRow=key;if(!byResource.has(key)){const list=[];list.lanes=1;byResource.set(key,list)}
41
+ byResource.get(key).push(event)}
42
+ const count=Math.max(1,ends.length);tree.rows=Array.from({length:count},(_,index)=>({key:"lane-"+index,level:1,status:null,h:{label:String(index+1)}}));tree.tops=Array.from({length:count+1},(_,index)=>index*tree.rowH);for(const row of tree.rows)this.tl.names.set(row.key,row.h.label);tree.version++;this.tl.stats=null;return{byResource,backgrounds}},tlVisibleRows(margin){const tree=this.tlTree,tops=tree.tops,count=tree.rows.length,main=this.tlMain;if(!count)return{first:0,last:-1};const top=main.scrollTop,bottom=top+main.clientHeight,find=y=>{let low=0,high=count-1;while(low<high){const mid=(low+high+1)>>1;if(tops[mid]<=y)low=mid;else high=mid-1}return low};return{first:Math.max(0,find(top)- margin),last:Math.min(count-1,find(bottom)+ margin)}},tlScheduleLanes(){if(this.tlFrame)return;this.tlFrame=requestAnimationFrame(()=>{this.tlFrame=0;if(!this.destroyed)this.tlPaintLanes()})},tlPaintLanes(){const tree=this.tlTree,axis=this.tlAxis,canvas=this.tlCanvas;if(!tree||!axis||this.calView!=="timeline"||!canvas.isConnected)return;const rows=tree.rows,tops=tree.tops,total=tops[rows.length]||0,main=this.tlMain;canvas.style.height=total+"px";canvas.setAttribute("aria-rowcount",String(rows.length));const visible=this.tlVisibleRows(3),bucket=Math.floor(this.tlScrollX()/ TL_MARGIN), left = (bucket - 1) * TL_MARGIN, right = (bucket + 2) * TL_MARGIN + main.clientWidth;
43
+ const lanes=this.tlLanes||=new Map(),keep=new Set(),signature=[this.calEpoch,this.calVersion,this.calSourceVersion||0,axis.zoom,axis.from,bucket,this.linkHighlight?.size||0,this.calSelection?.resource??""].join("|");for(let i=visible.first;i<=visible.last;i++){const row=rows[i],key=row.status?"status:"+i:row.key;keep.add(key);let lane=lanes.get(key);if(!lane){lane=h("div","cx-tl-lane");lane.setAttribute("role","row");lanes.set(key,lane)}
44
+ const height=(tops[i+1]??total)- tops[i];lane.style.top=tops[i]+ "px";lane.style.height=height+"px";lane.setAttribute("aria-rowindex",String(i+1));if(lane._sig!==signature+"|"+height||lane._row!==row){lane._sig=signature+"|"+height;lane._row=row;this.tlPaintLane(lane,row,height,left,right)}
45
+ if(lane.parentNode!==canvas)canvas.appendChild(lane)}
46
+ for(const[key,lane]of lanes)if(!keep.has(key)){if(lane.contains(document.activeElement))continue;lane.remove();lanes.delete(key)}
47
+ this.tlPaintCanvas(left,right,total);this.calMarkSelection();if(this.calRoot.contains(document.activeElement)&&!this.calBody.contains(document.activeElement))return;if(!canvas.querySelector('[tabindex="0"]'))this.calRestoreFocus(false)},tlPaintLane(lane,row,height,left,right){lane.replaceChildren();if(row.status){lane.removeAttribute("aria-label");return}
48
+ const axis=this.tlAxis,id=row.key,group=this.tl.children.has(id),events=group?[]:this.tlIndex.byResource.get(id)||[];lane.classList.toggle("cx-tl-group",group);lane.dataset.cxResource=id;const name=this.calResourceName(id),count=group?this.tlStats(id).count:events.length;lane.setAttribute("aria-label",fill(this.calLabels.calendarLane,{resource:name,events:calCount(this,this.calLabels.calendarEvents,count)}));const cells=[];axis.units.forEach((unit,index)=>{if(unit.x+axis.width<=left||unit.x>right)return;const cell=h("div","cx-tl-cell");cell.setAttribute("role","gridcell");cell.tabIndex=-1;cell.dataset.cxDay=String(unit.first);cell.dataset.cxUnit=String(index);cell.dataset.cxResource=id;if(!this.calInValid({firstDay:unit.first,lastDay:unit.last})){cell.classList.add("cx-cal-invalid");cell.setAttribute("aria-disabled","true")}
49
+ cell.style.insetInlineStart=unit.x+"px";cell.style.width=axis.width+"px";cell.setAttribute("aria-label",name+", "+this.tlUnitLabel(unit));cells.push(cell);lane.appendChild(cell)});if(group){this.tlPaintHeat(lane,id,left,right);return}
50
+ this.tlPaintShade(lane,id,left,right);const stack=Math.min(TL_STACK,events.lanes||1),inner=height-6,bar=Math.max(6,inner / stack - (stack > 1 ? 2 : 0));
51
+ const firstVisible=cells.length?Number(cells[0].dataset.cxUnit):0;const nextInRow=new Map(),after=new Map();for(let i=events.length-1;i>=0;i--){const row=Math.min(events[i].tlLane,stack-1);nextInRow.set(events[i],after.get(row));after.set(row,events[i].tlStart)}
52
+ for(const event of events){if(event.tlEnd<axis.from||event.tlStart>=axis.to)continue;const x1=axis.x(event.tlStart),x2=event.tlEnd>event.tlStart?axis.x(event.tlEnd):x1;if(x2<left||x1>right)continue;const span=x2-x1,point=event.marker||span<1;const element=this.calEventElement(event,"lane"),slot=Math.min(event.tlLane,stack-1),room=nextInRow.get(event)===undefined?Infinity:axis.x(nextInRow.get(event))- x1-1,width=point?0:Math.max(Math.min(span,2),Math.min(Math.max(TL_MIN_BAR,span),room));const unit=Math.max(firstVisible,axis.unitOf(event.tlStart)),cell=cells.find(item=>Number(item.dataset.cxUnit)===unit)||cells[0];const offset=cell?Number.parseFloat(cell.style.insetInlineStart):0;element.style.insetInlineStart=(x1-offset)+ "px";element.style.width=width+"px";element.style.top=(3+slot*(inner / stack)) + "px"; element.style.height = bar + "px";
53
+ if(bar<16)element.classList.add("cx-tl-thin");if(point)element.classList.add("cx-tl-point");else if(span<TL_SOLID_BAR){element.classList.add("cx-tl-tiny");element.title=this.calEventName(event)}
54
+ if(point&&(axis.zoom!=="hour"||!event.marker)){element.classList.add("cx-tl-bare");element.title=this.calEventName(event)}
55
+ if(width<40)element.classList.add("cx-tl-narrow");if(event.tlStart<axis.from)element.classList.add("cx-cal-cont-start");if(event.tlEnd>axis.to)element.classList.add("cx-cal-cont-end");(cell||lane).appendChild(element)}},tlUnitLabel(unit){const lower=this.tlHeader?.lower.find(cell=>cell.unit===unit);return lower?lower.label:this.calFmt.longDay(unit.first)},tlPaintShade(lane,id,left,right){const axis=this.tlAxis,add=(start,end,cls,label,tone)=>{const x1=axis.x(start),x2=axis.x(end);if(x2<=x1||x2<left||x1>right)return;const block=h("div","cx-tl-shade "+cls);block.setAttribute("aria-hidden","true");block.style.insetInlineStart=x1+"px";block.style.width=(x2-x1)+ "px";if(tone)block.style.setProperty("--cx-bg-tone","var(--cx-tone-"+tone+",var(--cx-tone-info))");if(label&&x2-x1>60){const text=h("span");setText(text,label);block.appendChild(text)}
56
+ lane.appendChild(block)};if(axis.zoom==="hour")for(let day=axis.units[0].first;day<=axis.units[axis.units.length-1].last;day++){const hours=this.calHoursFor(id,calDow(day))??(this.cal.working?(this.cal.working.days.has(calDow(day))?[this.cal.working]:[]):null);if(hours){let at=0;for(const span of hours.slice().sort((a,b)=>a.start-b.start)){add(this.calZone.instant(day,at),this.calZone.instant(day,span.start),"cx-tl-off");at=Math.max(at,span.end)}add(this.calZone.instant(day,at),this.calZone.instant(day,1440),"cx-tl-off")}}
57
+ for(const range of this.calRanges)if(range.resource===id)add(range.start,range.end,range.kind==="unavailable"?"cx-tl-unavailable":"cx-tl-bg",range.label,range.kind==="unavailable"?null:range.tone);for(const event of this.tlIndex.backgrounds.get(id)||[])add(event.tlStart,event.tlEnd,"cx-tl-bg",event.title,event.tone||"info")},tlPaintCanvas(left,right,total){const axis=this.tlAxis,layer=this.tlLayer||=h("div","cx-tl-layer");layer.setAttribute("aria-hidden","true");layer.style.height=total+"px";const blocks=[];for(const cell of this.tlHeader.lower)if(cell.weekend&&cell.x+cell.width>=left&&cell.x<=right){const block=h("div","cx-tl-weekend-col");block.style.insetInlineStart=cell.x+"px";block.style.width=cell.width+"px";blocks.push(block)}
58
+ const global=[...this.calRanges.filter(range=>range.resource==null),...(this.tlIndex.backgrounds.get("")||[]).map(event=>({start:event.tlStart,end:event.tlEnd,label:event.title,tone:event.tone||"info",kind:"background"}))];for(const range of global){const x1=axis.x(range.start),x2=axis.x(range.end);if(x2<=x1||x2<left||x1>right)continue;const block=h("div","cx-tl-range" +(range.kind==="unavailable"?" cx-tl-unavailable":""));block.style.insetInlineStart=x1+"px";block.style.width=(x2-x1)+ "px";if(range.kind!=="unavailable")block.style.setProperty("--cx-bg-tone","var(--cx-tone-"+range.tone+",var(--cx-tone-info))");block.title=range.label;blocks.push(block)}
59
+ const now=Date.now();if(this.cal.now&&now>=axis.from&&now<axis.to){const line=h("div","cx-tl-now");line.style.insetInlineStart=axis.x(now)+ "px";line.title=this.calLabels.calendarNow+" "+this.calFmt.time(now);blocks.push(line)}
60
+ layer.replaceChildren(...blocks);if(layer.parentNode!==this.tlCanvas)this.tlCanvas.prepend(layer);const labels=this.tlRangeLabels||=h("div","cx-tl-range-labels"),named=global.filter(range=>axis.x(range.end)- axis.x(range.start)>50);labels.replaceChildren(...named.map(range=>{const label=h("span","cx-tl-range-label");label.style.insetInlineStart=axis.x(range.start)+ "px";label.style.width=(axis.x(range.end)- axis.x(range.start))+ "px";setText(label,range.label);label.title=range.label;return label}));if(labels.parentNode!==this.tlHead)this.tlHead.appendChild(labels);if(this.tlHead.classList.contains("cx-tl-has-ranges")!==named.length>0){this.tlHead.classList.toggle("cx-tl-has-ranges",named.length>0);this.tlRoot.style.setProperty("--cx-tl-head-h",named.length?"78px":"57px");this.tlTree.scheduleRender()}},calTickTimeline(){if(this.calView==="timeline")this.tlPaintCanvas(this.tlScrollX()- TL_MARGIN,this.tlScrollX()+ this.tlMain.clientWidth+TL_MARGIN,this.tlTree.tops[this.tlTree.rows.length]||0)},tlPaintHeat(lane,id,left,right){const axis=this.tlAxis,heat=this.tlHeat(id),thresholds=this.cal.capacity?.thresholds||[],most=Math.max(1,...heat);heat.forEach((value,index)=>{const unit=axis.units[index];if(!value||unit.x+axis.width<left||unit.x>right)return;const block=h("div","cx-tl-heat"),tone=thresholds.reduce((found,item)=>value>=item.at?item.tone:found,null);block.style.insetInlineStart=unit.x+"px";block.style.width=axis.width+"px";block.style.setProperty("--cx-heat",String(Math.min(1,value / most)));
61
+ if(tone){block.dataset.cxTone=tone;block.style.setProperty("--cx-bg-tone","var(--cx-tone-"+tone+",var(--cx-accent))")}
62
+ block.setAttribute("aria-hidden","true");block.title=fill(this.calLabels.calendarCapacityAt,{count:numberFormat(this.lang).format(value)});if(axis.width>=28)setText(block,numberFormat(this.lang).format(value));lane.appendChild(block)});lane.setAttribute("aria-label",lane.getAttribute("aria-label")+ ", "+this.calLabels.calendarCapacity+" "+fill(this.calLabels.calendarCapacityAt,{count:numberFormat(this.lang).format(Math.max(0,...heat))}))},tlHeat(id){if(this.tl.heat.has(id))return this.tl.heat.get(id);const axis=this.tlAxis,units=axis.units,points=[],out=new Array(units.length).fill(0);for(const leaf of[id,...this.tlDescendants(id)])for(const event of this.tlIndex.byResource.get(leaf)||[]){if(event.tlEnd<=axis.from||event.tlStart>=axis.to)continue;points.push([Math.max(event.tlStart,axis.from),1],[Math.max(event.tlEnd,event.tlStart+1),-1])}
63
+ points.sort((a,b)=>a[0]- b[0]||a[1]- b[1]);let level=0,unit=0;for(let i=0;i<points.length;i++){level +=points[i][1];const from=points[i][0],to=i+1<points.length?points[i+1][0]:from;if(to<=from||level<=0)continue;while(unit<units.length-1&&units[unit].end<=from)unit++;for(let at=unit;at<units.length&&units[at].start<to;at++)out[at]=Math.max(out[at],level)}
64
+ this.tl.heat.set(id,out);return out},tlStats(id){const cache=this.tl.stats||=new Map();if(cache.has(id))return cache.get(id);const axis=this.tlAxis,stats={count:0,busy:0,overlaps:0};let end=-Infinity,lastEnd=-Infinity,lastIndex=-1;const overlapped=new Set(),list=(this.tlIndex.byResource.get(id)||[]).filter(event=>event.tlEnd>axis.from&&event.tlStart<axis.to);list.forEach((event,index)=>{const from=Math.max(event.tlStart,axis.from),to=Math.min(event.tlEnd,axis.to);if(to>end){stats.busy +=to-Math.max(from,end);end=to}
65
+ if(event.tlStart<lastEnd){overlapped.add(index);overlapped.add(lastIndex)}
66
+ if(event.tlEnd>lastEnd){lastEnd=event.tlEnd;lastIndex=index}});stats.count=list.length;stats.overlaps=overlapped.size;for(const child of this.tl.children.get(id)||[]){const inner=this.tlStats(child);stats.count +=inner.count;stats.busy +=inner.busy;stats.overlaps +=inner.overlaps}
67
+ cache.set(id,stats);return stats},tlAggregateText(id,kind){if(!this.tlIndex)return "";const stats=this.tlStats(id),format=numberFormat(this.lang);if(kind==="busy")return format.format(Math.round(stats.busy / CAL_HOUR * 10) / 10) + " h";
68
+ return format.format(kind==="overlap"?stats.overlaps:stats.count)}});Object.assign(DataGrid.prototype,{calKeyTimeline(event,target,eventElement){const key=event.key,tree=this.tlTree,axis=this.tlAxis;const cell=eventElement?eventElement.closest(".cx-tl-cell"):target.closest(".cx-tl-cell");if(!cell||!tree||!axis)return;const unit=Number(cell.dataset.cxUnit),resource=cell.dataset.cxResource,rowIndex=tree.rows.findIndex(row=>row.key===resource);if(eventElement){if(key==="Escape"){event.preventDefault();this.tlFocusCell(rowIndex,unit);return}
69
+ if(key==="ArrowLeft"||key==="ArrowRight"){event.preventDefault();const list=[...this.tlLanes.get(resource)?.querySelectorAll(".cx-cal-ev")||[]].sort((a,b)=>a._calEvent.start-b._calEvent.start);const next=list[list.indexOf(eventElement)+(key==="ArrowLeft"?-1:1)];if(next){eventElement.tabIndex=-1;next.tabIndex=0;next.focus()}}
70
+ return}
71
+ if(key==="ArrowLeft"||key==="ArrowRight"){event.preventDefault();const next=unit +(key==="ArrowLeft"?-1:1);if(next<0||next>=axis.units.length){this.calendarStep(next<0?-1:1).then(()=>this.tlFocusCell(rowIndex,next<0?this.tlAxis.units.length-1:0));return}
72
+ this.tlFocusCell(rowIndex,next)}else if(key==="ArrowUp"||key==="ArrowDown"){event.preventDefault();let next=rowIndex +(key==="ArrowUp"?-1:1);while(tree.rows[next]?.status)next +=key==="ArrowUp"?-1:1;if(next>=0&&next<tree.rows.length)this.tlFocusCell(next,unit)}else if(key==="Home"||key==="End"){event.preventDefault();this.tlFocusCell(rowIndex,key==="Home"?0:axis.units.length-1)}
73
+ else if(key==="PageUp"||key==="PageDown"){event.preventDefault();this.calendarStep(key==="PageUp"?-1:1).then(()=>this.tlFocusCell(rowIndex,unit))}
74
+ else if(key===" "||key==="Enter"){event.preventDefault();const inside=cell.querySelector(".cx-cal-ev");if(key==="Enter"&&inside){cell.tabIndex=-1;inside.tabIndex=0;inside.focus()}
75
+ else this.tlSelectUnit(axis.units[unit],resource)}},tlFocusCell(rowIndex,unitIndex){const tree=this.tlTree,axis=this.tlAxis,main=this.tlMain,row=tree.rows[rowIndex],unit=axis.units[unitIndex];if(!row||!unit)return;if(!this.calInValid({firstDay:unit.first,lastDay:unit.last}))return;const top=tree.tops[rowIndex],bottom=tree.tops[rowIndex+1]??top+tree.rowH,head=this.tlHead.offsetHeight;if(top<main.scrollTop)main.scrollTop=top;else if(bottom>main.scrollTop+main.clientHeight-head)main.scrollTop=bottom-main.clientHeight+head;const scrolled=this.tlScrollX();if(unit.x<scrolled)this.tlScrollTo(unit.x);else if(unit.x+axis.width>scrolled+main.clientWidth)this.tlScrollTo(unit.x+axis.width-main.clientWidth);tree.grid.scrollTop=main.scrollTop;this.calFocus={day:unit.first,minutes:null,event:null,resource:row.key,unit:unitIndex};this.tlPaintLanes();this.calRestoreFocus(true)},tlSelectUnit(unit,resource){if(this.tlSolo)resource=null;if(this.calZoom==="hour"){const minutes=this.calZone.parts(unit.start).minutes;this.calSelectSlots(unit.first,minutes,minutes+60,resource)}else this.calSelectDays(unit.first,unit.last,resource)},calTimelineClick(event){const lane=event.target.closest(".cx-tl-lane");if(!lane?.dataset.cxResource||!this.tlAxis)return false;const box=this.tlCanvas.getBoundingClientRect(),x=this.calRtl?box.right-event.clientX:event.clientX-box.left,axis=this.tlAxis;const index=Math.max(0,Math.min(axis.units.length-1,Math.floor(x / axis.width)));
76
+ const unit=axis.units[index];if(!this.calInValid({firstDay:unit.first,lastDay:unit.last}))return false;this.calFocus={day:axis.units[index].first,minutes:null,event:null,resource:lane.dataset.cxResource,unit:index};this.tlSelectUnit(axis.units[index],lane.dataset.cxResource);this.calRestoreFocus(true);return true},calTimelinePoint(x,y){const axis=this.tlAxis,tree=this.tlTree,box=this.tlCanvas.getBoundingClientRect();if(!axis||!tree)return null;const time=axis.time(Math.max(0,Math.min(axis.total,this.calRtl?box.right-x:x-box.left))),offset=y-box.top,tops=tree.tops;let low=0,high=tree.rows.length-1;while(low<high){const mid=(low+high+1)>>1;if(tops[mid]<=offset)low=mid;else high=mid-1}
77
+ const index=low;const row=tree.rows[index],resource=row&&!row.status&&!this.tlSolo&&!this.tl.children.has(row.key)?row.key:null;const parts=this.calZone.parts(time);return{day:parts.day,minutes:parts.minutes +(time%CAL_MINUTE)/ CAL_MINUTE, resource, time, row: row?.key ?? null };
78
+ },tlSnap(){const snap=this.cal.editable?.snap??this.cal.slotMinutes;return this.calZoom==="hour"?snap:this.calZoom==="day"?Math.max(60,snap):1440},calTimelineGhost(drag){const proposal=drag.proposal,axis=this.tlAxis,lane=this.tlLanes?.get(this.tlSolo?drag.event.tlRow??proposal.row:proposal.resource??drag.event.resource??drag.event.tlRow);const ghost=this.calGhost||=h("div","cx-cal-ghost");ghost.className="cx-cal-ghost cx-tl-ghost" +(drag.problem?" cx-cal-conflict":"");ghost.setAttribute("aria-hidden","true");const first=proposal.allDay?Math.floor(proposal.start / CAL_DAY) : this.calZone.day(proposal.start), last = Math.max(proposal.start, proposal.end - 1);
79
+ const label=(drag.drop?drag.event.title+" · ":"")+ this.calTimeText({...drag.event,start:proposal.start,end:proposal.end,sd:first,ed:proposal.allDay?Math.floor(last / CAL_DAY) : this.calZone.day(last) });
80
+ const text=ghost.querySelector(".cx-tl-ghost-label")||ghost.appendChild(h("span","cx-tl-ghost-label"));if(ghost.firstChild!==text)ghost.replaceChildren(text);setText(text,drag.problem?label+" · "+drag.problem:label);ghost.title=text.textContent;if(!lane){ghost.remove();return}
81
+ const span=this.calDisplaySpan(proposal),x1=axis.x(span.start),x2=Math.max(x1+3,axis.x(span.end));ghost.style.insetInlineStart=x1+"px";ghost.style.width=(x2-x1)+ "px";if(ghost.parentNode!==lane)lane.appendChild(ghost)}});const TL_PRINT_ROWS=400,TL_PRINT_LANE=760,TL_PRINT_CHAR=5.6;Object.assign(DataGrid.prototype,{tlPrint(on){this.tlPrintView?.remove();this.tlPrintView=null;if(!on||this.calView!=="timeline"||!this.tlTree||!this.tlAxis)return;const axis=this.tlAxis,tree=this.tlTree,view=this.tlPrintView=h("div","cx-tl-print"),share=time=>(axis.x(time)/ axis.total * 100) + "%";
82
+ view.setAttribute("aria-hidden","true");const head=h("div","cx-tl-print-row cx-tl-print-head"),corner=h("div","cx-tl-print-name"),scale=h("div","cx-tl-print-lane");setText(corner,this.tlSolo?"":this.cal.resources?.label||this.calLabels.calendarResources);for(const cell of this.tlHeader.lower){const mark=h("span","cx-tl-print-unit");mark.style.insetInlineStart=(cell.x / axis.total * 100) + "%"; mark.style.width = (cell.width / axis.total * 100) + "%";
83
+ setText(mark,cell.text);scale.appendChild(mark)}
84
+ head.append(corner,scale);view.appendChild(head);for(const row of tree.rows.filter(item=>!item.status).slice(0,TL_PRINT_ROWS)){const line=h("div","cx-tl-print-row"),name=h("div","cx-tl-print-name"),lane=h("div","cx-tl-print-lane"),group=this.tl.children.has(row.key);name.style.paddingInlineStart=(4 +(row.level-1)*12)+ "px";setText(name,this.tlSolo?"":this.calResourceName(row.key));if(group){line.classList.add("cx-tl-print-group");this.tlHeat(row.key).forEach((value,index)=>{if(!value)return;const unit=axis.units[index],mark=h("span","cx-tl-print-heat");mark.style.insetInlineStart=(unit.x / axis.total * 100) + "%"; mark.style.width = (axis.width / axis.total * 100) + "%"; setText(mark, String(value)); lane.appendChild(mark); });
85
+ }else for(const event of this.tlIndex.byResource.get(row.key)||[]){if(event.tlEnd<=axis.from||event.tlStart>=axis.to)continue;const bar=h("span","cx-tl-print-bar");const from=Math.max(event.tlStart,axis.from),to=Math.min(event.tlEnd,axis.to),pixels=(axis.x(to)- axis.x(from))/ axis.total * TL_PRINT_LANE;
86
+ bar.style.insetInlineStart=share(from);bar.style.width="max(6px, calc("+share(to)+ " - "+share(from)+ "))";if(event.tone)bar.style.setProperty("--cx-ev","var(--cx-tone-"+event.tone+",var(--cx-accent))");if(pixels<16)bar.classList.add("cx-tl-print-tiny");if(pixels>=event.title.length*TL_PRINT_CHAR+8)setText(bar,event.title);bar.title=this.calEventName(event);lane.appendChild(bar)}
87
+ line.append(name,lane);view.appendChild(line)}
88
+ this.tlRoot.appendChild(view)}});installed.add(context.DataGrid.prototype)}};(global.CanopyXParts||=[]).push(["timeline",part])})(typeof window!=="undefined"?window:globalThis);
@@ -0,0 +1,103 @@
1
+ /* Graphite chrome shared by flat grids and trees: the card,toolbar,search,buttons,menus,header and cells. */
2
+ .cx-tree-tools{border:var(--cx-size-1px) solid var(--cx-line);border-radius:calc(var(--cx-radius) + var(--cx-size-2px));overflow:hidden;font:var(--cx-font-size)/1.4 var(--cx-font);}
3
+ .cx-page > .cx-tree-tools,.cx-page > .cx-main > .cx-tree-tools{padding:0;}
4
+ body .cx-host.cx-tree-tools{padding:0;}
5
+ .cx-tree-tools [hidden]{display:none!important;}
6
+ .cx-tree-tools .cx-grid{border:0;border-radius:0;overflow-anchor:none;}
7
+ .cx-tree-tools .cx-toolbar{flex:none;gap:var(--cx-size-8px);padding:var(--cx-size-10px) var(--cx-size-12px);border-bottom:var(--cx-size-1px) solid var(--cx-line);}
8
+ .cx-tree-tools .cx-search{flex:1 1 var(--cx-size-240px);max-width:var(--cx-size-360px);height:var(--cx-control-h);display:flex;align-items:center;gap:var(--cx-size-8px);padding:0 var(--cx-size-10px);border:var(--cx-size-1px) solid var(--cx-control-border);border-radius:var(--cx-radius);color:var(--cx-muted);background:var(--cx-surface);min-width:0;}
9
+ .cx-tree-tools .cx-search::before,.cx-tree-tools .cx-search::after{display:none;}
10
+ .cx-tree-tools .cx-search-input{flex:1;min-width:0;width:100%;max-width:none;min-height:0;height:100%;border:0;padding:0;border-radius:0;background:transparent;}
11
+ .cx-tree-tools .cx-search:focus-within{outline:var(--cx-size-2px) solid var(--cx-accent);outline-offset:var(--cx-size-2px);}
12
+ .cx-tree-tools .cx-search .cx-search-input:focus-visible{outline:0;}
13
+ .cx-tree-tools .cx-search kbd{font:var(--cx-size-11px) var(--cx-font-mono);border:var(--cx-size-1px) solid var(--cx-line);border-radius:var(--cx-size-4px);padding:0 var(--cx-size-5px);}
14
+ .cx-tree-tools .cx-button,.cx-tree-tools .cx-btn{height:var(--cx-control-h);min-height:var(--cx-control-h);display:inline-flex;align-items:center;justify-content:center;gap:var(--cx-size-6px);padding:0 var(--cx-size-11px);border:var(--cx-size-1px) solid var(--cx-line-strong);border-radius:var(--cx-radius);background:var(--cx-surface);color:var(--cx-text);font:500 var(--cx-size-14px) var(--cx-font);cursor:pointer;white-space:nowrap;}
15
+ .cx-tree-tools .cx-columns > summary::after{display:none;}
16
+ .cx-tree-tools .cx-button:hover,.cx-tree-tools .cx-btn:hover{background:var(--cx-hover-bg);}
17
+ .cx-tree-tools .ghost{border-color:transparent;color:var(--cx-text-2);}
18
+ .cx-tree-tools .icon{width:var(--cx-control-h);padding:0;}
19
+ .cx-tree-tools .active{border-color:var(--cx-accent);color:var(--cx-accent-text);background:var(--cx-accent-soft);}
20
+ .cx-tree-tools .badge{min-width:var(--cx-size-18px);height:var(--cx-size-18px);padding:0 var(--cx-size-5px);border-radius:var(--cx-size-9px);background:var(--cx-accent);color:var(--cx-on-accent);font-size:var(--cx-size-11d5px);font-weight:700;display:inline-grid;place-items:center;}
21
+ .cx-tree-tools .cx-button:disabled{opacity:.4;cursor:default;}
22
+ .cx-spacer{flex:1;}
23
+ .cx-sep{width:var(--cx-size-1px);height:var(--cx-size-20px);background:var(--cx-line);}
24
+ .cx-tree-tools .cx-hrow{height:var(--cx-head-h);}
25
+ .cx-tree-tools .cx-hcell{padding:0 var(--cx-cell-px);font-size:var(--cx-size-13px);font-weight:700;color:var(--cx-text-2);border-right:0;overflow:visible;gap:var(--cx-size-4px);}
26
+ .cx-tree-tools .cx-hcell::after{content:"";position:absolute;right:0;top:var(--cx-size-9px);bottom:var(--cx-size-9px);width:var(--cx-size-1px);background:var(--cx-line);}
27
+ .cx-tree-tools .cx-hcell:last-child::after{display:none;}
28
+ .cx-tree-tools .cx-hcell:last-child .cx-resize{right:0;}
29
+ .cx-tree-tools .cx-hcell .cx-sort{min-width:var(--cx-size-24px);overflow:hidden;}
30
+ .cx-tree-tools .cx-htext{overflow:hidden;text-overflow:ellipsis;}
31
+ .cx-tree-tools .cx-cell{padding:0 var(--cx-cell-px);font-variant-numeric:tabular-nums;}
32
+ .cx-tree-tools .cx-row > .cx-cell:first-child:not([data-cx-pin]){position:relative;}
33
+ .cx-tree-tools .cx-row[aria-selected="true"] > .cx-cell:first-child::before{content:"";position:absolute;inset:0 auto 0 0;width:var(--cx-size-2px);background:var(--cx-accent);pointer-events:none;z-index:4;}
34
+ .cx-tree-tools .cx-grid-panel{position:fixed;height:auto;color:inherit;width:var(--cx-size-280px);max-width:calc(var(--cx-size-100vw) - var(--cx-size-32px));display:flex;flex-wrap:wrap;gap:var(--cx-size-8px);padding:var(--cx-size-10px) var(--cx-size-12px);border:var(--cx-size-1px) solid var(--cx-line);border-radius:var(--cx-radius);box-shadow:var(--cx-panel-shadow);}
35
+ .cx-tree-tools .cx-grid-columns > .cx-grid-panel{display:block;width:var(--cx-size-320px);padding:var(--cx-size-8px);max-height:var(--cx-size-420px);overflow:auto;}
36
+ .cx-tree-tools .cx-grid-field{display:flex;flex-direction:column;gap:var(--cx-size-4px);align-items:stretch;min-width:0;}
37
+ .cx-tree-tools .cx-grid-field :is(input:not([type="checkbox"]),select,textarea),.cx-tree-tools .cx-grid-panel > :is(select,input){min-width:0;width:100%;height:var(--cx-control-h);padding:0 var(--cx-size-10px);border:var(--cx-size-1px) solid var(--cx-control-border);border-radius:var(--cx-radius);background:var(--cx-surface);color:var(--cx-text);font:inherit;}
38
+ .cx-grid-control-error{color:var(--cx-tone-danger);margin:0;width:100%;overflow-wrap:anywhere;}
39
+ .cx-grid-delivery-status{margin:0;font-size:var(--cx-size-d875em);overflow-wrap:anywhere;}
40
+ .cx-grid-delivery-status:empty{display:none;}
41
+ .cx-grid-export progress{width:100%;max-width:100%;accent-color:var(--cx-accent);}
42
+ .cx-tree-tools .cx-grid-views .cx-grid-field{width:100%;}
43
+ .cx-tree-tools :is(button,summary,select,input,textarea):focus-visible{outline:var(--cx-size-2px) solid var(--cx-accent);outline-offset:var(--cx-size-2px);}
44
+ .cx-tree-tools .cx-grid-overflow .cx-grid-panel{right:0;left:auto;width:var(--cx-size-244px);}
45
+ .cx-tree-tools .cx-grid-overflow .cx-grid-panel > .cx-button{width:100%;justify-content:start;border:0;border-radius:var(--cx-radius-sm);}
46
+ .cx-tree-tools.cx-phone .cx-toolbar{gap:var(--cx-size-6px);}
47
+ .cx-tree-tools.cx-phone .cx-search{max-width:none;flex-basis:100%;height:var(--cx-size-44px);}
48
+ .cx-tree-tools.cx-phone .cx-spacer,.cx-tree-tools.cx-phone .cx-sep{display:none;}
49
+ .cx-tree-tools.cx-phone .cx-grid-columns > summary{width:var(--cx-size-44px);font-size:0;padding:0;}
50
+ .cx-tree-tools.cx-phone .cx-grid-columns > summary .cx-ico{width:var(--cx-size-16px);height:var(--cx-size-16px);}
51
+ .cx-tree-tools.cx-phone .cx-toolbar :is(.cx-btn,.cx-button){min-height:var(--cx-size-44px);}
52
+ .cx-tree-tools.cx-phone .cx-grid-panel{position:fixed!important;inset:auto 0 0!important;width:100%!important;max-width:100%!important;max-height:var(--cx-size-85vh)!important;overflow:auto;border-radius:var(--cx-radius) var(--cx-radius) 0 0;z-index:30;}
53
+ .cx-tree-tools.cx-phone .cx-grid-panel::before{content:"";display:block;width:var(--cx-size-32px);height:var(--cx-size-4px);border-radius:var(--cx-radius);background:var(--cx-muted);margin:0 auto var(--cx-size-8px);flex-basis:var(--cx-size-32px);}
54
+ .cx-tree-tools.cx-phone .cx-grid-panel:has(> [open])::before{display:none;}
55
+ .cx-tree-tools.cx-phone .cx-hrow{height:var(--cx-size-44px);}
56
+ .cx-tree-tools.cx-phone .cx-hidden-fields::after{content:"";position:absolute;inset:calc(-1 * var(--cx-size-10px)) calc(-1 * var(--cx-size-8px));}
57
+ .cx-grid-column-choice:hover{background:var(--cx-hover-bg);}
58
+ .cx-grid-column-handle{min-width:var(--cx-size-24px);}
59
+ .cx-grid-column-find{margin-bottom:var(--cx-size-4px);}
60
+ .cx-grid-column-choice{display:flex;align-items:center;border-radius:var(--cx-radius-sm);}
61
+ .cx-grid-column-choice label{flex:1;min-width:0;white-space:nowrap;}
62
+ .cx-grid-column-name{flex:1;overflow:hidden;text-overflow:ellipsis;}
63
+ :is(.cx-grid-column-note,.cx-grid-column-handle){flex:none;padding:0 var(--cx-size-6px);color:var(--cx-muted);font-size:var(--cx-size-12px);white-space:nowrap;}
64
+ .cx-grid-column-handle{height:var(--cx-size-28px);border:0;background:none;cursor:grab;touch-action:none;}
65
+ .cx-grid-column-choice.cx-drop-before{box-shadow:inset 0 var(--cx-size-2px) var(--cx-accent);}
66
+ .cx-grid-column-choice.cx-drop-after{box-shadow:inset 0 var(--cx-size-neg-2px) var(--cx-accent);}
67
+ .cx-grid-column-actions{display:flex;justify-content:space-between;margin-top:var(--cx-size-4px);padding-top:var(--cx-size-4px);border-top:var(--cx-size-1px) solid var(--cx-line);}
68
+ .cx-grid-column-actions .cx-button{border:0;color:var(--cx-accent-text);background:none;}
69
+ .cx-drawer{width:100%;max-width:var(--cx-size-440px);background:var(--cx-surface);border:var(--cx-size-1px) solid var(--cx-line);border-radius:var(--cx-radius);box-shadow:var(--cx-panel-shadow);font:var(--cx-size-14px)/1.45 var(--cx-font);color:var(--cx-text);overflow:hidden;}
70
+ .cx-drawer-h{display:flex;align-items:flex-start;gap:var(--cx-size-12px);padding:var(--cx-size-14px) var(--cx-size-16px);border-bottom:var(--cx-size-1px) solid var(--cx-line);}
71
+ .cx-drawer-h h4{margin:0;font-size:var(--cx-size-17px);width:fit-content;}
72
+ .cx-drawer-h p{color:var(--cx-muted);font-size:var(--cx-size-13px);}
73
+ .cx-drawer-h .cx-btn{margin-left:auto;}
74
+ .cx-dl{display:grid;grid-template-columns:var(--cx-size-140px) 1fr;gap:var(--cx-size-8px) var(--cx-size-16px);padding:var(--cx-size-14px) var(--cx-size-16px);margin:0;}
75
+ .cx-dl dt{color:var(--cx-muted);font-size:var(--cx-size-13px);padding-top:var(--cx-size-1px);}
76
+ .cx-dl dd{margin:0;}
77
+ .cx-drawer-s{padding:var(--cx-size-4px) var(--cx-size-16px) 0;font-size:var(--cx-size-11d5px);letter-spacing:var(--cx-size-d06em);text-transform:uppercase;color:var(--cx-muted);font-weight:700;}
78
+ body .cx-host.cx-drawer{position:fixed;left:auto;right:var(--cx-size-12px);top:var(--cx-size-12px);bottom:var(--cx-size-12px);margin:0;width:calc(100% - var(--cx-size-24px));max-width:var(--cx-size-440px);height:calc(100% - var(--cx-size-24px));padding:0;display:flex;flex-direction:column;z-index:1000;}
79
+ .cx-drawer-body{overflow:auto;flex:1;}
80
+ .cx-drawer .cx-drawer-h > div{flex:1;min-width:0;}
81
+ .cx-drawer .cx-drawer-h{flex:none;}
82
+ .cx-drawer .cx-drawer-h p{margin:var(--cx-size-4px) 0 0;overflow-wrap:anywhere;}
83
+ .cx-drawer dd{overflow-wrap:anywhere;min-width:0;}
84
+ .cx-drawer .cx-button{flex:none;}
85
+ .cx-drawer :is(.p-strip,.p-spark,.p-line){max-width:100%;}
86
+ body .cx-host.cx-drawer.cx-phone{inset:0;width:100%;max-width:none;height:100%;max-height:none;border-radius:0;}
87
+ .cx-drawer.cx-phone .cx-dl{grid-template-columns:1fr;gap:var(--cx-size-2px) 0;}
88
+ .cx-drawer.cx-phone dd{margin-bottom:var(--cx-size-8px);}
89
+ .cx-drawer.cx-phone .cx-button{min-height:var(--cx-size-44px);min-width:var(--cx-size-44px);}
90
+ .cx-drawer::backdrop{background:color-mix(in srgb,var(--cx-shadow-ink) 35%,transparent);}
91
+ .cx-grid-overlay{color:var(--cx-text);font:var(--cx-font-size)/1.45 var(--cx-font);}
92
+ body .cx-host.cx-grid-overlay{height:auto;min-height:0;padding:0;}
93
+ .cx-grid-overlay [hidden]{display:none!important;}
94
+ .cx-tree-tools.cx-pin-tree .cx-row > .cx-cell.cx-tree:first-child{position:sticky;}
95
+ .cx-tree-tools .cx-row > [data-cx-pin]{position:sticky;z-index:1;background:inherit;}
96
+ .cx-tree-tools .cx-hcell[data-cx-pin]{position:sticky;z-index:2;background:var(--cx-head-bg);}
97
+ .cx-tree-tools .cx-results{position:fixed;}
98
+ .cx-tree-tools .cx-hcell[aria-sort="ascending"] .cx-sort::after{content:"↑";font-size:var(--cx-size-14px);color:var(--cx-accent);}
99
+ .cx-tree-tools .cx-hcell[aria-sort="descending"] .cx-sort::after{content:"↓";font-size:var(--cx-size-14px);color:var(--cx-accent);}
100
+ .cx-tree-tools .cx-switch{font-size:var(--cx-size-14px);color:var(--cx-text-2);white-space:nowrap;}
101
+ .cx-tree-tools .cx-hidden-fields{color:var(--cx-muted);font:var(--cx-size-12d5px) var(--cx-font);border:0;background:transparent;padding:0;flex:none;height:auto;min-height:var(--cx-size-24px);min-width:var(--cx-size-24px);margin-left:var(--cx-size-4px);position:relative;}
102
+ .cx-tree-tools.cx-drawer :focus-visible{outline:var(--cx-size-2px) solid var(--cx-accent);outline-offset:var(--cx-size-2px);}
103
+ .cx-tree-tools.cx-drawer [data-cx-pointer-focus]:focus-visible{outline:none;}
@@ -0,0 +1,92 @@
1
+ (function(global){"use strict";const installed=new WeakSet();const part={version:"ce442e100494535d",install(context){if(installed.has(context.TreeGrid.prototype))return;const{TreeGrid,h,setText,fill,numberFormat,watchFlyout,columnWidth,prepareWidth,cellText,cellValue,isCellObject,foldText,formatting,sortKey,compareKeys,EXPORT_FORMATS,exportFormat,exportTimeout,exportFormatsOf,INDENT,MAX_PROTOCOL_INTEGER,hostControl,detailCell,HostCellContext,disposeHostSlot,loadPart,definePart,pluginItems,applyTone,toneOf,badgeElement,RECORD_IMPL,svgIcon,gridExportField}=context;const EXPORT_IMPL={formatsOf:exportFormatsOf};const GRID_ICONS={search:'<circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/>',filter:'<path d="M4 5h16l-6 7.5V19l-4-2v-4.5z"/>',columns:'<rect x="3.5" y="4.5" width="17" height="15" rx="2"/><path d="M9.5 4.5v15M14.5 4.5v15"/>',views:'<path d="M6 4h12v16l-6-4-6 4z"/>',export:'<path d="M12 4v11M7.5 10.5 12 15l4.5-4.5M5 19h14"/>',more:'<circle cx="5" cy="12" r="1.2"/><circle cx="12" cy="12" r="1.2"/><circle cx="19" cy="12" r="1.2"/>',close:'<path d="M6 6l12 12M18 6 6 18"/>',check:'<path d="m5 12.5 4.5 4.5L19 7.5"/>',chart:'<path d="M4 19h16M7 16V10M12 16V6M17 16v-4"/>',copy:'<rect x="8" y="8" width="11" height="11" rx="2"/><path d="M16 8V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h2"/>',up:'<path d="M12 19V5M6 11l6-6 6 6"/>',down:'<path d="M12 5v14M6 13l6 6 6-6"/>',retry:'<path d="M4 12a8 8 0 1 0 2.4-5.7M4 4v4.5h4.5"/>',previous:'<path d="m14 7-5 5 5 5"/>',next:'<path d="m10 7 5 5-5 5"/>',first:'<path d="m13 7-5 5 5 5M17 7l-5 5 5 5"/>',last:'<path d="m11 7 5 5-5 5M7 7l5 5-5 5"/>'};function gridIcon(name,shapes){return svgIcon(shapes||GRID_ICONS[name]||GRID_ICONS.more)}
2
+ function gridDecorateButton(button,icon,ghost){button.classList.add("cx-btn");if(ghost)button.classList.add("ghost");if(icon)button.prepend(gridIcon(icon));return button}
3
+ function gridFilterCount(query){const count=group=>group?group.filters.length+group.groups.reduce((sum,child)=>sum+count(child),0):0;return(query?.filters?.length||0)+ count(query?.filterGroup)}
4
+ function gridPriority(value){return["essential","normal","optional"].includes(value)||Number.isInteger(value)&&value>=0&&value<=MAX_PROTOCOL_INTEGER}
5
+ function gridRank(column){const value=column.priority;return typeof value==="number"?value:value==="optional"?10000:value==="essential"||value===undefined&&column.identity?0:5000}
6
+ function gridLevel(column){const rank=gridRank(column);return rank<2?0:rank<10000?1:2}
7
+ function gridOptions(column){return column.presenter||{}}
8
+ const COLUMN_DIGITS=new Map(),COLUMN_NUMERIC_CHARS="0123456789 .,:;+-−/()[]\u00a0\u202f",COLUMN_HAS_NUMERIC=/[0-9\s.,:;+\-−/()\[\]]/;
9
+ function gridNumericVariant(grid){let sample=grid.querySelector(".cx-cell"),owned=!sample;if(owned){sample=document.createElement("span");sample.className="cx-cell";sample.style.display="none";grid.appendChild(sample)}
10
+ const variant=getComputedStyle(sample).fontVariantNumeric;if(owned)sample.remove();return variant}
11
+ function gridMeasureText(context,value,variant="normal"){const text=String(value).slice(0,512),measured=context.measureText(text).width;if(!variant.includes("tabular-nums")||!COLUMN_HAS_NUMERIC.test(text))return measured;const font=context.font;let variants=COLUMN_DIGITS.get(font);if(!variants){if(COLUMN_DIGITS.size===32)COLUMN_DIGITS.delete(COLUMN_DIGITS.keys().next().value);COLUMN_DIGITS.set(font,variants=new Map())}
12
+ if(!variants.has(variant)){const probe=document.createElement("span"),glyphs=[];probe.style.cssText="all:initial;position:absolute;visibility:hidden;display:flex;white-space:pre;padding:0;border:0;max-width:none;";probe.style.font=font;probe.style.fontVariantNumeric=variant;for(const character of COLUMN_NUMERIC_CHARS)for(const numeric of[true,false]){const glyph=document.createElement("span");glyph.textContent=(numeric?"00"+character+"00":character).repeat(10);glyph.style.cssText="flex:none;white-space:pre;";probe.appendChild(glyph);glyphs.push(glyph)}
13
+ document.body.appendChild(probe);const zero=glyphs[0].getBoundingClientRect().width / 50, numeric = new Map(), plain = new Map();
14
+ for(let index=0;index<COLUMN_NUMERIC_CHARS.length;index++){const character=COLUMN_NUMERIC_CHARS[index],canvas=context.measureText(character).width;for(let mode=0;mode<2;mode++){const delta=glyphs[index*2+mode].getBoundingClientRect().width / 10 - (mode ? 0 : 4 * zero) - canvas;
15
+ if(Math.abs(delta)>0.02)(mode?plain:numeric).set(character.charCodeAt(0),delta)}}
16
+ probe.remove();variants.set(variant,{numeric:numeric.size?numeric:null,plain:plain.size?plain:null})}
17
+ const advances=variants.get(variant),digits=/[0-9]/.test(text) ? advances.numeric : advances.plain;
18
+ if(!digits)return measured;let width=measured;for(let index=0;index<text.length;index++){width +=digits.get(text.charCodeAt(index))||0}
19
+ return width}
20
+ function gridTextual(column){return column.kind==="text"&&!["statusStrip","sparklineBars","sparklineLine","boolean","progress"].includes(gridOptions(column).kind)}
21
+ function gridFitColumn(column,identity){prepareWidth(column);column.identity=column===identity;column.pref=column.autoWidth?0:column.width;column.basePriority=column.priority;column.declared=column.width;column.flexWeight=typeof column.flex==="number"?column.flex:0;if(column.flexWeight)column.flex=true;else if(typeof column.flex==="number")delete column.flex}
22
+ const COLUMN_FIT={fitManual(column){column.width=column.renderWidth??column.width;column.sized=true},fitSize(column,level){const need=(column.need??column.width)+(column.reserve||0);if(level===0)return column.identity&&column.priority===undefined&&!column.fixed&&!column.sized?
23
+ Math.max(column.minW,column.headNeed||0):column.renderWidth;return Math.round(columnWidth(column,column.fixed||column.sized?column.width:!level?Math.max(need,column.pref):level>1||!gridLevel(column)?need:
24
+ Math.min(need,Math.max(column.headNeed||0,gridTextual(column)?this.fitCh||88:0))))},fitWidths(cols,width){let total=0,target;for(const column of cols)total +=column.renderWidth=this.fitSize(column);if(width&&total>width&&this.layoutMode&&this.layoutMode!=="fit")width=total;for(const level of[2,1,0])if(width&&total>width&&(level||cols.reduce((sum,column)=>sum+column.renderWidth-this.fitSize(column,0),0)>=total-width))
25
+ total=width+this.fitShrink(cols,total-width,level);if(width&&total<width)target=this.fitSpare(cols.filter(column=>!column.fixed&&!column.sized),width-total);total=0;for(const column of cols)total +=column.renderWidth=Math.floor(column.renderWidth);if(width>total&&!(target?.renderWidth<target?.maxW))for(const column of cols)
26
+ if(!column.fixed&&!column.sized&&column.renderWidth<column.maxW&&gridTextual(column))target=column;if(target)target.renderWidth +=Math.min(width-total,target.maxW-target.renderWidth);return cols.map(column=>column.renderWidth)},fitShrink(cols,excess,level){for(const group of[cols.filter(column=>column.flex),cols.filter(gridTextual),cols]){if(excess<=0.5)break;const floor=new Map(group.map(column=>[column,Math.min(column.renderWidth,this.fitSize(column,level))]));const cut=width=>group.reduce((sum,column)=>sum+Math.max(0,column.renderWidth-Math.max(width,floor.get(column))),0);let low=0,high=Math.max(0,...group.map(column=>column.renderWidth));for(let step=0;step<24;step++){const middle=(low+high)/ 2; if (cut(middle) >= excess) low = middle; else high = middle; }
27
+ excess -=cut(low);for(const column of group)column.renderWidth=Math.min(column.renderWidth,Math.max(low,floor.get(column)))}
28
+ return excess},fitSpare(columns,spare){let target,flex=columns.filter(column=>column.flex&&column.flexWeight);const grow=(column,limit)=>{const add=column?Math.min(spare,Math.min(limit,column.maxW)- column.renderWidth):0;if(add>0){column.renderWidth +=add;spare -=add;target=column}};for(let before=0;spare>0.5&&flex.length&&before!==spare;){const weight=flex.reduce((sum,column)=>sum+column.flexWeight,0);before=spare;for(const column of flex)grow(column,column.renderWidth+before*column.flexWeight / weight);
29
+ flex=flex.filter(column=>column.maxW-column.renderWidth>0.5)}
30
+ const identity=columns.find(column=>column.identity),widest=columns.filter(column=>!column.identity&&
31
+ gridTextual(column)&&gridLevel(column)===1).sort((a,b)=>b.need-a.need)[0];grow(identity,420);if(identity&&widest)grow(widest,widest.renderWidth+spare*widest.need / (widest.need + identity.need));
32
+ grow(identity,Infinity);grow(widest,Infinity);return target},fitHide(shown,width,phone){let total=0,remaining=shown.length;const order=(a,b)=>gridLevel(b)- gridLevel(a)||gridRank(b)- gridRank(a)||shown.indexOf(b)- shown.indexOf(a),identity=phone&&shown.find(column=>column.identity);const hide=(column,pinned)=>!column.sized&&!column.alwaysVisible&&(column.pin==="none")!==pinned&&!(phone&&column.identity)&&gridLevel(column)>!phone;for(const column of this.columns)column.fitHidden=false;if(this.layoutMode&&this.layoutMode!=="fit")return;for(const column of shown)total +=this.fitSize(column,1);for(const column of shown.filter(column=>hide(column,false)).sort(order))
33
+ if(total>width&&remaining>1){column.fitHidden=true;total -=this.fitSize(column,1);remaining--}
34
+ if(identity&&!identity.fixed&&!identity.sized)total +=Math.min(identity.need??identity.width,(identity.indentNeed||0)+ 2*(this.fitCh||88))+(identity.reserve||0)- this.fitSize(identity,1);if(identity)for(const column of shown.filter(column=>hide(column,true)).sort(order))
35
+ if(total>width){column.fitHidden=true;total -=this.fitSize(column,1)}}};function gridButton(text,run){const button=h("button","cx-button");button.type="button";setText(button,text);button.onclick=event=>{button.focus({preventScroll:true});run(event)};return button}
36
+ let keyboardInput=false;if(typeof document!=="undefined"){document.addEventListener("keydown",()=>{keyboardInput=true},true);document.addEventListener("pointerdown",()=>{keyboardInput=false},true)}
37
+ const focusDrawerTitle=title=>{if(keyboardInput&&title===document.activeElement&&!title.matches(":focus-visible"))title.blur();title.toggleAttribute("data-cx-pointer-focus",!keyboardInput);if(!keyboardInput)title.addEventListener("blur",()=>title.removeAttribute("data-cx-pointer-focus"),{once:true});title.focus({preventScroll:true,focusVisible:keyboardInput})};function gridInputLabel(text,input){const label=h("label","cx-grid-field");label.appendChild(document.createTextNode(text));label.appendChild(input);return label}
38
+ function gridOption(value,text){const option=h("option");option.value=value;setText(option,text);return option}
39
+ const MENU_EVENT="canopyx:closemenus",announceMenu=source=>document.dispatchEvent(new CustomEvent(MENU_EVENT,{detail:{source}}));const TOOLBAR_PANELS={startMenus(){this.controlFlyouts=[];this.disposeControls=()=>this.controlFlyouts.forEach(flyout=>flyout.dispose());let pressed=null;for(const type of["mouseup","click","keydown","pointercancel"])document.addEventListener(type,()=>{pressed=null},{capture:true,signal:this.lifetime.signal});for(const type of["pointerdown","focusin",MENU_EVENT])document.addEventListener(type,event=>{if(type==="pointerdown")pressed=event.target;const node=type==="focusin"&&pressed?.isConnected&&event.target.contains(pressed)?pressed:event.detail?.source||event.target;if(type!==MENU_EVENT||event.target.contains(this.host))this.closeMenusOutside(node)},{signal:this.lifetime.signal})},closeMenusOutside(node){for(const details of this.toolbar.querySelectorAll(".cx-columns[open]"))if(!details.contains(node))details.open=false;const popover=this.gridPopover;if(popover&&!popover.panel.contains(node)&&!popover.anchor?.contains(node))this.closeGridPopover(false)},closeMenus(){this.closeMenusOutside(document)},controlPanel(title,className,onOpen){const details=h("details","cx-columns "+className),summary=h("summary","cx-btn"),panel=h("div","cx-columns-list cx-grid-panel cx-pop");summary.setAttribute("role","button");if(className!=="cx-grid-filters")summary.classList.add("ghost");setText(summary,title);details.append(summary,panel);this.toolbar.appendChild(details);summary.prepend(gridIcon(className.slice(8).replace("rs","r")));panel.popover="manual";const flyout=watchFlyout(details,panel,()=>details.open);this.controlFlyouts.push(flyout);details.addEventListener("toggle",()=>{if(details.open){announceMenu(details);if(panel.isConnected)panel.showPopover?.();if(onOpen)onOpen(panel);flyout.position()}else{panel.hidePopover?.();for(const inner of panel.querySelectorAll("details[open]"))inner.open=false}});details.addEventListener("keydown",event=>{if(event.key==="Escape"&&details.open){details.open=false;summary.focus();event.preventDefault();event.stopPropagation()}});return{details,panel}},buildSavedViews(){const panel=this.controlPanel(this.labels.gridViews,"cx-grid-views").panel;const choice=this.savedChoice=h("select"),name=h("input");name.type="text";name.maxLength=100;choice.setAttribute("aria-label",this.labels.gridChooseView);panel.appendChild(choice);panel.appendChild(gridInputLabel(this.labels.gridViewName,name));const error=h("p","cx-grid-control-error");error.setAttribute("role","status");const run=action=>{try{Promise.resolve(action()).then(()=>setText(error,""),failure=>setText(error,failure.message))}
40
+ catch(failure){setText(error,failure.message)}};panel.appendChild(gridButton(this.labels.gridApply,()=>run(()=>this.applySavedView(choice.value))));panel.appendChild(gridButton(this.labels.gridSaveView,()=>run(()=>this.saveView(name.value))));panel.appendChild(gridButton(this.labels.gridRemoveView,()=>run(()=>this.removeSavedView(choice.value))));panel.appendChild(error);this.syncSavedViews()},syncSavedViews(){if(!this.savedChoice)return;const selected=this.savedChoice.value;this.savedChoice.textContent="";this.savedChoice.appendChild(gridOption("",this.labels.gridChooseView));this.getSavedViews().forEach(name=>this.savedChoice.appendChild(gridOption(name,name)));if(this.savedViews.has(selected))this.savedChoice.value=selected},placeMenus(phone){if(this.overflow)for(const selector of[".cx-grid-views",".cx-grid-export"]){const item=this.toolbar.querySelector(selector);if(!item)continue;item.open=false;if(phone)this.overflow.panel.appendChild(item);else this.toolbar.insertBefore(item,selector===".cx-grid-views"?this.slots?.afterViews||this.spacer:this.overflow.details)}}};const COLUMNS_MENU={moveColumnChoice(column,target,after){column.pin=target.pin;const ids=this.columns.map(item=>item.id).filter(id=>id!==column.id);ids.splice(ids.indexOf(target.id)+ after,0,column.id);this.setColumnOrder(ids)},renderGridColumns(panel){if(!this.columnList){const find=this.columnFind=h("input","cx-grid-column-find"),actions=h("div","cx-grid-column-actions");find.type="search";find.placeholder=this.labels.gridFindColumn;find.setAttribute("aria-label",find.placeholder);find.hidden=this.columns.length<9;find.oninput=()=>this.syncColumnControls();actions.append(gridButton(this.labels.gridShowAllColumns,()=>this.showAllColumns()),gridButton(this.labels.gridResetColumns,()=>this.resetColumns()));panel.replaceChildren(find,this.columnList=h("div"),actions)}
41
+ this.syncColumnControls()},syncColumnControls(){const list=this.columnList,active=document.activeElement,query=foldText(this.columnFind?.value.trim()||"");if(!list)return;const focus=list.contains(active)&&active.closest(".cx-grid-column-choice").dataset.cxColumn,held=focus&&active.matches(".cx-grid-column-handle"),last=this.columns.filter(item=>!item.hidden).length<2;list.textContent="";for(const column of this.columns){const row=h("div","cx-grid-column-choice"),label=h("label"),input=h("input"),name=h("span","cx-grid-column-name"),handle=h("button","cx-grid-column-handle"),note=column.fitHidden||column.responsiveHidden?this.labels.gridResponsiveHidden:column.pin==="left"?this.labels.gridPinnedLeft:column.pin==="right"?this.labels.gridPinnedRight:"";input.type="checkbox";input.checked=!column.hidden;input.disabled=!column.hidden&&last;input.onchange=()=>{input.focus({preventScroll:true});this.setColumnVisible(column.id,input.checked)};setText(name,name.title=column.title);handle.type="button";setText(handle,"⋮⋮");handle.setAttribute("aria-label",fill(this.labels.gridReorderColumn,{column:column.title}));label.append(input,name);row.append(handle,label);row.hidden=!!query&&!foldText(column.title).includes(query);if(note){const span=h("span","cx-grid-column-note");setText(span,note);row.append(span)}
42
+ row.onkeydown=event=>{const target=event.altKey&&this.columns[this.columns.indexOf(column)+(event.key==="ArrowUp"?-1:event.key==="ArrowDown"?1:NaN)];if(target){event.preventDefault();event.stopPropagation();this.moveColumnChoice(column,target,event.key==="ArrowDown")}};handle.onpointerdown=event=>{if(event.button)return;event.preventDefault();handle.focus();handle.setPointerCapture(event.pointerId);let target,after;const clear=()=>{for(const item of list.children)item.classList.remove("cx-drop-before","cx-drop-after")};handle.onpointermove=move=>{clear();const over=document.elementFromPoint(move.clientX,move.clientY)?.closest(".cx-grid-column-choice");target=over!==row&&list.contains(over)&&this.columns[[...list.children].indexOf(over)];if(target){const box=over.getBoundingClientRect();after=move.clientY>box.top+box.height / 2; over.classList.add(after ? "cx-drop-after" : "cx-drop-before"); }
43
+ };handle.onpointerup=handle.onpointercancel=up=>{handle.onpointermove=handle.onpointerup=handle.onpointercancel=null;clear();if(up.type==="pointerup"&&target)this.moveColumnChoice(column,target,after)}};row.dataset.cxColumn=column.id;list.appendChild(row);if(focus===column.id)(held?handle:input).focus({preventScroll:true})}}};function gridOperationActive(grid,signal){if(grid.destroyed||signal?.aborted)throw new DOMException("Grid cancelled.","AbortError")}
44
+ const exportPartReady=()=>typeof loadExportPart==="function"?loadExportPart():Promise.resolve();function exportAs(grid,format,options={}){const{onProgress,timeoutMs,download,...capture}=options;let provider,resolutionError;try{provider=EXPORT_IMPL.formatsOf(grid).find(item=>item.id===format)}
45
+ catch(error){resolutionError=error}
46
+ const prepared=grid.calIcsFormatWriter&&provider?.write===grid.calIcsFormatWriter?grid.calPrepareIcsExport(capture):grid.prepareExport(capture);return exportPartReady().then(()=>{if(resolutionError)throw resolutionError;return EXPORT_IMPL.run(grid,format,options,prepared,provider)})}
47
+ Object.assign(TreeGrid.prototype,TOOLBAR_PANELS,COLUMNS_MENU,{installTools(){this.checkTreeLayout();const bar=this.toolbar,tools=this.tools,labels=this.labels;this.host.classList.add("cx-chrome","cx-tree-tools");this.exportScopes=[["visible","gridVisibleRows"],["selected","gridSelectedRows"],["all","gridAllRows"]];this.toolbar.querySelector(".cx-search")?.prepend(gridIcon("search"));this.startMenus();this.lifetime.signal.addEventListener("abort",()=>{this.disposeControls();this.host.classList.remove("cx-chrome","cx-tree-tools","cx-phone")},{once:true});if(tools.columns!==false&&this.columns.length>1)this.controlPanel(labels.columns,"cx-grid-columns",panel=>this.renderGridColumns(panel));for(const item of pluginItems(this,"toolbarItems"))bar.appendChild(this.treeAction(item));this.prepareSavedViews();if(tools.views!==false&&this.stateKey()){this.buildSavedViews();bar.querySelector(".cx-grid-views .cx-grid-panel").appendChild(gridButton(labels.gridResetView,()=>this.resetView().catch(()=>{})))}
48
+ bar.appendChild(this.spacer=h("span","cx-spacer"));if(tools.export!==false)this.exportControl=this.controlPanel(labels.gridExport,"cx-grid-export",panel=>this.renderGridExport(panel));if(tools.more!==false)this.buildMoreMenu();if(bar.childElementCount===1)bar.replaceChildren();this.syncToolbar();this.startFit()},buildMoreMenu(){const overflow=this.overflow=this.controlPanel(this.labels.gridMore,"cx-grid-overflow"),summary=overflow.details.firstChild;summary.replaceChildren(gridIcon("more"));summary.classList.add("icon");summary.setAttribute("aria-label",this.labels.gridMore);for(const action of[...this.opts.actions||[],...pluginItems(this,"menuItems")])overflow.panel.appendChild(this.treeAction(action));if(this.columns.length>1)overflow.panel.appendChild(Object.assign(gridButton(this.labels.gridDetails,()=>
49
+ this.openDetails((this.focused||this.rows.find(w=>this.selected.has(w)))?.key).catch(error=>this.emit("error",{error}))),{className:"cx-button cx-grid-details"}));overflow.panel.appendChild(Object.assign(gridButton(this.labels.gridPrint,()=>global.print()),{className:"cx-button cx-grid-print"}))},treeSelection(){return Array.from(this.selected,w=>w.h)},treeAction(action){if(!action||typeof action.label!=="string"||typeof action.run!=="function")throw new Error("CanopyX: actions need a label and handler.");return gridButton(action.label,()=>Promise.resolve().then(()=>
50
+ action.run({nodes:this.treeSelection(),signal:this.dataLifetime.signal,api:this.host.canopyx})).catch(error=>this.emit("error",{error})))},closeMenusOutside(node){TOOLBAR_PANELS.closeMenusOutside.call(this,node);const panel=this.interactionPanel;if(panel?.getAttribute("role")==="menu"&&!panel.contains(node))this.closeInteractionPanel(false)},renderGridColumns(panel){COLUMNS_MENU.renderGridColumns.call(this,panel);this.columnList.setAttribute("role","group");this.columnList.setAttribute("aria-label",this.labels.visibleColumns)},syncColumnControls(){COLUMNS_MENU.syncColumnControls.call(this);const row=this.columnList?.firstChild;if(row){row.querySelector(".cx-grid-column-handle").hidden=true;row.querySelector("input").disabled=true}},syncPhone(){const phone=this.host.clientWidth<=640;if(phone===this.phone)return;if(this.hiddenFieldCount())this.version++;this.phone=phone;this.host.classList.toggle("cx-phone",phone);this.placeMenus(phone)}});const OPEN_PANEL=TreeGrid.prototype.openInteractionPanel;if(OPEN_PANEL)TreeGrid.prototype.openInteractionPanel=function(...args){const panel=OPEN_PANEL.apply(this,args);if(panel?.getAttribute("role")==="menu")announceMenu(panel);return panel};const TREE_ACTIVATION={activate:TreeGrid.prototype.activate,onDblClick:TreeGrid.prototype.onDblClick};Object.assign(TreeGrid.prototype,{rowActivated(w,keyboard){const callback=this.opts.onRowActivate;let go=this.host.dispatchEvent(new CustomEvent("canopyx:rowActivate",{detail:{id:w.key,node:w.h,keyboard},bubbles:true,cancelable:true}));if(typeof callback==="function"){try{go=callback(w.h,{keyboard})!==false&&go}catch(error){global.console?.error(error)}}
51
+ return go},activate(w,enter){if(!enter||w.status||this.rowActivated(w,true))TREE_ACTIVATION.activate.call(this,w,enter)},onDblClick(event){const w=this.rowFromEvent(event);if(!w||w.status||hostControl(event.target)||event.target.closest(".cx-exp")||this.rowActivated(w,false))TREE_ACTIVATION.onDblClick.call(this,event)}});const TREE_FIT={};for(const name of["applyWidths","visibleColumns","setColumnWidth","startResize","buildHeader","render","getState","readState","applyStatePresentation"])
52
+ TREE_FIT[name]=TreeGrid.prototype[name];const TREE_FIT_ROWS=2000;Object.assign(TreeGrid.prototype,COLUMN_FIT,{checkTreeLayout(){for(const[index,column]of this.view.columns.entries()){if(column.priority!==undefined&&!gridPriority(column.priority)||column.flex!==undefined&&!(typeof column.flex==="number"&&column.flex>=0&&column.flex<=100)||
53
+ [column.fixed,column.alwaysVisible,column.autoWidth].some(value=>value!==undefined&&typeof value!=="boolean")||
54
+ column.autoSize!==undefined&&!["content","header","none"].includes(column.autoSize)||
55
+ column.pinned!==undefined&&(index?!["left","right",null].includes(column.pinned):column.pinned!==null&&column.pinned!=="left"))throw new Error("CanopyX: invalid tree column layout.")}},startFit(){const identity=this.columns[0];for(const column of this.columns){const declared=this.view.columns.find(item=>item.id===column.id);column.autoWidth=!!(declared.autoWidth||declared.width===undefined);gridFitColumn(column,identity);column.declared=columnWidth(column,declared.width??160);if(this.restoredPin&&column.width!==column.declared)column.sized=true;column.pin=column===identity?"left":this.restoredPin&&column.pin||declared.pinned||"none"}
56
+ this.groupPins();if(identity.pinned!==null&&!this.restoredPin)this.host.classList.add("cx-pin-tree");this.fitReady=true;this.fitRows=null;this.observeFit();this.buildHeader()},observeFit(){let width=0;const observer=new ResizeObserver(()=>requestAnimationFrame(()=>{if(this.destroyed||!this.grid.clientWidth||this.grid.clientWidth===width)return;width=this.grid.clientWidth;this.syncPhone();this.applyWidths();this.heightTotal=undefined;this.scheduleRender()}));observer.observe(this.grid);this.lifetime.signal.addEventListener("abort",()=>observer.disconnect(),{once:true})},visibleColumns(){return TREE_FIT.visibleColumns.call(this).filter(column=>!column.fitHidden)},buildHeader(){if(this.fitReady)this.fitLayout();TREE_FIT.buildHeader.call(this);if(this.fitReady)this.headCells.forEach((cell,index)=>cell.querySelector(".cx-resize").addEventListener("keydown",event=>{if(["ArrowLeft","ArrowRight","Home"].includes(event.key))this.fitManual(this.cols[index])},true))},applyWidths(widths){if(widths||!this.fitReady||!this.cols)return TREE_FIT.applyWidths.call(this,widths);const width=this.grid.clientWidth;this.fitLayout();const visible=this.visibleColumns();if(visible.length!==this.cols.length||visible.some((column,index)=>column!==this.cols[index])){this.buildHeader();this.syncColumnControls();this.version++;this.scheduleRender();return}
57
+ TREE_FIT.applyWidths.call(this,this.fitWidths(this.cols,width))},startResize(event,column){if(!this.destroyed&&!event.button&&this.fitReady)this.fitManual(column);return TREE_FIT.startResize.call(this,event,column)},setColumnWidth(id,width){const column=this.columns.find(item=>item.id===id);if(column&&Number.isFinite(width))column.sized=true;return TREE_FIT.setColumnWidth.call(this,id,width)},fitLayout(){const width=this.grid.clientWidth;if(!width)return;const key=this.layout+":"+this.local+":" +(this.host.clientWidth<=640);if(this.fitRows!==this.rows||this.fitKey!==key){this.fitRows=this.rows;this.fitKey=key;this.measureTreeColumns()}
58
+ const shown=TREE_FIT.visibleColumns.call(this),phone=this.host.clientWidth<=640,identity=this.columns[0];identity.reserve=0;this.fitHide(shown,width,phone);const reserve=()=>{this.fitContext.font="700 12.5px"+this.fitFamily;identity.reserve=Math.max(24,Math.ceil(this.fitContext.measureText("+"+this.hiddenFieldCount()).width))+ 8};if(phone&&this.fitContext&&this.hiddenFieldCount()){reserve();this.fitHide(shown,width,phone);reserve()}},measureTreeColumns(){const context=this.fitContext||=document.createElement("canvas").getContext("2d");if(!context)return;const style=getComputedStyle(this.grid),family=this.fitFamily=" "+style.fontFamily,head=this.headCells?.[0]&&getComputedStyle(this.headCells[0]);const font=style.fontWeight+" "+style.fontSize+family,headFont=(head?head.fontWeight+" "+head.fontSize:"700 13px")+ family;const badgeFont="400 "+parseFloat(style.fontSize)*0.8+"px"+family,pad=parseFloat(getComputedStyle(this.host).getPropertyValue("--cx-cell-px"))||8;const numericVariant=gridNumericVariant(this.grid);const text=(value,using=font,numeric=true)=>{context.font=using;return gridMeasureText(context,value,numeric?numericVariant:"normal")};const badges=list=>(list||[]).reduce((sum,badge)=>sum+text(badge.text,badgeFont)+ 20,0);this.fitCh=Math.ceil(text("00000000000"));const rows=[];for(const w of this.rows){if(rows.length===TREE_FIT_ROWS)break;if(!w.status&&!w.h.detail)rows.push(w)}
59
+ const check=this.checkMode?28:0;this.columns.forEach((column,index)=>{const headNeed=Math.ceil(text(column.title,headFont,false)+ 2*pad +(column.sortable?22:8));let values=0,indent=0;if(column.autoSize!=="none"&&column.autoSize!=="header")for(const w of rows){const cell=this.cellOf(w.h,column,index),object=isCellObject(cell);let need=text(cellText(cell,column,this.fmt))+ badges(index===0?w.h.badges:null)+ badges(object?cell.badges:null);const lead=index?0:(w.level-1)*INDENT+22+check +(w.h.icon&&this.iconTemplates.has(w.h.icon)?22:0);if(lead>indent)indent=lead;if(need+lead>values)values=need+lead}
60
+ const cap=index===0?column.maxW:columnWidth(column,420);column.headNeed=Math.min(headNeed,cap);column.indentNeed=indent+2*pad;column.need=Math.max(column.minW,column.autoSize==="none"?column.pref||column.width:Math.min(cap,Math.max(headNeed,Math.ceil(values+2*pad+2))))})},render(){const measured=TREE_FIT.render.call(this);if(this.fitReady&&this.fitRows!==this.rows&&!this.fitPending){this.fitPending=true;requestAnimationFrame(()=>{this.fitPending=false;if(!this.destroyed&&this.fitRows!==this.rows)this.applyWidths()})}
61
+ this.watchHeight();return measured},getState(){const state=TREE_FIT.getState.call(this);state.columns.forEach((saved,index)=>{const column=this.columns[index];if(column.sized)saved.sized=true;if(index)saved.pin=column.pin});return state},readState(state){const result=TREE_FIT.readState.call(this,state);if(result&&result.columns)result.columns.forEach((column,index)=>{if(state.columns[index].sized===true)column.sized=true;if(["none","left","right"].includes(state.columns[index].pin))column.pin=state.columns[index].pin});return result},applyStatePresentation(state){if(state.version&&state.columns){const order=state.columns.map(column=>column.id),rank=column=>{const at=order.indexOf(column.id);return at<0?order.length:at};this.columns=[this.columns[0],...this.columns.slice(1).sort((a,b)=>rank(a)- rank(b))];for(const saved of state.columns){const column=this.columns.find(item=>item.id===saved.id);if(column){column.sized=!!saved.sized||column.declared!==undefined&&saved.width!==column.declared;if(column!==this.columns[0])column.pin=saved.pin??column.pin}}
62
+ this.groupPins();this.restoredPin=true}
63
+ return TREE_FIT.applyStatePresentation.call(this,state)}});const TREE_HEIGHT_DELAY=60;Object.assign(TreeGrid.prototype,{watchHeight(){if(!this.fitReady||this.view.autoHeight===false||this.total===this.heightTotal&&
64
+ (this.heightFitted||!this.rows.some(row=>!row.status)))return;const growing=this.total>this.heightTotal;this.heightTotal=this.total;clearTimeout(this.heightTimer);if(!this.heightFitted||growing){this.fitHeight();return}
65
+ this.heightTimer=setTimeout(()=>this.destroyed||this.fitHeight(),TREE_HEIGHT_DELAY)},fitHeight(){const grid=this.grid,style=this.host.style;if(!grid.clientWidth){this.heightTotal=undefined;return}
66
+ if(this.heightInline===undefined){this.heightInline=style.maxHeight;this.heightMax=parseFloat(getComputedStyle(this.host).maxHeight)||Infinity;this.lifetime.signal.addEventListener("abort",()=>{clearTimeout(this.heightTimer);style.maxHeight=this.heightInline},{once:true})}
67
+ const content=[...grid.children].reduce((sum,child)=>sum+child.offsetHeight,grid.offsetHeight-grid.clientHeight);const value=this.rows.length?Math.min(this.heightMax,Math.ceil(this.host.offsetHeight-grid.offsetHeight+content))+ "px":this.heightInline;if(style.maxHeight!==value){style.maxHeight=value;const anchor=this.interactionPanel&&this.rendered.get(this.panelNode);if(anchor?.isConnected)this.placeInteractionPanel(anchor)}
68
+ if(this.rows.some(row=>!row.status))this.heightFitted=true}});Object.assign(TreeGrid.prototype,{prepareSavedViews(){this.savedViews=new Map();if(this.stateKey())try{const stored=JSON.parse(sessionStorage.getItem(this.stateKey()+ ":views")||"[]");for(const entry of Array.isArray(stored)?stored.slice(0,20):[])if(this.readState(entry&&entry.state))this.savedViews.set(this.viewName(entry.name),entry.state)}catch(error){/* Unavailable storage or an invalid entry leaves the views that could be read. */ }
69
+ },writeSavedViews(){if(this.stateKey())try{sessionStorage.setItem(this.stateKey()+ ":views",JSON.stringify([...this.savedViews].map(([name,state])=>({name,state}))))}
70
+ catch(error){/* A disabled or full storage leaves the current session usable. */ }
71
+ },viewName(name){if(typeof name!=="string"||!name.trim()||name.trim().length>100)throw new Error("CanopyX: view names need 1 to 100 nonblank characters.");return name.trim()},getSavedViews(){return[...this.savedViews.keys()]},saveView(name){name=this.viewName(name);if(!this.savedViews.has(name)&&this.savedViews.size>=20)throw new Error("CanopyX: maximum 20 saved views.");this.savedViews.set(name,this.getState());this.writeSavedViews();this.syncSavedViews();if(this.savedChoice)this.savedChoice.value=name},async applySavedView(name){const state=this.savedViews.get(this.viewName(name));if(!state)throw new Error("CanopyX: the saved view does not exist.");return this.setState(state)},removeSavedView(name){this.savedViews.delete(this.viewName(name));this.writeSavedViews();this.syncSavedViews()},resetView(){return this.setState(this.declaredState())},declaredState(){const expanded=[],walk=parent=>this.modelChildren(parent).forEach(w=>{if(w.h.expanded&&this.expandable(w)){expanded.push(this.pathOf(w));walk(w)}});walk(this.root);return{version:1,expanded,selection:[],columns:this.declaredColumns(),sort:null,filters:[],timeZone:this.view.timeZone==="local"?"local":"utc",pinTreeColumn:!!this.view.pinTreeColumn||this.columns[0].pinned!==null,focus:null,anchor:null,...this.layoutOptions&&{layout:{mode:this.layoutOptions.mode,density:this.layoutOptions.density}},...this.highlightOptions&&{highlight:this.highlightOptions.enabled}}},declaredColumns(){return this.view.columns.map((declared,index)=>({id:declared.id,width:columnWidth(this.columns.find(column=>column.id===declared.id),declared.width??160),hidden:index>0&&!!declared.hidden,pin:index&&declared.pinned||"none"}))},setColumnOrder(ids){if(!Array.isArray(ids)||ids.length!==this.columns.length||new Set(ids).size!==ids.length||ids.some(id=>!this.columns.some(column=>column.id===id)))
72
+ throw new Error("CanopyX: name each column once.");if(this.cancelResize)this.cancelResize();const identity=this.columns[0];this.columns=[identity,...ids.filter(id=>id!==identity.id).map(id=>this.columns.find(column=>column.id===id))];this.groupPins();this.columnsChanged()},showAllColumns(){for(const column of this.columns)column.hidden=false;this.columnsChanged()},resetColumns(){const declared=this.declaredColumns();this.columns=declared.map((saved,index)=>Object.assign(this.columns.find(column=>column.id===saved.id),{width:saved.width,hidden:saved.hidden,sized:false,...index&&{pin:saved.pin}}));this.groupPins();this.columnsChanged()},columnsChanged(){this.buildHeader();this.syncColumnControls();this.relayout();this.stateChanged()}});const TREE_PINS={};for(const name of["applyWidths","render","setTreeColumnPinned"])TREE_PINS[name]=TreeGrid.prototype[name];Object.assign(TreeGrid.prototype,{groupPins(){const[tree,...rest]=this.columns;this.columns=[tree,...["left","none","right"].flatMap(side=>rest.filter(column=>(column.pin||"none")===side))]},setColumnPinned(id,pin){const column=this.columns.find(item=>item.id===id);if(!column||column===this.columns[0]||!["none","left","right"].includes(pin))throw new Error("CanopyX: invalid column pin.");column.pin=pin;this.groupPins();this.columnsChanged();this.emit("columnPin",{column:id,pin})},applyWidths(widths){TREE_PINS.applyWidths.call(this,widths);if(this.fitReady&&this.cols)this.pinRows(true)},setTreeColumnPinned(pinned){TREE_PINS.setTreeColumnPinned.call(this,pinned);if(this.fitReady&&this.cols)this.pinRows(true)},render(){const result=TREE_PINS.render.call(this);this.pinRows();return result},pinRows(measure){const cols=this.cols,width=column=>column.renderWidth??column.width;if(measure){let start=this.host.classList.contains("cx-pin-tree")?width(cols[0]):0,end=0;let stop=false;const room=column=>!(stop||=start+end+width(column)>this.grid.clientWidth-128);for(const column of cols)column.pinAt=null;for(const column of cols.slice(1))if(column.pin==="left"&&room(column)){column.pinAt=start;start +=width(column)}
73
+ stop=false;for(const column of cols.slice(1).reverse())if(column.pin==="right"&&room(column)){column.pinAt=end;end +=width(column)}
74
+ this.pinned=cols.some(column=>column.pinAt!=null)}
75
+ const place=(cell,column)=>{const side=column?.pinAt!=null&&column.pin,key=side&&side+column.pinAt;if(cell._pin===key)return;cell._pin=key;cell.style.left=cell.style.right="";if(side){cell.dataset.cxPin=side;cell.style[side]=column.pinAt+"px"}else delete cell.dataset.cxPin};if(!(this.pinsPlaced||=this.pinned))return;this.headCells.forEach((cell,index)=>place(cell,cols[index]));for(const row of this.rendered.values())if(row._kind==="node")row._cells.forEach((slot,index)=>place(slot.cell,cols[index]))}});const TREE_EXPORT={prepareExport(options={}){const{scope="visible",values="display",signal}=options;if(this.destroyed||!["visible","selected","all"].includes(scope)||!["raw","display"].includes(values)||signal!==undefined&&!(signal instanceof AbortSignal))
76
+ throw new Error("CanopyX: invalid tree export.");const ids=options.columns??this.columns.filter(column=>!column.hidden).map(column=>column.id);const columns=Array.isArray(ids)?ids.map(id=>this.columns.find(column=>column.id===id)):[];if(!columns.length||columns.some(column=>!column)||new Set(ids).size!==ids.length)throw new Error("CanopyX: invalid export columns.");const rows=[],add=(node,level,path)=>{if(!node.detail)rows.push({id:node.id,level,path,node:{...node}})};const sort=this.sortState,column=sort&&this.columns.find(item=>item.id===sort.column),index=this.columns.indexOf(column);const key=node=>sortKey(this.cellOf(node,column,index),column);const raw=(nodes,level,path)=>(column&&!this.queryAware?nodes.map((node,at)=>[key(node),at,node])
77
+ .sort((a,b)=>compareKeys(a[0],b[0],sort.direction==="desc"?-1:1)||a[1]- b[1]).map(entry=>entry[2]):nodes)
78
+ .forEach(node=>{const at=[...path,node.id];add(node,level,at);if(node.children)raw(node.children,level+1,at)});const walk=parent=>this.modelChildren(parent).forEach(w=>{if(scope==="all"||this.selected.has(w))add(w.h,w.level,this.pathOf(w));walk(w)});if(scope==="visible")this.rows.forEach(w=>{if(!w.status)add(w.h,w.level,this.pathOf(w))});else if(scope==="all"&&this.root.inlineItems)raw(this.root.inlineItems,1,[]);else walk(this.root);const request=Object.freeze({kind:"tree",scope,presentation:"text",values,revision:this.datasetRevision,recordCount:rows.length,columns:Object.freeze(columns.map(({id,title,kind})=>Object.freeze({id,title,kind}))),locale:this.lang,timeZone:this.local?"local":"utc"}),grid=this;return Object.freeze({request,rows:async function*(more){const linked=AbortSignal.any([grid.lifetime.signal,signal,more?.signal].filter(Boolean));await exportPartReady();yield*EXPORT_IMPL.treeRows(grid,request,rows,linked)}})},exportAs(format,options){return exportAs(this,format,options)}};Object.assign(TreeGrid.prototype,{outlineTable(){const cols=this.visibleColumns(),table=h("table","cx-outline-table"),head=h("tr"),body=h("tbody");cols.forEach((column)=>setText(head.appendChild(h("th")),column.title));table.appendChild(h("thead")).appendChild(head);table.appendChild(body);this.rows.forEach((w)=>{if(w.status){return}
79
+ const tr=body.appendChild(h("tr")),indent=(td)=>{td.style.paddingLeft=((w.level-1)*14+4)+ "px";return td};if(w.h.detail){const td=indent(tr.appendChild(h("td")));td.colSpan=cols.length;this.renderDetail(w.h,td,true);return}
80
+ cols.forEach((column,i)=>{const index=this.columns.indexOf(column);const value=this.cellOf(w.h,column,index);const text=cellText(value,column,this.fmt);const td=tr.appendChild(h("td")),content=h("span");if(i===0)indent(td);const slot={};try{if(!column.render||column.render(w.h,content,new HostCellContext(slot,column.id,w.level,w.expanded,index))!==true){const badges=(i===0?w.h.badges||[]:[]).concat(isCellObject(value)?value.badges||[]:[]);content.appendChild(detailCell("span",Object.assign({},isCellObject(value)?value:{},{text,badges}),this.fmt))}
81
+ td.appendChild(content.cloneNode(true))}finally{disposeHostSlot(slot)}})});return table}});const TREE_DETAILS={paintNodeRow:TreeGrid.prototype.paintNodeRow,active:null};Object.assign(TreeGrid.prototype,{focusRing:focusDrawerTitle,hiddenFieldCount(){return this.columns.filter(column=>column.hidden||column.fitHidden).length},paintNodeRow(rowEl,w){TREE_DETAILS.paintNodeRow.call(this,rowEl,w);const slot=rowEl._cells[0],count=this.phone&&this.fitReady&&this.hiddenFieldCount();let button=slot.hiddenFields;if(!count){button?.remove();slot.hiddenFields=null;return}
82
+ if(!button){button=slot.hiddenFields=gridButton("",()=>this.openDetails(button.dataset.cxRecord).catch(error=>this.emit("error",{error})));button.classList.add("cx-hidden-fields");button.tabIndex=-1;button.addEventListener("click",event=>event.stopPropagation())}
83
+ if(button.parentNode!==slot.cell)slot.cell.appendChild(button);button.dataset.cxRecord=w.h.id;button.setAttribute("aria-label",this.labels.gridDetails);setText(button,"+"+count)},async openDetails(id,options){const node=this.keyMap.get(id)?.h;if(node&&this.recordNeeded(node))await this.requirePart("record-panel");return this.showDetails(id,options)},showDetails(id,options={}){const rows=this.rows.filter(w=>!w.status&&!w.h.detail),returnFocus=options.returnFocus||document.activeElement,labels=this.labels,owner=this.dataLifetime;let index=rows.findIndex(w=>w.key===id);const loose=index<0?options.node||this.keyMap.get(id)?.h:null;if(index<0&&!loose||this.destroyed)throw new Error("CanopyX: open the details of a loaded node.");if(typeof this.opts.onDetails==="function"){const node=JSON.parse(JSON.stringify(loose||rows[index].h)),controller=new AbortController();owner.signal.addEventListener("abort",()=>controller.abort(),{once:true});return Promise.resolve(this.opts.onDetails({node,signal:controller.signal,returnFocus}))}
84
+ if(TREE_DETAILS.active){TREE_DETAILS.active._replaced=true;TREE_DETAILS.active.close();TREE_DETAILS.active.remove()}
85
+ const dialog=TREE_DETAILS.active=this.recordDrawer=h("dialog","cx-host cx-tree-tools cx-drawer"),head=h("div","cx-drawer-h"),title=h("h4"),body=h("div","cx-drawer-body");dialog._returnFocus=returnFocus;dialog.setAttribute("data-cx-theme",this.host.getAttribute("data-cx-theme"));const theme=getComputedStyle(this.host);dialog.style.colorScheme=theme.colorScheme;for(const name of theme)if(name.startsWith("--cx-"))dialog.style.setProperty(name,theme.getPropertyValue(name));title.id=this.id+"-record-title";title.tabIndex=-1;title.setAttribute("aria-level","2");dialog.setAttribute("aria-labelledby",title.id);const button=(icon,label,run)=>{const item=gridDecorateButton(gridButton("",run),icon,true);item.classList.add("icon");item.setAttribute("aria-label",labels[label]);return item};const step=position=>{paint(position);focusDrawerTitle(title)};const previous=button("up","gridPreviousRecord",()=>step(index-1)),next=button("down","gridNextRecord",()=>step(index+1));head.append(h("div"),previous,next,button("close","gridCloseRecord",()=>dialog.close()));head.firstChild.appendChild(title);dialog.append(head,body);let shown=loose,paints=null;const paint=position=>{if(!loose&&(position<0||position>=rows.length))return;if(!loose){index=position;shown=rows[index].h}
86
+ const node=shown;paints?.abort();paints=new AbortController();setText(title,node.label);dialog._cxRecord=node;dialog.setAttribute("data-cx-record",node.id);dialog.setAttribute("data-cx-view",this.view.id);previous.disabled=!!loose||!index;next.disabled=!!loose||index===rows.length-1;this.paintDrawerBody(node,body,dialog,{index:loose?null:index,signal:paints.signal});dialog.dispatchEvent(new CustomEvent("cx-drawer-paint",{detail:{id:node.id,index:loose?null:index}}))};dialog._cxPaint=node=>{shown=node;paint(index)};dialog.addEventListener("keydown",event=>{if(event.defaultPrevented)return;if(event.key==="Escape"){event.preventDefault();dialog.close()}
87
+ else if((event.key==="ArrowUp"||event.key==="ArrowDown")&&!event.target.matches("input,textarea,select,[role=tab]")&&!event.target.closest(".cx-data-grid,.cx-record-nested")){event.preventDefault();step(index +(event.key==="ArrowUp"?-1:1))}});const close=()=>dialog.close();owner.signal.addEventListener("abort",close,{once:true});dialog.addEventListener("close",()=>{owner.signal.removeEventListener("abort",close);paints?.abort();dialog.remove();if(TREE_DETAILS.active===dialog)TREE_DETAILS.active=null;if(this.recordDrawer!==dialog||this.destroyed)return;this.recordDrawer=null;if(TREE_DETAILS.active||dialog._replaced)return;const key=shown.id,row=this.rows.find(w=>w.key===key);if(returnFocus?.isConnected&&(!returnFocus.dataset.cxRecord||returnFocus.dataset.cxRecord===id))returnFocus.focus({preventScroll:true});else if(row)this.setFocus(row,true);else this.grid.focus({preventScroll:true})},{once:true});RECORD_IMPL.decorate?.(this,dialog,{head,identity:head.firstChild,title,body,options});document.body.appendChild(dialog);const phone=this.host.clientWidth<=640;dialog.classList.toggle("cx-phone",phone);if(phone)dialog.showModal();else dialog.show();paint(index);focusDrawerTitle(title);return dialog},paintDrawerBody(node,body,dialog,context){if(RECORD_IMPL.paint&&this.recordNeeded(node))return RECORD_IMPL.paint(this,node,body,dialog,context);const sections=new Map();body.replaceChildren();this.columns.forEach((column,position)=>{if(!position||column.drawer===false)return;const name=column.section||this.labels.gridDetailsSection;if(!sections.has(name)){const heading=h("div","cx-drawer-s"),list=h("dl","cx-dl");setText(heading,name);sections.set(name,list);body.append(heading,list)}
88
+ const term=h("dt"),value=h("dd");setText(term,column.title);term.setAttribute("data-cx-field",column.id);value.setAttribute("data-cx-field",column.id);this.paintDrawerValue(column,node,value,position,context);sections.get(name).append(term,value)})},paintDrawerValue(column,node,value,position,context){const cell=this.cellOf(node,column,position),object=isCellObject(cell);if(typeof column.render==="function"){try{if(column.render(node,value,{column:column.id,level:1,expanded:false,index:position,signal:context.signal,onDispose:cleanup=>{if(context.signal.aborted)cleanup();else context.signal.addEventListener("abort",cleanup,{once:true})}})===true)return}
89
+ catch(error){this.emit("error",{error})}}
90
+ const text=cellText(cell,column,this.fmt),span=h("span");applyTone(span,"cx-drawer-text" +(text?"":" p-missing"),toneOf(object?cell.tone:null));setText(span,text||"—");if(object&&cell.title)span.title=cell.title;value.appendChild(span);if(object)for(const badge of cell.badges||[])value.appendChild(badgeElement(badge))}});const TREE_EXPORT_PART=definePart(TreeGrid,"export","export part",()=>({DataGrid:TreeGrid,EXPORT_IMPL,h,setText,gridButton,gridOption,fill,numberFormat,gridExportField,gridOperationActive,formatting,cellValue,cellText,isCellObject,exportTimeout,exportFormat,EXPORT_FORMATS}));function loadExportPart(){return loadPart(TREE_EXPORT_PART)}
91
+ Object.assign(TreeGrid.prototype,TREE_EXPORT,{async renderGridExport(panel){if(panel.firstChild)return;setText(panel,this.labels.loading);try{await loadExportPart();if(!this.destroyed&&panel.isConnected){setText(panel,"");this.renderGridExport(panel);this.controlFlyouts.forEach(item=>item.position())}}
92
+ catch(error){if(this.destroyed||!panel.isConnected)return;panel.replaceChildren(gridButton(fill(this.labels.loadError,{error:error.message}),()=>{panel.replaceChildren();this.renderGridExport(panel)}));this.emit("error",{error})}},exportText(...args){return loadExportPart().then(()=>EXPORT_IMPL.exportText.apply(this,args))}});installed.add(context.TreeGrid.prototype)}};(global.CanopyXParts||=[]).push(["tree-tools",part])})(typeof window!=="undefined"?window:globalThis);