@evotecit/canopyx 0.3.11 → 0.3.13

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.
@@ -44,9 +44,10 @@ if(typeof value==="boolean"){return value?fmt.labels.yes:fmt.labels.no}
44
44
  if(typeof value==="number"&&kind==="number"){return numberText(value,fmt.lang,format)}
45
45
  if(typeof value==="string"&&kind==="datetime"){return formatDate(value,fmt)}
46
46
  return String(value)}
47
- function cellText(cell,column,fmt){if(isCellObject(cell)&&typeof cell.text==="string"){return cell.text}
47
+ function cellText(cell,column,fmt){const raw=cellValue(cell);if(typeof raw==="string"&&Object.hasOwn(column.valueLabels||{},raw))return column.valueLabels[raw];if(isCellObject(cell)&&typeof cell.text==="string"){return cell.text}
48
48
  return formatValue(cellValue(cell),column.kind,fmt,column.format)}
49
- const collator=new Intl.Collator(undefined,{numeric:true,sensitivity:"base"});const safeGridNumber=value=>Number.isFinite(value)&&Math.abs(value)<=Number.MAX_SAFE_INTEGER;function sortKey(cell,column){let value=isCellObject(cell)&&(typeof cell.sort==="string"||safeGridNumber(cell.sort))?cell.sort:cellValue(cell);if((value===null||value==="")&&isCellObject(cell)&&typeof cell.text==="string"&&cell.text!==""){value=cell.text}
49
+ const collator=new Intl.Collator(undefined,{numeric:true,sensitivity:"base"});const safeGridNumber=value=>Number.isFinite(value)&&Math.abs(value)<=Number.MAX_SAFE_INTEGER;function sortKey(cell,column){if(column.valueOrder?.length){const raw=cellValue(cell);if(raw==null)return{rank:2,value:0};const at=typeof raw==="string"?column.valueOrder.indexOf(raw):-1;return{rank:1,category:at<0?column.valueOrder.length:at,type:typeof raw,value:raw}}
50
+ let value=isCellObject(cell)&&(typeof cell.sort==="string"||safeGridNumber(cell.sort))?cell.sort:cellValue(cell);if((value===null||value==="")&&isCellObject(cell)&&typeof cell.text==="string"&&cell.text!==""){value=cell.text}
50
51
  if(value===null||value===""){return{rank:2,value:0}}
51
52
  if(typeof value==="boolean"){return{rank:0,value:value?1:0}}
52
53
  if(typeof value==="number"){return{rank:0,value}}
@@ -54,7 +55,20 @@ if(column.kind==="datetime"){const time=Date.parse(value);if(!isNaN(time)){retur
54
55
  return{rank:1,value:String(value)}}
55
56
  function compareKeys(a,b,direction){if(a.rank!==b.rank){return a.rank-b.rank}
56
57
  if(a.rank===2){return 0}
57
- const order=a.rank===0?(a.value<b.value?-1:a.value>b.value?1:0):collator.compare(a.value,b.value);return order*direction}
58
+ const order=a.category!==undefined?a.category-b.category||
59
+ (a.type<b.type?-1:a.type>b.type?1:a.value<b.value?-1:a.value>b.value?1:0):
60
+ a.rank===0?(a.value<b.value?-1:a.value>b.value?1:0):collator.compare(a.value,b.value);return order*direction}
61
+ function columnNumericTone(column,raw){return typeof raw==="number"&&Number.isFinite(raw)?column.numericTones?.find(rule=>
62
+ rule.operator==="atMost"?raw<=rule.value:rule.operator==="atLeast"?raw>=rule.value:
63
+ rule.operator==="below"?raw<rule.value:raw>rule.value):undefined}
64
+ function columnValueTone(column,cell){const raw=cellValue(cell);return columnNumericTone(column,raw)?.tone||(typeof raw==="string"&&Object.hasOwn(column.valueTones||{},raw)?column.valueTones[raw]:undefined)}
65
+ function validateColumnValues(column){const fail=()=>{throw new Error("CanopyX: invalid column value labels, order, tones or line limit.")};const tone=value=>typeof value==="string"&&/^[a-z][a-z0-9-]{0,31}$/.test(value) && !value.endsWith("-bg");
66
+ if(column.maxLines!==undefined&&(!Number.isInteger(column.maxLines)||column.maxLines<1||column.maxLines>12))fail();for(const name of["valueLabels","valueTones"])if(column[name]!==undefined){const map=column[name];if(column.kind!=="text"||!map||typeof map!=="object"||Array.isArray(map)||Object.keys(map).length>512||
67
+ Object.entries(map).some(([key,value])=>key.length>4096||(name==="valueTones"?!tone(value):typeof value!=="string"||value.length>4096)))fail()}
68
+ if(column.valueOrder!==undefined&&(column.kind!=="text"||!Array.isArray(column.valueOrder)||column.valueOrder.length>512||
69
+ new Set(column.valueOrder).size!==column.valueOrder.length||column.valueOrder.some(value=>typeof value!=="string"||value.length>4096)))fail();if(column.numericTones!==undefined&&(column.kind!=="number"||!Array.isArray(column.numericTones)||column.numericTones.length>32||
70
+ column.numericTones.some(rule=>!rule||!["atMost","atLeast","below","above"].includes(rule.operator)||!Number.isFinite(rule.value)||
71
+ !tone(rule.tone)||typeof rule.label!=="string"||!rule.label.trim()||rule.label.length>4096)))fail()}
58
72
  function fill(template,values){return template.replace(/\{(\w+)\}/g, (match, name) => (values && Object.hasOwn(values, name) ? String(values[name]) : match));
59
73
  }
60
74
  const pluralRules=new Map();function plural(template,count,lang){if(!template.startsWith("["))return template;const forms={};for(const match of template.matchAll(/\[(zero|one|two|few|many|other)\]([^[]*)/g)) forms[match[1]] = match[2];
@@ -117,7 +131,8 @@ if(column.kind==="datetime"){const date=typeof value==="string"&&/^\d{4}-\d\d-\d
117
131
  if(!Number.isFinite(date))
118
132
  throw new Error("CanopyX: date grid cells need ISO dates with an explicit time zone.");return date}
119
133
  if(typeof value!=="string"&&typeof value!=="boolean")throw new Error("CanopyX: text grid cells need strings or booleans.");return value}
120
- function cellMatches(cell,predicate,column){const scalar=gridScalar(cell,column),op=predicate.operator;if(op==="isNull")return scalar===null;if(op==="isNotNull")return scalar!==null;if(scalar===null)return false;const normalize=value=>column.kind==="text"&&typeof value==="string"?foldText(value):value;const value=normalize(scalar),values=predicate.values.map(operand=>normalize(gridScalar(operand,column))),operand=values[0];switch(op){case "eq":return value===operand;case "ne":return value!==operand;case "in":return values.includes(value);case "contains":return String(value).includes(String(operand));case "startsWith":return String(value).startsWith(String(operand));case "gt":return value>operand;case "ge":return value>=operand;case "lt":return value<operand;case "le":return value<=operand}
134
+ function gridExactTokens(column){return column.kind==="text"&&(column.valueOrder?.length||Object.keys(column.valueLabels||{}).length)}
135
+ function cellMatches(cell,predicate,column){const scalar=gridScalar(cell,column),op=predicate.operator;if(op==="isNull")return scalar===null;if(op==="isNotNull")return scalar!==null;if(scalar===null)return false;const normalize=value=>column.kind==="text"&&!gridExactTokens(column)&&typeof value==="string"?foldText(value):value;const value=normalize(scalar),values=predicate.values.map(operand=>normalize(gridScalar(operand,column))),operand=values[0];switch(op){case "eq":return value===operand;case "ne":return value!==operand;case "in":return values.includes(value);case "contains":return String(value).includes(String(operand));case "startsWith":return String(value).startsWith(String(operand));case "gt":return value>operand;case "ge":return value>=operand;case "lt":return value<operand;case "le":return value<=operand}
121
136
  return false}
122
137
  function validateGridRows(rows,columns,ids=new Set()){if(!Array.isArray(rows))throw new Error("CanopyX: grid rows must be an array.");const declared=new Map(columns.map(column=>[column.id,column]));for(const row of rows){requireIdentifier(row&&row.id,"grid row ID");if(ids.has(row.id))throw new Error("CanopyX: duplicate grid row ID "+row.id);ids.add(row.id);if(!row.cells||typeof row.cells!=="object"||Array.isArray(row.cells))
123
138
  throw new Error("CanopyX: invalid flat row fields.");gridDecoration(row.tone,row.className);for(const id of Object.keys(row.cells)){if(!declared.has(id))throw new Error("CanopyX: undeclared grid column "+id);const cell=row.cells[id];if(isCellObject(cell)){if(Array.isArray(cell)||
@@ -191,7 +206,7 @@ return checkDocument(await response.json(),type)}catch(error){if(timedOut)throw
191
206
  class TreeGrid{constructor(host,options){const view=checkDocument(options.view,"view");requireIdentifier(view.id,"view ID");if(view.columns.some(column=>column.format!==undefined))throw new Error("CanopyX: number formats apply to flat grids only.");this.host=host;this.view=view;this.opts=options;for(const name of["isSelectable","beforeSelect","sanitizeHtml"]){if(options[name]!==undefined&&typeof options[name]!=="function")throw new Error("CanopyX: "+name+" must be a function.")}
192
207
  this.id="cx" + ++instanceSeq;this.lifetime=new AbortController();this.source=options.source||sourceFor(view,{signal:this.lifetime.signal,timeoutMs:options.requestTimeoutMs});this.queryAware=this.source.queryAware===true;this.dataLifetime=new AbortController();this.acceptedQuery=Object.freeze({version:1,sort:null,filters:Object.freeze([])});this.datasetRevision=null;this.rowH=view.rowHeight||28;this.pageSize=view.pageSize||100;this.retainedNodeLimit=options.retainedNodeLimit===undefined?1024:options.retainedNodeLimit;if(!validStructuralCount(this.retainedNodeLimit))throw new Error("CanopyX: retainedNodeLimit must be a nonnegative 32-bit integer.");this.inactiveNodeLimit=options.inactiveNodeLimit===undefined?4096:options.inactiveNodeLimit;if(!validStructuralCount(this.inactiveNodeLimit))throw new Error("CanopyX: inactiveNodeLimit must be a nonnegative 32-bit integer.");this.multi=view.selection==="multiple";this.lang=document.documentElement.lang||undefined;this.labels=labelsFor(view.labels,options.labels);this.tools=Object.assign({},view.toolbar,options.toolbar);if(Object.entries(this.tools).some(([name,value])=>!/^(search|filters|columns|views|export|more|matches|layout)$/.test(name) || typeof value !== "boolean"))
193
208
  throw new Error("CanopyX: toolbar options are booleans by control name.");this.local=view.timeZone==="local";this.fmt=formatting(this.lang,this.local,this.labels);this.kind="tree";this.plugins=viewPlugins(options,this.kind);const renderers=hostRenderers(options.renderers||{},view.columns,this.plugins);if(!options.formatLink!==!options.parseLink){throw new Error("CanopyX: formatLink and parseLink define one link scheme and are given together.")}
194
- this.columns=view.columns.map((column,index)=>({...column,hidden:index>0&&!!column.hidden,render:Object.hasOwn(renderers,column.id)?renderers[column.id]:null}));this.columns.forEach(prepareWidth);this.keyMap=new Map();this.root={key:null,h:null,parent:null,level:0,idx:0,expanded:true,children:null,total:null,next:null,loading:false,error:null};if(!options.source&&(!view.source||view.source.kind==="inline")){this.root.inlineItems=view.roots||[]}
209
+ this.columns=view.columns.map((column,index)=>({...column,hidden:index>0&&!!column.hidden,render:Object.hasOwn(renderers,column.id)?renderers[column.id]:null}));this.columns.forEach(prepareWidth);this.columns.forEach(validateColumnValues);this.keyMap=new Map();this.root={key:null,h:null,parent:null,level:0,idx:0,expanded:true,children:null,total:null,next:null,loading:false,error:null};if(!options.source&&(!view.source||view.source.kind==="inline")){this.root.inlineItems=view.roots||[]}
195
210
  this.rows=[];this.tops=[0];this.total=0;this.version=1;this.rendered=new Map();this.pool=[];this.focused=null;this.selected=new Set();this.anchor=null;this.filter=null;this.declaredFilter=null;this.filterExpand=false;this.activeFilters=new Set();this.sortState=null;this.typeBuf="";this.typeAt=0;this.rafId=0;this.iconTemplates=this.buildIcons(view.icons||{});this.initializing=true;this.prepareViewModes();this.build();this.buildToolbar();if(view.deepLink)loadPart(LINKS).catch(()=>{});this.ready=this.modesReady?Promise.all([this.init(),this.modesReady]).then(([result])=>result):this.init()}
196
211
  async search(query,limit){if(this.destroyed)throw new DOMException("Grid was destroyed.","AbortError");const navigation=navigationScope(this,this.dataLifetime.signal);try{const result=await navigation.wait(this.source.search(query,limit,this.sourceRequest(this.dataLifetime.signal)));if(navigation.cancelled())throw new DOMException("Search snapshot was retired.","AbortError");if(this.queryAware)snapshotRevision(result,this.datasetRevision);return validateSearchResult(result)}finally{navigation.dispose()}}
197
212
  buildIcons(icons){const templates=new Map();Object.keys(icons).forEach((key)=>{const holder=h("span","cx-icon");holder.setAttribute("aria-hidden","true");hostHtml(holder,icons[key],this.opts.sanitizeHtml,"icon");// trusted host SVG, declared once per view
@@ -259,7 +274,7 @@ function snapshotRevision(value,expected){requireIdentifier(value&&value.revisio
259
274
  Object.assign(TreeGrid.prototype,{getQuery(){return{version:1,sort:this.sortState&&Object.assign({},this.sortState),filters:Array.from(this.activeFilters)}},sourceRequest(signal){return this.queryAware?{signal:signal||this.dataLifetime.signal,query:this.acceptedQuery,revision:this.datasetRevision}:{signal}},syncQueryControls(){this.toolbar.querySelectorAll("[data-cx-filter]").forEach(input=>{input.checked=this.activeFilters.has(input.getAttribute("data-cx-filter"))})},querySortHeader(id){const query=this.pendingQuery||this.acceptedQuery,state=query.sort&&query.sort.column===id?query.sort.direction:null;this.sort(id,state==="asc"?"desc":state==="desc"?null:"asc").catch(()=>{})}});Object.assign(TreeGrid.prototype,{retireWrapper(w){w._invalidated=true;this.retirePage(w);if(this.inlineRetained&&this.inlineRetained.get(w.key)===w)this.inlineRetained.delete(w.key);if(this.inactiveCache)this.inactiveCache.delete(w);if(this.keyMap.get(w.key)===w)this.keyMap.delete(w.key);w.children=null;w.inlineCache=null;w.inlineOrder=null;const selected=this.selected.delete(w);if(this.anchor===w)this.anchor=null;return selected?w:null}});Object.assign(TreeGrid.prototype,{build(){const host=this.host;host.classList.add("cx-host");if(!host.hasAttribute("data-cx-theme")){host.setAttribute("data-cx-theme","auto")}
260
275
  host.style.setProperty("--cx-row-h",this.rowH+"px");this.setTreeColumnPinned(this.view.pinTreeColumn);this.toolbar=h("div","cx-toolbar");this.toolbar.hidden=true;const grid=this.grid=h("div","cx-grid");grid.id=this.id;grid.setAttribute("role","treegrid");grid.setAttribute("aria-label",this.view.label);if(this.multi){grid.setAttribute("aria-multiselectable","true")}
261
276
  this.head=h("div","cx-head");this.head.setAttribute("role","rowgroup");this.headRow=h("div","cx-hrow");this.headRow.setAttribute("role","row");this.headRow.setAttribute("aria-rowindex","1");this.head.appendChild(this.headRow);this.canvas=h("div","cx-canvas");this.canvas.setAttribute("role","rowgroup");grid.appendChild(this.head);grid.appendChild(this.canvas);this.live=h("div","cx-live cx-sr-only");this.live.setAttribute("aria-live","polite");this.outline=h("div","cx-outline");host.appendChild(this.toolbar);host.appendChild(grid);host.appendChild(this.live);host.appendChild(this.outline);this.buildHeader();this.onScroll=()=>{this.scheduleRender();this.stateChanged()};this.onPrint=()=>{const table=this.outlineElement();this.outline.replaceChildren(...table?[table]:[])};grid.addEventListener("scroll",this.onScroll,{passive:true});grid.addEventListener("click",(e)=>this.onClick(e));grid.addEventListener("dblclick",(e)=>this.onDblClick(e));grid.addEventListener("pointerover",(e)=>this.cellTip(e));grid.addEventListener("keydown",(e)=>this.onKey(e));this.canvas.addEventListener("focusin",(e)=>{const rowEl=e.target.closest(".cx-row");if(rowEl&&rowEl._w&&this.focused!==rowEl._w){this.focusRevision=(this.focusRevision||0)+ 1;this.focused=rowEl._w;this.scheduleRender()}});this.canvas.addEventListener("focusout",(e)=>this.settleCell(e.relatedTarget));global.addEventListener("beforeprint",this.onPrint);this.onHash=(e)=>{const href=global.location.href;const last=this.locationEvent;this.locationEvent=last&&last.href===href&&last.type!==e.type?null:{href,type:e.type};if(this.locationEvent)this.readLocation()};global.addEventListener("hashchange",this.onHash);global.addEventListener("popstate",this.onHash);const viewWidth=()=>{if(grid.clientWidth)host.style.setProperty("--cx-view-w",grid.clientWidth+"px")};viewWidth();this.resizeObserver=new ResizeObserver(()=>{viewWidth();this.scheduleRender()});this.resizeObserver.observe(grid)},visibleColumns(){return this.columns.filter((column)=>!column.hidden)},buildHeader(){const active=document.activeElement;const focusedColumn=active&&this.headRow.contains(active)?active.closest(".cx-hcell").getAttribute("data-cx-column"):null;const focusedResize=active&&active.classList.contains("cx-resize");const nextCols=this.visibleColumns();const layoutChanged=!this.cols||this.cols.length!==nextCols.length||nextCols.some((column,i)=>column!==this.cols[i]);this.cols=nextCols;this.columnIndex=this.cols.map((column)=>this.columns.indexOf(column));if(layoutChanged){this.layout=(this.layout||0)+ 1;this.version++}
262
- this.grid.setAttribute("aria-colcount",String(this.cols.length));this.headRow.textContent="";this.headCells=this.cols.map((column,i)=>{const cell=h("div","cx-hcell cx-kind-" +(column.kind||"text"));cell.setAttribute("role","columnheader");cell.setAttribute("aria-label",column.title);cell.setAttribute("data-cx-column",column.id);cell.setAttribute("aria-colindex",String(i+1));if(column.sortable){const sorted=this.sortState&&this.sortState.column===column.id?this.sortState.direction:null;cell.setAttribute("aria-sort",sorted==="asc"?"ascending":sorted==="desc"?"descending":"none");const button=h("button","cx-sort");button.type="button";setText(button,column.title);button.addEventListener("click",(event)=>this.queryAware?this.querySortHeader(column.id,event):this.sort(column.id,sorted==="asc"?"desc":sorted==="desc"?null:"asc"));cell.appendChild(button)}else{const title=h("span","cx-htext");setText(title,column.title);cell.appendChild(title)}
277
+ this.grid.setAttribute("aria-colcount",String(this.cols.length));this.headRow.textContent="";this.headCells=this.cols.map((column,i)=>{const cell=h("div","cx-hcell cx-kind-" +(column.kind||"text"));cell.setAttribute("role","columnheader");cell.setAttribute("aria-label",column.title);if(column.headerDescription)cell.setAttribute("aria-description",column.headerDescription);cell.title=column.headerDescription??column.title;cell.setAttribute("data-cx-column",column.id);cell.setAttribute("aria-colindex",String(i+1));if(column.sortable){const sorted=this.sortState&&this.sortState.column===column.id?this.sortState.direction:null;cell.setAttribute("aria-sort",sorted==="asc"?"ascending":sorted==="desc"?"descending":"none");const button=h("button","cx-sort");button.type="button";button.title=column.headerDescription??column.title;setText(button,column.title);button.addEventListener("click",(event)=>this.queryAware?this.querySortHeader(column.id,event):this.sort(column.id,sorted==="asc"?"desc":sorted==="desc"?null:"asc"));cell.appendChild(button)}else{const title=h("span","cx-htext");title.title=column.headerDescription??column.title;setText(title,column.title);cell.appendChild(title)}
263
278
  const grip=h("span","cx-resize");grip.setAttribute("aria-label",fill(this.labels.resizeColumn,{column:column.title}));grip.tabIndex=0;grip.setAttribute("role","separator");grip.setAttribute("aria-orientation","vertical");grip.setAttribute("aria-valuemin",column.minW);grip.setAttribute("aria-valuemax",column.maxW);grip.addEventListener("keydown",(e)=>{if(!["ArrowLeft","ArrowRight","Home"].includes(e.key))return;e.preventDefault();e.stopPropagation();column.width=columnWidth(column,e.key==="Home"?40:column.width +(e.key==="ArrowLeft"?-1:1)*(e.shiftKey?50:10));this.applyWidths();this.stateChanged()});grip.addEventListener("pointerdown",(e)=>this.startResize(e,column));cell.appendChild(grip);this.headRow.appendChild(cell);return cell});this.applyWidths();if(focusedColumn){const index=this.cols.findIndex((c)=>c.id===focusedColumn);const button=index>=0?this.headCells[index].querySelector(focusedResize?".cx-resize":".cx-sort"):null;if(button){button.focus()}}},rowCount(){return this.rows.length},rowItem(index){return this.rows[index]},rowTop(index){return this.tops[index]},rowAt(y){const tops=this.tops;let lo=0;let hi=this.rows.length-1;while(lo<hi){const mid=(lo+hi+1)>>1;if(tops[mid]<=y){lo=mid}else{hi=mid-1}}
264
279
  return Math.max(0,lo)},indexOf(w){const i=w?w._ri:undefined;return i!==undefined&&this.rows[i]===w?i:-1},render(){let measured=false;for(let pass=0;!this.destroyed;pass++){this.renderPass();if(!this.measureDetails())break;measured=true;if(pass===3){this.scheduleRender();break}}
265
280
  return measured}});function columnWidth(column,width){return Math.min(column.maxW,Math.max(column.minW,width))}
@@ -309,13 +324,13 @@ this.paintSlot(slot,node,this.cols[i],this.columnIndex[i],w)}},paintRowState(row
309
324
  const expander=this.expandable(w)?"cx-exp":"cx-exp cx-leaf";if(slot.expCls!==expander){slot.exp.className=expander;slot.expCls=expander}
310
325
  const key=w.h.icon&&this.iconTemplates.has(w.h.icon)?w.h.icon:null;if(slot.iconKey!==key){if(slot.iconEl){slot.iconEl.remove()}
311
326
  slot.iconEl=key?this.iconTemplates.get(key).cloneNode(true):null;if(slot.iconEl){slot.cell.insertBefore(slot.iconEl,slot.content)}
312
- slot.iconKey=key}},cellTip(event){const cell=event.target.closest?.(".cx-cell"),row=cell?.parentNode._kind==="node"&&cell.parentNode._w;const column=row&&!row.status&&this.cols[[...cell.parentNode.children].indexOf(cell)],tip=column?.tooltip;const source=tip==="auto"?column:this.columns.find(item=>item.id===tip);if(!source||cell.title&&!cell._cxTip)return;cell._cxTip=true;cell.title=tip!=="auto"||[cell,...cell.querySelectorAll("*")].some(item=>item.scrollWidth>item.clientWidth)?
327
+ slot.iconKey=key}},cellTip(event){const cell=event.target.closest?.(".cx-cell"),row=cell?.parentNode._kind==="node"&&cell.parentNode._w;const column=row&&!row.status&&this.cols[[...cell.parentNode.children].indexOf(cell)],tip=column?.tooltip;const source=tip==="auto"?column:this.columns.find(item=>item.id===tip);if(!source||cell.title&&!cell._cxTip)return;cell._cxTip=true;cell.title=tip!=="auto"||[cell,...cell.querySelectorAll("*")].some(item=>item.scrollWidth>item.clientWidth||item.scrollHeight>item.clientHeight)?
313
328
  cellText(this.cellOf(row.h,source,this.columns.indexOf(source)),source,this.fmt):""},paintSlot(slot,node,column,index,w){const value=this.cellOf(node,column,index);if(slot.cell._cxTip){slot.cell._cxTip=false;slot.cell.removeAttribute("title");slot.title=null}
314
329
  const hosted=column.render?this.paintHostSlot(slot,node,column,index,w):null;if(hosted==="host"){return}
315
330
  const decorated=hosted==="decorated";const text=cellText(value,column,this.fmt);if(slot.text.data!==text){slot.text.data=text}
316
- const object=isCellObject(value);const tone=object?toneOf(value.tone):NO_TONE;const cls=slot.base+tone.cls;if(slot.cls!==cls){if(decorated){if(tone.cls)slot.cell.className +=tone.cls}else{slot.cell.className=cls}
331
+ const object=isCellObject(value);const rule=columnNumericTone(column,cellValue(value));const tone=toneOf(columnValueTone(column,value)||(object?value.tone:null));const cls=slot.base+tone.cls;if(slot.cls!==cls){if(decorated){if(tone.cls)slot.cell.className +=tone.cls}else{slot.cell.className=cls}
317
332
  slot.cls=cls}
318
- toneColors(slot.cell,tone);const title=object&&value.title?value.title:decorated?null:otherZone(value,column,this.fmt);if(slot.title!==title){if(title){slot.cell.title=title}else{slot.cell.removeAttribute("title")}
333
+ toneColors(slot.cell,tone);const title=object&&value.title?value.title:decorated?null:rule?.label||otherZone(value,column,this.fmt);setAttr(slot.cell,"aria-description",rule?.label||null);if(slot.title!==title){if(title){slot.cell.title=title}else{slot.cell.removeAttribute("title")}
319
334
  slot.title=title}
320
335
  this.paintBadges(slot,(index===0&&node.badges)||null,object&&value.badges?value.badges:null)},paintBadges(slot,first,second){const count=(first?first.length:0)+(second?second.length:0);for(let k=0;k<count;k++){const badge=first&&k<first.length?first[k]:second[k -(first?first.length:0)];let span=slot.badges[k];if(!span){span=slot.content.appendChild(h("span"));span._text=span.appendChild(document.createTextNode(""));slot.badges.push(span)}
321
336
  const tone=toneOf(badge.tone||"neutral");if(span._cls!==tone.cls){applyTone(span,"cx-badge",tone);span._cls=tone.cls}
@@ -504,7 +519,7 @@ if(active>=0){list.children[active].setAttribute("aria-selected","false")}
504
519
  active=active<0?(delta<0?hits.length-1:0):(active+delta+hits.length)%hits.length;const item=list.children[active];item.setAttribute("aria-selected","true");input.setAttribute("aria-activedescendant",item.id);item.scrollIntoView({block:"nearest"})};input.addEventListener("input",()=>{cancelNavigation();sequence++;clearTimeout(timer);hits=[];close();timer=setTimeout(run,150)});input.addEventListener("keydown",(e)=>{if(e.defaultPrevented||e.isComposing)return;if(e.key==="ArrowDown"||e.key==="ArrowUp"){move(e.key==="ArrowDown"?1:-1)}else if(e.key==="Enter"){if(!list.hidden){choose(active>=0?active:0)}}else if(e.key==="Escape"){cancelNavigation();sequence++;clearTimeout(timer);if(list.hidden){input.value=""}
505
520
  close()}else{return}
506
521
  e.preventDefault()});input.addEventListener("blur",()=>{cancelNavigation();sequence++;clearTimeout(timer);clearTimeout(blurTimer);blurTimer=setTimeout(close,150)});this.cancelSearch=()=>{cancelNavigation();sequence++;clearTimeout(timer);clearTimeout(blurTimer);hits=[];close()};box.appendChild(input);box.appendChild(list);box.appendChild(status);bar.appendChild(box);this.searchInput=input}});function watchFlyout(anchorElement,panel,isOpen){const position=()=>{if(!isOpen())return;const anchor=anchorElement.getBoundingClientRect(),fixed=getComputedStyle(panel).position==="fixed";const below=Math.max(0,global.innerHeight-anchor.bottom-8);const above=Math.max(0,anchor.top-8);const opensAbove=below<120&&above>below,room=opensAbove?above:below;panel.style.maxHeight=(panel.classList.contains("cx-fb")?room:Math.min(320,room))+ "px";panel.style.top=opensAbove?"auto":fixed?anchor.bottom+"px":"100%";panel.style.bottom=opensAbove?fixed?global.innerHeight-anchor.top+"px":"100%":"auto";const width=panel.getBoundingClientRect().width;panel.style.left=Math.max(8,Math.min(anchor.left,global.innerWidth-width-8))-(fixed?0:anchor.left)+ "px"};global.addEventListener("resize",position);global.addEventListener("scroll",position,true);return{position,dispose:()=>{global.removeEventListener("resize",position);global.removeEventListener("scroll",position,true)}}}
507
- const PART_URL=typeof document!=="undefined"&&document.currentScript?.src;const PARTS={"tree-tools":["bbcdb89bb78ede8b","canopyx-tree-tools.8f90c97d2d2dda86.js","canopyx-tree-tools.ef7a3fb9c9115a82.css"],"filter-editor":["20fda9e421ce521f","canopyx-filter-editor.a5edb204d5e10be3.js","canopyx-filter-editor.01b7bb6820dc9edb.css"],"export":["8b99c0b7b0ec37c5","canopyx-export.6989ea36f5d6da7b.js"],"history":["7d9901d2fe04df72","canopyx-history.9432e724bf14c9ed.js"],"pager":["8f804f70b96409f2","canopyx-pager.ac543250cf2f6e8b.js","canopyx-pager.08ad67c69026852e.css"],"enhance":["31162b1ffa622bf8","canopyx-enhance.65868addbc5c4a1a.js"],"data":["f07aebe37f3d1bb4","canopyx-data.401d09bc34c61d2f.js"],"forms":["a8c60f205d9babca","canopyx-forms.16987de1cdf9bda9.js","canopyx-forms.29058ce3c88af96e.css"],"flow":["842e1f1956f6213f","canopyx-flow.efc6250968e8b10a.js","canopyx-flow.3152e616c5557452.css"],"flow-host":["de4f9b11ab881eca","canopyx-flow-host.aea5ed35816df2af.js","canopyx-flow-host.1301fcf3454a723a.css"],"flow-checks":["ec2451183901867b","canopyx-flow-checks.29c4586a80f04b6a.js","canopyx-flow-checks.4502d6f7f7487b73.css"],"flow-options":["60450342239ded26","canopyx-flow-options.d31458a54aa4b1e7.js"],"flow-pick":["426718e2fa1f3cd0","canopyx-flow-pick.379205e09325bca3.js","canopyx-flow-pick.771b06ac50c141a1.css"],"flow-records":["f3c09661bdffb8d0","canopyx-flow-records.fddf130ace0764b1.js","canopyx-flow-records.e362111fb5f85732.css"],"flow-drafts":["4f112f64736ca8e3","canopyx-flow-drafts.09b88e275c7bc3b9.js","canopyx-flow-drafts.2dd86fb31fc10458.css"],"flow-preview":["f4fb5c42743873c0","canopyx-flow-preview.5778d5fce9ae0d78.js","canopyx-flow-preview.7928e22901da2088.css"],"flow-command":["39472118ca80ef02","canopyx-flow-command.78f4f931c52b1bfc.js","canopyx-flow-command.0c1247a371b7e775.css"],"flow-tasks":["147dd31638a9cb94","canopyx-flow-tasks.f012a521560f7075.js","canopyx-flow-tasks.524df90f908f81dd.css"],"flow-dialog":["ebb432cd6e34aba6","canopyx-flow-dialog.b00addd6a176198e.js","canopyx-flow-dialog.e6192e827eca25d2.css"],"flow-links":["2c14b19c9236e90d","canopyx-flow-links.7b6cfe42d28b6067.js"],"flow-endpoint":["f5cddfc9545e0920","canopyx-flow-endpoint.b31146202bd76aac.js"],"flow-consent":["22121778bc0d07c5","canopyx-flow-consent.749b97f13039bc71.js","canopyx-flow-consent.9f6580d3673ae8bf.css"],"matrix":["16ab7faa98c96b46","canopyx-matrix.4d417eaeba54ca4f.js","canopyx-matrix.9b3f57c1d0f090b6.css"],"changes":["2db8e138da4b5658","canopyx-changes.053104f8f56b0a87.js","canopyx-changes.dfbdb3d6c468ccb1.css"],"editing":["05fcb2c8be754b50","canopyx-editing.d96e5d0bee7fb477.js","canopyx-editing.b6bfd3c6c383bcbd.css"],"column-groups":["b42238fd108a8614","canopyx-column-groups.d8ad6322f769b915.js","canopyx-column-groups.37e177d74cebb516.css"],"cell-range":["e99a39e7cccc57b1","canopyx-cell-range.647da96e57924f3e.js","canopyx-cell-range.23f3222652588441.css"],"links":["f1ab7e32b501ce37","canopyx-links.d96addeefb3eccf5.js"],"search":["521eebd6e1bbbd35","canopyx-search.14c69f4551c69f23.js"],"formatting":["1a28068597f435de","canopyx-formatting.68c501f97b71f1ec.js","canopyx-formatting.a59507e4e8334891.css"],"format-editor":["24f176a39c02944a","canopyx-format-editor.3b1dec2527e53988.js","canopyx-format-editor.1ba153c82aa87b04.css"],"link":["fa0c9e888463553b","canopyx-link.4ec39bc39fa6cf50.js","canopyx-link.8435c892613926ac.css"],"detail-rows":["4908d1d2b7f67aa8","canopyx-detail-rows.fe29b1759c962565.js","canopyx-detail-rows.8e38a8ad01fded76.css"],"grouping":["0970f2edbcb32de8","canopyx-grouping.84660cd1a0ea5f8f.js","canopyx-grouping.6c93259b4b89e523.css"],"highlight":["f39423961654c1e2","canopyx-highlight.a6f93893d36ab343.js","canopyx-highlight.5b6d2e0d979f9f9b.css"],"layouts":["fa8c686f21626884","canopyx-layouts.e7250c82a6abf52e.js","canopyx-layouts.0b75738924533ee8.css"],"facets":["f9219d35a87635f8","canopyx-facets.8bf477b7915bdcd6.js","canopyx-facets.648a88d2f36d4999.css"],"live":["a27c818b731c22e3","canopyx-live.d19df9edc92e7d09.js","canopyx-live.cc4b94a2dec6f064.css"],"record-panel":["bcc06276c7933af6","canopyx-record-panel.a374fb4254f9115c.js","canopyx-record-panel.f3691d54cefaab04.css"],"calendar":["762f4b4b62ecb4d8","canopyx-calendar.dc45ebdeb704d9c3.js","canopyx-calendar.1099197a45632f63.css"],"calendar-recurrence":["64bcc24d785bd1af","canopyx-calendar-recurrence.4b7f430c2a64de23.js"],"calendar-edit":["bdde26d4b7de2096","canopyx-calendar-edit.4ab2cf55e84f310f.js"],"calendar-ics":["feb3ed2cd67d057f","canopyx-calendar-ics.2a3af9eb3bf444fc.js"],"timeline":["3f04ba99401e9ebd","canopyx-timeline.76928f089774b3de.js","canopyx-timeline.0393f92746f8fa09.css"]},PART_CODE=new Map(),partName=name=>typeof name==="string"&&/^[a-z][a-z\d-]{0,31}$/.test(name);
522
+ const PART_URL=typeof document!=="undefined"&&document.currentScript?.src;const PARTS={"tree-tools":["c68e6612a9ea6eb0","canopyx-tree-tools.b8ee5c807c1d4fcd.js","canopyx-tree-tools.aae203232147f116.css"],"presenters":["b6a65af41d9187d9","canopyx-presenters.c48eacff1e9be0cd.js"],"filter-editor":["ad3c3d19c0c13c6d","canopyx-filter-editor.a52d28e96aadf798.js","canopyx-filter-editor.01b7bb6820dc9edb.css"],"export":["9203882f58fa0155","canopyx-export.cedfec6462c161b4.js"],"history":["7d9901d2fe04df72","canopyx-history.9432e724bf14c9ed.js"],"pager":["8f804f70b96409f2","canopyx-pager.ac543250cf2f6e8b.js","canopyx-pager.08ad67c69026852e.css"],"enhance":["31162b1ffa622bf8","canopyx-enhance.65868addbc5c4a1a.js"],"data":["f07aebe37f3d1bb4","canopyx-data.401d09bc34c61d2f.js"],"forms":["a8c60f205d9babca","canopyx-forms.16987de1cdf9bda9.js","canopyx-forms.29058ce3c88af96e.css"],"flow":["842e1f1956f6213f","canopyx-flow.efc6250968e8b10a.js","canopyx-flow.3152e616c5557452.css"],"flow-host":["de4f9b11ab881eca","canopyx-flow-host.aea5ed35816df2af.js","canopyx-flow-host.1301fcf3454a723a.css"],"flow-checks":["ec2451183901867b","canopyx-flow-checks.29c4586a80f04b6a.js","canopyx-flow-checks.4502d6f7f7487b73.css"],"flow-options":["60450342239ded26","canopyx-flow-options.d31458a54aa4b1e7.js"],"flow-pick":["426718e2fa1f3cd0","canopyx-flow-pick.379205e09325bca3.js","canopyx-flow-pick.771b06ac50c141a1.css"],"flow-records":["f3c09661bdffb8d0","canopyx-flow-records.fddf130ace0764b1.js","canopyx-flow-records.e362111fb5f85732.css"],"flow-drafts":["4f112f64736ca8e3","canopyx-flow-drafts.09b88e275c7bc3b9.js","canopyx-flow-drafts.2dd86fb31fc10458.css"],"flow-preview":["f4fb5c42743873c0","canopyx-flow-preview.5778d5fce9ae0d78.js","canopyx-flow-preview.7928e22901da2088.css"],"flow-command":["39472118ca80ef02","canopyx-flow-command.78f4f931c52b1bfc.js","canopyx-flow-command.0c1247a371b7e775.css"],"flow-tasks":["147dd31638a9cb94","canopyx-flow-tasks.f012a521560f7075.js","canopyx-flow-tasks.524df90f908f81dd.css"],"flow-dialog":["ebb432cd6e34aba6","canopyx-flow-dialog.b00addd6a176198e.js","canopyx-flow-dialog.e6192e827eca25d2.css"],"flow-links":["2c14b19c9236e90d","canopyx-flow-links.7b6cfe42d28b6067.js"],"flow-endpoint":["f5cddfc9545e0920","canopyx-flow-endpoint.b31146202bd76aac.js"],"flow-consent":["22121778bc0d07c5","canopyx-flow-consent.749b97f13039bc71.js","canopyx-flow-consent.9f6580d3673ae8bf.css"],"matrix":["16ab7faa98c96b46","canopyx-matrix.4d417eaeba54ca4f.js","canopyx-matrix.9b3f57c1d0f090b6.css"],"changes":["2db8e138da4b5658","canopyx-changes.053104f8f56b0a87.js","canopyx-changes.dfbdb3d6c468ccb1.css"],"editing":["05fcb2c8be754b50","canopyx-editing.d96e5d0bee7fb477.js","canopyx-editing.b6bfd3c6c383bcbd.css"],"column-groups":["b42238fd108a8614","canopyx-column-groups.d8ad6322f769b915.js","canopyx-column-groups.37e177d74cebb516.css"],"cell-range":["e99a39e7cccc57b1","canopyx-cell-range.647da96e57924f3e.js","canopyx-cell-range.23f3222652588441.css"],"links":["f1ab7e32b501ce37","canopyx-links.d96addeefb3eccf5.js"],"search":["521eebd6e1bbbd35","canopyx-search.14c69f4551c69f23.js"],"formatting":["1a28068597f435de","canopyx-formatting.68c501f97b71f1ec.js","canopyx-formatting.a59507e4e8334891.css"],"format-editor":["24f176a39c02944a","canopyx-format-editor.3b1dec2527e53988.js","canopyx-format-editor.1ba153c82aa87b04.css"],"link":["fa0c9e888463553b","canopyx-link.4ec39bc39fa6cf50.js","canopyx-link.8435c892613926ac.css"],"detail-rows":["4908d1d2b7f67aa8","canopyx-detail-rows.fe29b1759c962565.js","canopyx-detail-rows.8e38a8ad01fded76.css"],"grouping":["0e0a3529c0b099d7","canopyx-grouping.95b3f72fc66f2bea.js","canopyx-grouping.6c93259b4b89e523.css"],"highlight":["f39423961654c1e2","canopyx-highlight.a6f93893d36ab343.js","canopyx-highlight.5b6d2e0d979f9f9b.css"],"layouts":["dd1076d5684bfc6e","canopyx-layouts.670fd555e6e08904.js","canopyx-layouts.b1df38a90cb3215d.css"],"facets":["b46aac5ddb8be693","canopyx-facets.1709d78a83f05966.js","canopyx-facets.648a88d2f36d4999.css"],"live":["a27c818b731c22e3","canopyx-live.d19df9edc92e7d09.js","canopyx-live.cc4b94a2dec6f064.css"],"record-panel":["e78e0e62d74d6811","canopyx-record-panel.2fe5e43bb99cc818.js","canopyx-record-panel.f3691d54cefaab04.css"],"calendar":["762f4b4b62ecb4d8","canopyx-calendar.dc45ebdeb704d9c3.js","canopyx-calendar.1099197a45632f63.css"],"calendar-recurrence":["64bcc24d785bd1af","canopyx-calendar-recurrence.4b7f430c2a64de23.js"],"calendar-edit":["bdde26d4b7de2096","canopyx-calendar-edit.4ab2cf55e84f310f.js"],"calendar-ics":["feb3ed2cd67d057f","canopyx-calendar-ics.2a3af9eb3bf444fc.js"],"timeline":["3f04ba99401e9ebd","canopyx-timeline.76928f089774b3de.js","canopyx-timeline.0393f92746f8fa09.css"]},PART_CODE=new Map(),partName=name=>typeof name==="string"&&/^[a-z][a-z\d-]{0,31}$/.test(name);
508
523
  function registerPart(name,part){if(!partName(name)||!part||typeof part.version!=="string"||typeof part.install!=="function"||
509
524
  part.requires!==undefined&&!(Array.isArray(part.requires)&&part.requires.every(partName)))throw new Error("CanopyX: invalid part.");PART_CODE.set(name,part)}
510
525
  function definePart(View,name,label,context){const parts=View.prototype.parts||={};return parts[name]={name,label,context,parts}}
@@ -514,7 +529,7 @@ const load=(element,attribute,file,kind)=>new Promise((resolve,reject)=>{const u
514
529
  .catch(error=>{part.styleReady=null;throw error}));const code=PART_CODE.get(part.name)?.version===part.version||(part.scriptReady||=load(script,"src",hashed?scriptFile:"canopyx-"+part.name+".js","script")
515
530
  .finally(()=>script.remove()).catch(error=>{part.scriptReady=null;throw error}));await Promise.all([style,code])}}
516
531
  const code=PART_CODE.get(part.name);if(code?.version!==part.version)throw new Error("CanopyX: "+part.label+" and runtime must come from the same build.");for(const name of code.requires||[])await loadPart(part.parts[name]);code.install(part.context())}).catch(error=>{part.ready=null;throw error})}
517
- const partQueue=global.CanopyXParts=global.CanopyXParts||[];partQueue.forEach(entry=>registerPart(...entry));partQueue.length=0;partQueue.push=(...entries)=>{entries.forEach(entry=>registerPart(...entry));return 0};const TREE_TOOLS=definePart(TreeGrid,"tree-tools","tree tools",()=>({TreeGrid,h,setText,fill,numberFormat,watchFlyout,columnWidth,prepareWidth,cellText,cellValue,isCellObject,foldText,formatting,sortKey,compareKeys,EXPORT_FORMATS,exportFormat,exportTimeout,exportFormatsOf:EXPORT_IMPL.formatsOf,INDENT,MAX_PROTOCOL_INTEGER,hostControl,detailCell,HostCellContext,disposeHostSlot,loadPart,definePart,pluginItems,applyTone,toneOf,badgeElement,RECORD_IMPL,svgIcon,gridExportField}));const SEARCH_IMPL={},SEARCH_PART=definePart(TreeGrid,"search","sidecar search",()=>({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}));async function requirePart(name){await this.toolsReady;const part=Object.hasOwn(this.parts,name)?this.parts[name]:null;if(!part)throw new Error("CanopyX: unknown part '"+name+"'.");return loadPart(part)}
532
+ const partQueue=global.CanopyXParts=global.CanopyXParts||[];partQueue.forEach(entry=>registerPart(...entry));partQueue.length=0;partQueue.push=(...entries)=>{entries.forEach(entry=>registerPart(...entry));return 0};const TREE_TOOLS=definePart(TreeGrid,"tree-tools","tree tools",()=>({TreeGrid,h,setText,fill,numberFormat,watchFlyout,columnWidth,prepareWidth,cellText,cellValue,isCellObject,foldText,formatting,sortKey,compareKeys,EXPORT_FORMATS,exportFormat,exportTimeout,exportFormatsOf:EXPORT_IMPL.formatsOf,INDENT,MAX_PROTOCOL_INTEGER,hostControl,detailCell,HostCellContext,disposeHostSlot,loadPart,definePart,pluginItems,applyTone,toneOf,badgeElement,RECORD_IMPL,svgIcon,gridExportField,columnNumericTone,columnValueTone}));const SEARCH_IMPL={},SEARCH_PART=definePart(TreeGrid,"search","sidecar search",()=>({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}));async function requirePart(name){await this.toolsReady;const part=Object.hasOwn(this.parts,name)?this.parts[name]:null;if(!part)throw new Error("CanopyX: unknown part '"+name+"'.");return loadPart(part)}
518
533
  TreeGrid.prototype.requirePart=requirePart;function readStateColumn(c,seen){requireIdentifier(c&&c.id,"state column ID");if(seen.has(c.id)||!Number.isFinite(c.width)||c.width<40||c.width>MAX_COLUMN_WIDTH||typeof c.hidden!=="boolean")
519
534
  throw new Error("CanopyX: invalid state column.");seen.add(c.id);return{id:c.id,width:c.width,hidden:c.hidden}}
520
535
  function statePaths(value){if(!Array.isArray(value))throw new Error("CanopyX: state paths must be arrays.");return value.map(path=>{if(!Array.isArray(path)||!path.length)throw new Error("CanopyX: state paths cannot be empty.");return path.map(id=>{requireIdentifier(id,"state path ID");return id})})}
@@ -573,7 +588,7 @@ return this.openDeepLink()};DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAUL
573
588
  linkMethods(TreeGrid);function linkGridPart(View){(Object.hasOwn(View.prototype,"parts")?View.prototype.parts:View.prototype.parts={}).link=LINK_PART}
574
589
  function linkReady(grid,ready){return Promise.all([ready,grid.linkStart()]).then(([result])=>result)}
575
590
  function linkApi(grid){const api={};for(const name of LINK_METHODS.concat("getExternalFilters","getHighlight"))api[name]=(...args)=>grid[name](...args);return api}
576
- const RECORD_IMPL={},RECORD_PART=definePart(TreeGrid,"record-panel","record panel",()=>({RECORD_IMPL,TreeGrid,h,setText,fill,cellText,cellValue,isCellObject,formatValue,toneOf,applyTone,toneColors,badgeElement,loadSidecar,requireIdentifier,validateGridRows,PROTOCOL,foldText,createTreeGrid,svgIcon,gridExportField}));function loadRecordPanel(){return loadPart(RECORD_PART)}
591
+ const RECORD_IMPL={},RECORD_PART=definePart(TreeGrid,"record-panel","record panel",()=>({RECORD_IMPL,TreeGrid,h,setText,fill,cellText,cellValue,isCellObject,formatValue,toneOf,applyTone,toneColors,badgeElement,loadSidecar,requireIdentifier,validateGridRows,PROTOCOL,foldText,createTreeGrid,svgIcon,gridExportField,columnNumericTone,columnValueTone,validateColumnValues}));function loadRecordPanel(){return loadPart(RECORD_PART)}
577
592
  const RECORD_STRUCTURE=["items","fields","records","events","changes","ref"];TreeGrid.prototype.recordNeeded=function(node){return!!this.view.record||!!node&&(!!node.fields||Object.values(node.cells||{}).some(cell=>isCellObject(cell)&&RECORD_STRUCTURE.some(name=>cell[name]!==undefined)))};TreeGrid.prototype.openRecord=function(id,options){return loadRecordPanel().then(()=>RECORD_IMPL.open(this,id,options))};function recordStart(grid){if(grid.view.record?.deepLink)loadRecordPanel().then(()=>RECORD_IMPL.start(grid),error=>grid.emit("error",{error}))}
578
593
  DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{matchesHighlight:"Highlight matches",matchesCount:"[one]{count} match[other]{count} matches",matchesPosition:"{current} of {count}",matchesNone:"No matches",matchesLoaded:"[one]{count} match in loaded rows[other]{count} matches in loaded rows",matchesPrevious:"Previous match",matchesNext:"Next match",matchesAnnounce:"Match {current} of {count}, {column}",layoutMenu:"Layout",layoutFit:"Fit to width",layoutScroll:"All columns, scroll sideways",layoutCards:"Cards",layoutDensity:"Density",layoutCompact:"Compact",layoutNormal:"Normal",layoutComfortable:"Comfortable",layoutChanged:"Layout: {mode}, {density}",layoutSort:"Sort by"}));const LAYOUT_MODES=["fit","scroll","cards"],LAYOUT_DENSITIES=["compact","default","comfortable"];const DENSITY_STEP={tree:{compact:-4,default:0,comfortable:8},grid:{compact:-6,default:0,comfortable:8}};const VIEW_MODES={};const HIGHLIGHT_KEYS=["enabled","search","filters","matchCase","ignoreAccents","minLength","filterTones"];function readSearchHighlight(value,columns){if(value===undefined||value===false)return null;const options=value===true?{}:value,tone=name=>typeof name==="string"&&/^[a-z][a-z0-9-]{0,31}$/.test(name) && !name.endsWith("-bg");
579
594
  if(!options||typeof options!=="object"||Array.isArray(options)||Object.keys(options).some(key=>!HIGHLIGHT_KEYS.includes(key))||
@@ -631,12 +646,13 @@ throw new Error("CanopyX: ordinal row identity is snapshot-local; keyed live upd
631
646
  throw new Error("CanopyX: ordinal row identity is snapshot-local; record deep links require stable row keys.");if(typeof view.label!=="string"||!view.label.trim()||!Array.isArray(view.columns)||!view.columns.length)
632
647
  throw new Error("CanopyX: a grid needs a label and columns.");if(view.reporting!==undefined){if(!GRID_REPORTING.validate)throw new Error("CanopyX: this view needs the reporting runtime.");GRID_REPORTING.validate(view)}
633
648
  const ids=new Set();for(const column of view.columns){requireIdentifier(column&&column.id,"grid column ID");if(ids.has(column.id)||typeof column.title!=="string"||!["text","number","datetime"].includes(column.kind)||
649
+ column.headerDescription!==undefined&&typeof column.headerDescription!=="string"||
634
650
  column.width!==undefined&&(!Number.isInteger(column.width)||column.width<40)||
635
651
  ["wrap","autoWidth","fixed","rowHeader","alwaysVisible","editable","filterable","exportable"].some(name=>column[name]!==undefined&&typeof column[name]!=="boolean")||
636
652
  column.flex!==undefined&&!(typeof column.flex==="number"&&column.flex>=0&&column.flex<=100)||column.autoSize!==undefined&&!["content","header","none"].includes(column.autoSize)||
637
653
  column.pinned!==undefined&&![null,"left","right"].includes(column.pinned)||column.priority!==undefined&&!gridPriority(column.priority)||
638
654
  column.fixed&&column.width===undefined||column.tooltip!==undefined&&column.tooltip!=="auto"&&!view.columns.some(item=>item.id===column.tooltip))
639
- throw new Error("CanopyX: invalid or duplicate grid column.");ids.add(column.id);if(column.presenter!==undefined)gridPresenter(column.presenter,column,view.columns);if(column.format!==undefined){if(column.kind!=="number")throw new Error("CanopyX: number formats need number columns.");gridNumberFormat(column.format)}
655
+ throw new Error("CanopyX: invalid or duplicate grid column.");ids.add(column.id);validateColumnValues(column);if(column.presenter!==undefined)gridPresenter(column.presenter,column,view.columns);if(column.format!==undefined){if(column.kind!=="number")throw new Error("CanopyX: number formats need number columns.");gridNumberFormat(column.format)}
640
656
  if(column.aggregatable!==undefined&&(typeof column.aggregatable!=="boolean"||column.aggregatable&&column.kind!=="number")||
641
657
  column.section!==undefined&&(typeof column.section!=="string"||!column.section.trim()||column.section.length>256))
642
658
  throw new Error("CanopyX: invalid column aggregate or drawer section.")}
@@ -676,9 +692,10 @@ function gridOrder(left,right){return left===right?0:left<right?-1:1}
676
692
  function gridIntegerId(id){if(id.length>1&&id.charCodeAt(0)===48)return false;for(let index=0;index<id.length;index++){const code=id.charCodeAt(index);if(code<48||code>57)return false}
677
693
  return id.length>0}
678
694
  function gridIdOrder(left,right){if(left===right)return 0;const a=gridIntegerId(left),b=gridIntegerId(right);if(a!==b)return a?-1:1;return a&&left.length!==right.length?left.length-right.length:left<right?-1:1}
679
- function gridSortScalar(cell,column){return isCellObject(cell)&&cell.sort!=null?cell.sort:gridScalar(cell,column)}
695
+ function gridSortScalar(cell,column){return!column.valueOrder?.length&&isCellObject(cell)&&cell.sort!=null?cell.sort:gridScalar(cell,column)}
680
696
  function gridCompare(left,right,column,direction){return gridKeyCompare(gridSortScalar(left.cells[column.id],column),gridSortScalar(right.cells[column.id],column),column,direction)}
681
- function gridKeyCompare(a,b,column,direction){if(a===null||b===null)return a===b?0:a===null?1:-1;const x=column.kind==="text"&&typeof a!=="number"?String(a):a,y=column.kind==="text"&&typeof b!=="number"?String(b):b;const rank=gridOrder(typeof x,typeof y);if(rank)return rank;const result=gridOrder(x,y);return direction==="desc"?-result:result}
697
+ function gridKeyCompare(a,b,column,direction){if(a===null||b===null)return a===b?0:a===null?1:-1;if(column.valueOrder?.length){const at=value=>{const index=typeof value==="string"?column.valueOrder.indexOf(value):-1;return index<0?column.valueOrder.length:index};const rank=at(a)- at(b),result=rank||gridOrder(typeof a,typeof b)||gridOrder(a,b);return direction==="desc"?-result:result}
698
+ const x=column.kind==="text"&&typeof a!=="number"?String(a):a,y=column.kind==="text"&&typeof b!=="number"?String(b):b;const rank=gridOrder(typeof x,typeof y);if(rank)return rank;const result=gridOrder(x,y);return direction==="desc"?-result:result}
682
699
  function gridMatches(row,predicate,column){return cellMatches(row.cells[column.id],predicate,column)}
683
700
  function gridQueryRows(view,query,columns,compare=gridCompare){const terms=gridSearchTerms(query.search,query.searchMode),searchColumns=view.searchColumns?view.searchColumns.map(id=>columns.get(id)):view.columns;const rows=view.rows.filter(row=>gridMatchesSearch(row,terms,searchColumns)&&
684
701
  query.filters.every(predicate=>gridMatches(row,predicate,columns.get(predicate.column)))&&gridMatchesGroup(row,query.filterGroup,columns));if(compare!==gridCompare||!query.sort.length)return compare?rows.sort((a,b)=>{for(const sort of query.sort){const compared=compare(a,b,columns.get(sort.column),sort.direction);if(compared)return compared}
@@ -695,7 +712,7 @@ page.total!==null&&page.matched!==null&&page.matched>page.total||
695
712
  !page.items.length&&(page.offset!==0||next)||!page.offset&&previous||
696
713
  page.matched!==null&&next!==(end<page.matched)||page.total!==null&&next&&end>=page.total||
697
714
  query.cursor===undefined&&page.offset!==0)throw new Error("CanopyX: inconsistent cursor page.");const tokens=[page.nextCursor,page.previousCursor].filter(token=>token!==undefined);tokens.forEach(gridCursor);if(new Set(tokens).size!==tokens.length||tokens.includes(query.cursor))throw new Error("CanopyX: repeated cursor.");return checkedGridPage(page,view,query,accepted)}
698
- function gridFacetKey(value,column){if(value!==null&&typeof value==="object"||value===undefined)throw new Error("CanopyX: facet values are raw scalars.");const scalar=gridScalar(value,column);if(scalar===null)return "null";return column.kind==="datetime"?"d:"+scalar:typeof scalar==="string"?"s:"+foldText(scalar):
715
+ function gridFacetKey(value,column){if(value!==null&&typeof value==="object"||value===undefined)throw new Error("CanopyX: facet values are raw scalars.");const scalar=gridScalar(value,column);if(scalar===null)return "null";return column.kind==="datetime"?"d:"+scalar:typeof scalar==="string"?"s:" +(gridExactTokens(column)?scalar:foldText(scalar)):
699
716
  typeof scalar==="boolean"?"b:"+scalar:"n:"+scalar}
700
717
  function validateGridFacetPage(input,view,request,snapshot){checkDocument(input,"gridFacetPage");const column=view.columns.find(item=>item.id===request.column);if(input.view!==view.id||input.revision!==request.query.revision||input.column!==request.column||
701
718
  input.search!==request.search||input.includeCurrentFilter!==request.includeCurrentFilter||
@@ -712,7 +729,8 @@ throw new Error("CanopyX: facet buckets contradict the matching row count.");ret
712
729
  class DataGrid{constructor(host,options){const{rows,rowData,...definition}=validateGridView(options.view),owned=parsedViews.has(options.view);this.view=JSON.parse(JSON.stringify(definition));if(this.view.rowIdentity==="ordinal"&&options.live)
713
730
  throw new Error("CanopyX: ordinal row identity is snapshot-local; keyed live updates require stable row keys.");if(rows)this.view.rows=owned?rows:JSON.parse(JSON.stringify(rows));if(rowData){this.view.rowData=owned?rowData:structuredClone(rowData);this.view.rows=[]}
714
731
  this.host=host;this.opts=options;this.id="cx" + ++instanceSeq;this.lifetime=new AbortController();this.dataLifetime=new AbortController();this.source=options.source||(this.view.source.kind==="inline"?this.view.rowData?rowDataSource(this):inlineGridSource(this.view):null);if(!this.source||typeof this.source.query!=="function")throw new Error("CanopyX: host grids need a query source.");this.cursor=this.view.source.navigation==="cursor";if(this.source.navigation!==undefined&&this.source.navigation!==(this.cursor?"cursor":"offset"))
715
- throw new Error("CanopyX: source navigation must match the grid definition.");this.pageSize=this.view.pageSize;this.authoredAutoRows=this.view.rowHeight==="auto"||!!this.view.autoRowHeight;this.autoRows=this.authoredAutoRows;this.rowH=this.view.rowHeight==="auto"?this.view.estimatedRowHeight||28:this.view.rowHeight;this.rowHeights=new Map();this.paged=this.view.presentation==="paged";this.pageLength=this.view.pageLength||50;this.pageOffset=0;this.searchDelayMs=options.searchDelayMs===undefined?this.view.searchDelayMs===undefined?
732
+ throw new Error("CanopyX: source navigation must match the grid definition.");this.pageSize=this.view.pageSize;this.authoredAutoRows=this.view.rowHeight==="auto"||!!this.view.autoRowHeight||
733
+ this.view.autoRowHeight!==false&&this.view.columns.some(column=>column.wrap);this.autoRows=this.authoredAutoRows;this.rowH=this.view.rowHeight==="auto"?this.view.estimatedRowHeight||28:this.view.rowHeight;this.rowHeights=new Map();this.paged=this.view.presentation==="paged";this.pageLength=this.view.pageLength||50;this.pageOffset=0;this.searchDelayMs=options.searchDelayMs===undefined?this.view.searchDelayMs===undefined?
716
734
  this.view.source.kind==="inline"?0:300:this.view.searchDelayMs:options.searchDelayMs;if(!Number.isInteger(this.searchDelayMs)||this.searchDelayMs<0||this.searchDelayMs>5000)
717
735
  throw new Error("CanopyX: search delay must be an integer from 0 to 5000 milliseconds.");this.cachePageLimit=options.cachePageLimit===undefined?40:options.cachePageLimit;this.requestTimeoutMs=options.requestTimeoutMs===undefined?rowData&&!options.source?2147483647:30000:options.requestTimeoutMs;if(!Number.isInteger(this.cachePageLimit)||this.cachePageLimit<2||this.cachePageLimit>1000||
718
736
  !Number.isInteger(this.requestTimeoutMs)||this.requestTimeoutMs<1||this.requestTimeoutMs>2147483647)
@@ -804,7 +822,7 @@ button.setAttribute("aria-label",cell.getAttribute("aria-label")+ ", "+sorts[ind
804
822
  this.buildHeaderSelection?.();this.buildColumnMenus?.()},cellOf(row,column){return row.cells[column.id]},refreshRowState(element,row){setAttr(element,"aria-selected",row.status||this.view.selection==="none"?null:String(this.selected.has(row.key)))},fillRow(element,row){const kind=row.status?"status":"node";element._w=row;if(element._kind!==kind||element._layout!==this.layout){disposeRowHostCells(element);element.textContent="";element._kind=kind;element._layout=this.layout;element._attrs={};element._cls=null;element.setAttribute("role","row");element.style.height=this.rowH+"px";element.style.width=this.rowWidth+"px";element._cells=(row.status?[null]:this.cols).map((column,index)=>{const cell=this.cell(element,index,column?column.width:this.rowWidth,column?column.kind:null);if(!column)cell.setAttribute("aria-colspan",String(this.cols.length));const content=index===0&&column?.render&&this.view.reporting?.selectionControls?cell.appendChild(h("span","cx-content")):cell;const slot={cell,content,base:cell.className +(column?.wrap?" cx-wrap":""),cls:null,title:null,badges:[],mode:"default"};slot.textSpan=content.appendChild(h("span","cx-text"));slot.text=slot.textSpan.appendChild(document.createTextNode(""));return slot})}
805
823
  setClass(element,"cx-row" +(row.status?" cx-status cx-"+row.status:this.autoRows?" cx-auto-row":""));if(this.autoRows){element.style.height=row.status?this.rowH+"px":"auto";this.observeDetail(element,!row.status);this.measureNeeded=true}else element.style.height=this.rowH+"px";setAttr(element,"data-cx-id",row.key||null);setAttr(element,"data-cx-status",row.status||null);setAttr(element,"draggable",this.view.dragRows&&!row.status?"true":null);setAttr(element,"aria-busy",row.status==="loading"?"true":null);this.refreshRowState(element,row);if(row.status)element._cells[0].text.data=row.status==="error"?fill(this.labels.loadError,{error:((this.pages.get(Math.floor(row._ri / this.pageSize) * this.pageSize) || {}).error || {}).message || ""
806
824
  }):this.labels.loading;else for(let i=0;i<this.cols.length;i++){const slot=element._cells[i];if(slot.highlighted){slot.cls=null;slot.highlighted=false}
807
- const column=this.cols[i];this.paintSlot(slot,row.h,column,this.columnIndex[i],row);if(!column.render&&!slot.text.data){slot.text.data="—";slot.cell.classList.add("p-missing");slot.missing=true}
825
+ const column=this.cols[i],cell=row.h.cells[column.id];this.paintSlot(slot,row.h,column,this.columnIndex[i],row);if(!column.render&&!slot.text.data&&!(isCellObject(cell)&&cellValue(cell)==null&&cell.text==="")){slot.text.data="—";slot.cell.classList.add("p-missing");slot.missing=true}
808
826
  else if(slot.missing){slot.cell.classList.remove("p-missing");slot.missing=false}
809
827
  if(this.phone||slot.hiddenFields||slot.phonePrimary)this.paintHiddenFields?.(slot,row.h,column,this.columnIndex[i])}
810
828
  this.paintGridHighlights(element,row);if(row.status)this.paintGridSkeleton(element,row)}});class AxisWindow{constructor(){this.count=0;this.uniform=0;this.offsets=null;this.total=0}
@@ -870,7 +888,7 @@ Object.assign(DataGrid.prototype,COLUMN_FIT,{fitAvailableWidth(){const grid=this
870
888
  for(const column of peers)if(!column.fixed&&!column.sized&&!column.alwaysVisible)column.fitHidden=true},fitSize(column,level){if(column.fixed||column.sized)return columnWidth(column,column.width);const need=column.need??column.width,content=column.autoSize==="header"?need:column.contentNeed??need;const header=column.headWrapNeed||0;const floor=Math.max(level===undefined?need:content,header);let width=Math.max(floor,level===undefined?column.pref||0:0);if(column.identity&&this.host.clientWidth<=640&&(this.layoutMode||"fit")==="fit"){const available=this.fitAvailableWidth(),minimum=Math.min(content,available*.4);width=Math.max(header,minimum,Math.min(width,Math.max(minimum,available*.5)))}
871
889
  return Math.ceil(columnWidth(column,width))},fitShrink(cols,excess){const slack=cols.map(column=>Math.max(0,column.renderWidth-this.fitSize(column,1)));const total=slack.reduce((sum,width)=>sum+width,0),ratio=total?Math.min(1,excess / total) : 0;
872
890
  cols.forEach((column,index)=>column.renderWidth -=slack[index]*ratio);return Math.max(0,excess-total)},fitSpare(columns,spare){const flex=columns.filter(column=>column.flexWeight);const first=gridFitGrow(flex,spare,column=>column.flexWeight);return gridFitGrow(columns.filter(gridTextual),first.spare,column=>column.contentNeed||column.need).target||first.target},visibleColumns(){return FIT.visibleColumns.call(this).filter(column=>!column.fitHidden)},newCell(index,width,kind){return FIT.newCell.call(this,index,kind?this.cols[index].renderWidth??width:width,kind)},buildHeader(){this.fitLayout();this.fitBuilding=true;try{FIT.buildHeader.call(this)}finally{this.fitBuilding=false}
873
- this.headCells.forEach((cell,index)=>{cell.querySelector(".cx-sort,.cx-htext").title=this.cols[index].title;cell.querySelector(".cx-resize").addEventListener("keydown",event=>{if(["ArrowLeft","ArrowRight","Home"].includes(event.key))this.fitManual(this.cols[index])},true)})},startResize(event,column){if(!this.destroyed&&!event.button){this.fitManual(column);global.addEventListener("pointerup",()=>this.emit("columnResize",{column:column.id,width:column.width}),{once:true,signal:this.lifetime.signal})}
891
+ this.headCells.forEach((cell,index)=>{cell.querySelector(".cx-sort,.cx-htext").title=this.cols[index].headerDescription??this.cols[index].title;cell.querySelector(".cx-resize").addEventListener("keydown",event=>{if(["ArrowLeft","ArrowRight","Home"].includes(event.key))this.fitManual(this.cols[index])},true)})},startResize(event,column){if(!this.destroyed&&!event.button){this.fitManual(column);global.addEventListener("pointerup",()=>this.emit("columnResize",{column:column.id,width:column.width}),{once:true,signal:this.lifetime.signal})}
874
892
  return 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;FIT.setColumnWidth.call(this,id,width);this.emit("columnResize",{column:id,width:column.width})},applyWidths(){this.fitLayout();if(this.phone!==undefined)this.updateGridPhone();const visible=this.visibleColumns(),cols=this.cols,width=this.fitAvailableWidth();if(cols&&(visible.length!==cols.length||visible.some((column,index)=>column!==cols[index]))){if(!this.fitBuilding){this.buildHeader();this.syncColumnControls();this.render();return}
875
893
  queueMicrotask(()=>this.destroyed||this.applyWidths())}
876
894
  FIT.applyWidths.call(this,this.fitWidths(cols,width));if(this.headRow.matches(":hover"))this.syncColumnMenuRoom?.();this.fitHeight()},fitLayout(){const width=this.fitAvailableWidth(),phone=this.host.clientWidth<=640,shown=FIT.visibleColumns.call(this).filter(column=>!column.responsiveHidden);if(!width)return;const key=this.pendingQuery?this.fitKey:this.queryEpoch+":"+phone;if(key!==this.fitKey||!this.fitCh){this.fitKey=key;this.fitFont=null;for(const column of this.columns)column.need=this.measureGridColumn(column).width}
@@ -878,7 +896,7 @@ for(const column of this.columns){if(!column.fixed&&!column.sized)column.width=t
878
896
  this.fitHide(shown,width,phone)},measureGridColumn(column){const context=this.fitContext||=document.createElement("canvas").getContext("2d"),query=this.acceptedQuery;if(!context)throw new Error("CanopyX: no canvas context.");if(!this.fitFont){const style=getComputedStyle(this.grid),head=this.headCells?.[0]&&getComputedStyle(this.headCells[0]),family=" "+style.fontFamily;this.fitFont=[style.fontWeight+" "+style.fontSize+family,"700 12.5px"+family,(head?head.fontWeight+" "+head.fontSize:"700 13px")+ family,parseFloat(getComputedStyle(this.host).getPropertyValue("--cx-cell-px"))||12];this.fitFont.push(gridClassFont(this.grid,"p-mono"),gridClassFont(this.grid,"p-sub"),gridClassFont(this.grid,"p-pill",this.fitPill={}),gridClassFont(this.grid,"cx-sort-priority"));this.fitNumericVariant=gridNumericVariant(this.grid);context.font=this.fitFont[0];this.fitCh=Math.ceil(gridMeasureText(context,"00000000000",this.fitNumericVariant))}
879
897
  const[,,headFont,pad,mono,sub,pillFont,priorityFont]=this.fitFont,first=column===FIT.visibleColumns.call(this)[0],options=gridOptions(column),kind=options.kind;const text=(value,font=this.fitFont[0],numeric=true)=>{context.font=font;return gridMeasureText(context,value,numeric?this.fitNumericVariant:"normal")};const move=this.view.reporting?.columnReorder?Math.max(32,Math.ceil(text("⋮⋮",headFont,false))+ 8):0,target=this.host.clientWidth<=640?44:24;const sort=query?.sort.findIndex(sort=>sort.column===column.id)??-1;const chrome=2*pad+8+move +(sort<0?0:22 +(query.sort.length>1?text(sort+1,priorityFont,false)+ 4:0))+
880
898
  (gridColumnFiltered(query,column.id)?target:0)+(first&&this.selectionControls?target+2:0);const title=text(column.title,headFont,false),head=Math.ceil(Math.max(24,title)+ chrome);const words=column.title.trim().split(/\s+/);
881
- let balanced=title;for(let split=1;split<words.length;split++)balanced=Math.min(balanced,Math.max(text(words.slice(0,split).join(" "),headFont,false),text(words.slice(split).join(" "),headFont,false)));column.headWrapNeed=Math.ceil(Math.max(24,balanced)+ chrome);let values=0,sampled=0;const none=column.autoSize==="none"||column.pref&&(column.wrap||["longText","tags","list"].includes(kind));if(!none&&column.autoSize!=="header")for(const row of this.rowCache.values()){if(sampled===200)break;const cell=row.h.cells[column.id],value=cellText(cell,column,this.fmt)||"—",series=gridSeries(cell).length;const tone=gridPresenterTone(options,cellValue(cell),isCellObject(cell)&&cell.tone),quiet=options.quietTones?.includes(tone);const secondary=kind==="identifier"&&(options.secondaryColumn?cellText(row.h.cells[options.secondaryColumn],this.columns.find(item=>item.id===options.secondaryColumn),this.fmt):isCellObject(cell)&&cell.secondary);const atomic=kind==="enum"||kind==="state";const pill=kind==="enum"&&!quiet&&tone!=="success";const atomicWidth=atomic?text(value,pill?pillFont:undefined)+
899
+ let balanced=title;for(let split=1;split<words.length;split++)balanced=Math.min(balanced,Math.max(text(words.slice(0,split).join(" "),headFont,false),text(words.slice(split).join(" "),headFont,false)));column.headWrapNeed=Math.ceil(Math.max(24,balanced)+ chrome);let values=0,sampled=0;const none=column.autoSize==="none"||column.pref&&(column.wrap||["longText","tags","list"].includes(kind));if(!none&&column.autoSize!=="header")for(const row of this.rowCache.values()){if(sampled===200)break;const cell=row.h.cells[column.id],value=cellText(cell,column,this.fmt)||"—",series=gridSeries(cell).length;const tone=columnValueTone(column,cell)||gridPresenterTone(options,cellValue(cell),isCellObject(cell)&&cell.tone),quiet=options.quietTones?.includes(tone);const secondary=kind==="identifier"&&(options.secondaryColumn?cellText(row.h.cells[options.secondaryColumn],this.columns.find(item=>item.id===options.secondaryColumn),this.fmt):isCellObject(cell)&&cell.secondary);const atomic=kind==="enum"||kind==="state";const pill=kind==="enum"&&!quiet&&tone!=="success";const atomicWidth=atomic?text(value,pill?pillFont:undefined)+
882
900
  (pill?this.fitPill.extra+this.fitPill.spacing*Array.from(value).length:quiet&&kind==="enum"?16:quiet?0:kind==="state"&&tone!=="success"?15:13):0;values=Math.max(values,atomic?atomicWidth:kind==="identifier"?Math.min(420,text(value,options.mono?mono:undefined,!options.mono)+(secondary?6+text(secondary,sub):0)):kind==="statusStrip"?Math.min(series,12)*7:kind==="sparklineBars"?Math.min(series,12)*6:kind==="sparklineLine"?80:kind==="boolean"?16:
883
901
  Math.min(kind==="longText"||kind==="tags"||kind==="list"||column.wrap?320:420,text(value))+
884
902
  (kind==="progress"?80:kind==="tags"||kind==="list"?48:0));sampled++}
@@ -889,7 +907,9 @@ rule.target!==undefined&&!["row","cell"].includes(rule.target)||rule.tone===unde
889
907
  throw new Error("CanopyX: invalid highlight rule.");const{column,operator,values}=rule;gridPredicate({column,operator,values},columns,budget);gridDecoration(rule.tone,rule.className)}}
890
908
  DataGrid.prototype.paintGridHighlights=function(element,row){if(!this.view.highlightRules?.length&&!row.h.tone&&!row.h.className&&!element._cxHighlight)return;const matches=new Map();if(!row.status)for(const rule of this.view.highlightRules||[]){const key=rule.target==="cell"?rule.column:null;if(!matches.has(key)&&gridMatches(row.h,rule,this.columns.find(column=>column.id===rule.column)))matches.set(key,rule)}
891
909
  const mark=matches.get(null),name=row.status?null:mark?.tone??row.h.tone;const tone=toneOf(name),classes=row.status?"":[row.h.className,mark?.className].filter(Boolean).join(" ");setClass(element,(element._cls??element.className)+(classes?" "+classes:"")+ tone.cls);toneColors(element,tone);setAttr(element,"data-cx-tone",name||null);if(name)element.style.setProperty("--cx-row-tone","var(--cx-tone-"+name+",var(--cx-text))");else element.style.removeProperty("--cx-row-tone");element._cxHighlight=!!(name||classes);for(const[id,rule]of matches)if(id!==null){const index=this.cols.findIndex(column=>column.id===id),slot=element._cells[index];if(!slot)continue;const base=rule.tone?slot.cell.className.replace(/(?:^|\s)cx-tone-[a-z0-9-]+|(?:^|\s)cx-toned/g, "") : slot.cell.className;
892
- slot.cell.className=base +(rule.className?" "+rule.className:"")+(rule.tone?toneOf(rule.tone).cls:"");if(rule.tone)toneColors(slot.cell,toneOf(rule.tone));slot.highlighted=true}};DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{gridExpandCell:"{column}: show complete text",gridCloseCell:"Close complete text"}));const GRID_PRESENTERS_BUILD=DataGrid.prototype.build;function gridPresenter(options,column,columns){const kinds=["link","icon","progress","boolean","list","longText","enum","state","change","statusStrip","sparklineBars","sparklineLine","identifier","tags","missing","structured"];const invalid=()=>{throw new Error("CanopyX: invalid grid presenter or raw column binding.")};if(!options||typeof options!=="object"||Array.isArray(options)||!kinds.includes(options.kind))invalid();if(["progress","change"].includes(options.kind)&&column.kind!=="number"||
910
+ slot.cell.className=base +(rule.className?" "+rule.className:"")+(rule.tone?toneOf(rule.tone).cls:"");if(rule.tone)toneColors(slot.cell,toneOf(rule.tone));slot.highlighted=true}};const VALUE_PAINT=DataGrid.prototype.paintSlot;DataGrid.prototype.paintSlot=function(slot,row,column,index,wrapper){VALUE_PAINT.call(this,slot,row,column,index,wrapper);if(!column.render){const cell=row.cells[column.id],rule=columnNumericTone(column,cellValue(cell)),tone=columnValueTone(column,cell);if(tone){applyTone(slot.cell,slot.base,toneOf(tone));slot.cls=slot.cell.className}
911
+ if(rule){slot.cell.title=rule.label;slot.title=rule.label}
912
+ setAttr(slot.cell,"aria-description",rule?.label||null)}};DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{gridExpandCell:"{column}: show complete text",gridCloseCell:"Close complete text"}));const GRID_PRESENTERS_BUILD=DataGrid.prototype.build;function gridPresenter(options,column,columns){const kinds=["link","icon","progress","boolean","list","longText","enum","state","change","statusStrip","sparklineBars","sparklineLine","identifier","tags","missing","structured"];const invalid=()=>{throw new Error("CanopyX: invalid grid presenter or raw column binding.")};if(!options||typeof options!=="object"||Array.isArray(options)||!kinds.includes(options.kind))invalid();if(["progress","change"].includes(options.kind)&&column.kind!=="number"||
893
913
  ["boolean","list","tags","link"].includes(options.kind)&&column.kind!=="text")invalid();for(const name of["newWindow","inverted","mono","higherIsGood"])if(options[name]!==undefined&&typeof options[name]!=="boolean")invalid();for(const name of["hrefColumn","deltaColumn","secondaryColumn"])if(options[name]!==undefined){const target=columns.find(item=>item.id===options[name]);if(!target||name==="hrefColumn"&&target.kind!=="text"||name==="deltaColumn"&&target.kind!=="number")invalid()}
894
914
  if(options.kind==="change"&&!options.deltaColumn||options.kind==="icon"&&(typeof options.glyph!=="string"||!options.glyph.trim()||options.glyph.length>32))invalid();if(options.maximum!==undefined&&(!Number.isFinite(options.maximum)||options.maximum<=0||options.maximum>Number.MAX_SAFE_INTEGER))invalid();if(["list","tags"].includes(options.kind)&&(typeof options.separator!=="string"||!options.separator.length||options.separator.length>16||
895
915
  options.limit!==undefined&&(!Number.isInteger(options.limit)||options.limit<1||options.limit>16)))invalid();if((options.minimum===undefined)!==(options.scaleMaximum===undefined)||options.minimum!==undefined&&
@@ -906,14 +926,8 @@ const value=raw.trim();try{const url=new URL(value,document.baseURI);if(["http:"
906
926
  }catch(_){/* Invalid destinations retain plain text. */ }
907
927
  return null}
908
928
  DataGrid.prototype.build=function(){for(const column of this.columns){const options=column.presenter||(column.wrap?{kind:"longText"}:null);if(options&&!column.render){column.render=gridCellRenderer(this,column,options);column.hostRenderer=false}}
909
- return GRID_PRESENTERS_BUILD.call(this)};function gridCellRenderer(grid,column,options){return(row,element)=>{const cell=row.cells[column.id],raw=cellValue(cell),text=cellText(cell,column,grid.fmt),object=isCellObject(cell);const tone=gridPresenterTone(options,raw,object?cell.tone:null);element.classList.add("cx-presented-cell");if(object&&cell.title)element.title=cell.title;const add=(value,cls="cx-presenter-text",tag="span")=>{const item=h(tag,cls);setText(item,value);element.appendChild(item);return item};const more=(value,label=grid.labels.gridShowMore)=>{const button=add(label,"cx-link cx-presenter-expand","button");button.type="button";button.setAttribute("aria-haspopup","dialog");button.setAttribute("aria-label",fill(grid.labels.gridExpandCell,{column:column.title}));button.addEventListener("click",()=>grid.showReportingText(column,value,button,row.id,options.mono));return button};if(GRID_HISTORY_KINDS.includes(options.kind)){if(GRID_HISTORY_IMPL.render)GRID_HISTORY_IMPL.render(grid,column,options,cell,element,text);else grid.loadHistory()}else if(options.kind==="structured"){if(RECORD_IMPL.summary)RECORD_IMPL.summary(grid,column,options,row,element,text);else{add(text);grid.loadRecordPanel()}}else if(raw==null&&(!object||cell.text===undefined)||text==="")add("—","p-missing");else if(options.kind==="link"){const href=gridPresenterLink(cellValue(options.hrefColumn?row.cells[options.hrefColumn]:cell));const link=add(text,"p-link",href?"a":"span");if(href){link.href=href;if(options.newWindow){link.target="_blank";link.rel="noopener noreferrer"}}}else if(options.kind==="icon"){add(options.glyph,"cx-presenter-icon").setAttribute("aria-hidden","true");add(text)}
910
- else if(options.kind==="boolean"&&typeof raw==="boolean"){const value=add(raw?"":"—",raw?"p-bool-yes"+(options.inverted?" cx-bool-bad":""):"p-bool-no");value.setAttribute("role","img");value.setAttribute("aria-label",raw?grid.labels.yes:grid.labels.no);if(raw)value.appendChild(gridIcon("check"))}else if(options.kind==="state"||options.kind==="enum"){if(options.quietTones?.includes(tone))add(text,(options.quietStyle==="plain"?"cx-presenter-text":"p-muted")+(options.kind==="enum"?" p-inset":""));else if(options.kind==="state"||tone==="success"){const state=add("","p-state"+(tone==="success"?" quiet":""));const dot=h("span","p-dot "+(tone==="success"?"quiet":tone));toneColors(dot,toneOf(tone));state.append(dot,document.createTextNode(text))}else{const pill=add(text,"p-pill "+tone);applyTone(pill,pill.className,toneOf(tone))}}else if(options.kind==="change"){const delta=cellValue(row.cells[options.deltaColumn]);if(typeof delta==="number")add((delta===0?"":delta>0?"↑ ":"↓ ")+numberFormat(grid.lang).format(Math.abs(delta)),"p-delta "+(delta===0?"flat":(delta>0)===!!options.higherIsGood?"good":"bad"));add(text)}else if(options.kind==="progress"&&typeof raw==="number"){const box=add("","p-progress"),track=h("span","track"),bar=h("span","fill "+tone),maximum=options.maximum||100;track.setAttribute("role","progressbar");track.setAttribute("aria-label",column.title);track.setAttribute("aria-valuemin","0");track.setAttribute("aria-valuemax",String(maximum));track.setAttribute("aria-valuenow",String(Math.min(maximum,Math.max(0,raw))));track.setAttribute("aria-valuetext",text);bar.style.width=Math.min(100,Math.max(0,raw/maximum*100))+"%";toneColors(bar,toneOf(tone));track.appendChild(bar);box.append(track,document.createTextNode(text));
911
- }else if(options.kind==="identifier"){add(text,options.mono?"p-mono":"cx-presenter-text");const secondary=options.secondaryColumn?cellText(row.cells[options.secondaryColumn],grid.columns.find(item=>item.id===options.secondaryColumn),grid.fmt):object&&cell.secondary;if(secondary)add(secondary,"p-sub")}else if(options.kind==="tags"||options.kind==="list"){const values=text.split(options.separator).map(item=>item.trim()).filter(Boolean),limit=options.kind==="tags"?3:options.limit||3;const preview=add("","cx-tag-list");element.classList.add("cx-list-cell");for(const value of values.slice(0,limit)){const tag=h("span","p-tag");setText(tag,value);preview.appendChild(tag)}
912
- if(values.length>limit||options.kind==="list")more(text,values.length>limit?"+"+(values.length-limit):grid.labels.gridShowMore)}else if(options.kind==="longText"){const budget=Math.max(256,Math.ceil((column.renderWidth||column.width)/7*5));
913
- const preview=add(text.length>budget?text.slice(0,budget).replace(/[\uD800-\uDBFF]$/,"")+" …":text,"cx-wrapped-text"+(options.mono?" p-mono":""));
914
- if(!grid.autoRows)element.classList.add("cx-fixed-text");if(!column.wrap||text.length>Math.max(40,(column.renderWidth||column.width)/7*4)||text.split("\n").length>4){element.classList.add("cx-clamped");more(text);}
915
- }else add(text);if(object)for(const badge of cell.badges||[])element.appendChild(badgeElement(badge));return true}}
916
- Object.assign(DataGrid.prototype,{setNotice(text,error){clearTimeout(this.gridLoadingTimer);this.notice.replaceChildren();this.notice.hidden=true;this.host.insertBefore(this.notice,this.grid);this.host.classList.remove("cx-grid-awaiting");if(!this.stateCleanup){this.stateCleanup=true;this.lifetime.signal.addEventListener("abort",()=>{clearTimeout(this.gridLoadingTimer);clearTimeout(this.gridSkeletonTimer)},{once:true})}
929
+ return GRID_PRESENTERS_BUILD.call(this)};const GRID_PRESENTER_IMPL={},GRID_PRESENTERS=definePart(DataGrid,"presenters","cell presenters",()=>({GRID_PRESENTER_IMPL,h,setText,fill,cellValue,cellText,isCellObject,columnNumericTone,columnValueTone,gridPresenterTone,gridPresenterLink,numberFormat,toneColors,toneOf,applyTone,gridIcon,badgeElement,GRID_HISTORY_KINDS,GRID_HISTORY_IMPL,RECORD_IMPL}));function gridCellRenderer(grid,column,options,record=false,complete=false){let paint;return(row,element)=>{if(!GRID_PRESENTER_IMPL.create)return false;return(paint||=GRID_PRESENTER_IMPL.create(grid,column,options,record,complete))(row,element)}}
930
+ DataGrid.prototype.loadPresenters=function(){return this.presenterLoad||=loadPart(GRID_PRESENTERS).then(()=>{this.version++;this.scheduleRender()})};Object.assign(DataGrid.prototype,{setNotice(text,error){clearTimeout(this.gridLoadingTimer);this.notice.replaceChildren();this.notice.hidden=true;this.host.insertBefore(this.notice,this.grid);this.host.classList.remove("cx-grid-awaiting");if(!this.stateCleanup){this.stateCleanup=true;this.lifetime.signal.addEventListener("abort",()=>{clearTimeout(this.gridLoadingTimer);clearTimeout(this.gridSkeletonTimer)},{once:true})}
917
931
  this.notice.className="cx-grid-notice";this.notice.setAttribute("role",error?"alert":"status");if(this.pendingQuery&&!error){const epoch=this.queryEpoch;this.gridLoadingTimer=setTimeout(()=>{if(this.destroyed||epoch!==this.queryEpoch||!this.pendingQuery)return;setText(this.live,this.labels.loading);if(!this.snapshot){this.host.classList.add("cx-grid-awaiting");this.notice.classList.add("cx-initial-skeleton");this.notice.hidden=false;this.host.insertBefore(this.notice,this.grid.nextSibling);for(let index=0;index<6;index++){const row=h("div","cx-skel");row.setAttribute("aria-hidden","true");for(const column of this.visibleColumns()){const cell=h("span"),bar=h("i");cell.style.flex=column.renderWidth||column.width;cell.appendChild(bar);row.appendChild(cell)}this.notice.appendChild(row)}}},150);return}
918
932
  if(error){this.notice.classList.add("cx-banner");const message=h("div"),title=h("b"),detail=h("span","d");setText(title,this.labels.gridLoadFailed);setText(detail,text);message.append(title,document.createTextNode(" "),detail);const retry=gridDecorateButton(gridButton(this.labels.gridRetry,()=>this.retry().catch(()=>{})),"retry",true);retry.classList.add("cx-grid-retry");this.notice.append(message,retry);this.notice.hidden=false;setText(this.live,this.labels.gridLoadFailed+" "+text);return}
919
933
  if(this.snapshot&&(this.cursor?this.cursorWindow.end===this.pageOffset:this.snapshot.matched===0)){const query=this.acceptedQuery,active=!!query.search||gridFilterCount(query)>0,title=h("h4"),reason=h("p"),actions=h("div","acts");this.host.classList.add("cx-grid-awaiting");this.notice.classList.add("cx-state");this.host.insertBefore(this.notice,this.grid.nextSibling);title.setAttribute("aria-level","2");setText(title,fill(active?this.labels.gridNoMatches:this.labels.gridEmpty,{noun:this.noun}));setText(reason,active?fill(this.labels.gridNoMatchesReason,{search:query.search||"—",count:gridFilterCount(query)}):this.view.emptyReason||this.labels.gridEmptyReason);if(active)actions.appendChild(gridButton(this.labels.gridClearAll,()=>this.setQuery(gridQueryStart(this.queryForChange(true),{search:"",filters:[],filterGroup:undefined})).catch(()=>{})));this.notice.append(title,reason,actions);this.notice.hidden=false;setText(this.live,title.textContent+" "+reason.textContent)}else if(text){setText(this.notice,text);this.notice.hidden=false}},paintGridSkeleton(element,row){if(row.status!=="loading"){element._skeleton?.remove();element._skeleton=null;return}
@@ -965,11 +979,11 @@ for(const field of CAL_FIELDS)if(field!=="allDay"&&event[field]!=null){cells[fie
965
979
  return{id,cells}});if(options.resources)used.add("resource");if(pick("sources"))used.add("source");if(drop||create&&!(typeof create==="object"&&create.allDay===false))used.add("allDay");const writable=editable||!!create||drop;const columns=[{id:"title",title:"Title",kind:"text",rowHeader:true,sortable:true,editable:writable},{id:"start",title:"Start",kind:"datetime",sortable:true,editable:writable},{id:"end",title:"End",kind:"datetime",sortable:true,editable:writable},...CAL_FIELDS.filter(field=>used.has(field)).map(field=>({id:field,title:CAL_TITLES[field],kind:"text",hidden:field!=="description",editable:writable&&(field==="resource"||field==="allDay"||field==="recurrence"||field==="exceptions")}))];let toolbar=pick("toolbar");if(options.export===true&&toolbar!==true)toolbar=toolbar===false?["export"]:toolbar.includes("export")?toolbar:[...toolbar,"export"];if(options.export===false&&toolbar!==false)toolbar=(toolbar===true?["search","filters","columns","views","more"]:toolbar.filter(item=>item!=="export"));if(Array.isArray(toolbar)&&!toolbar.length)toolbar=false;const calendar={start:"start",end:"end",title:"title",views:pick("views"),toolbar,details:options.drawer===true?"drawer":options.drawer===false?"popover":pick("details")};for(const field of CAL_FIELDS)if(used.has(field))calendar[field]=field;for(const name of["view","date","timeZone","firstDay","sources"])if(options[name]!==undefined)calendar[name]=options[name];if(editable)calendar.editable=typeof pick("editable")==="object"?pick("editable"):true;if(create)calendar.create=create;if(drop)calendar.drop=true;if(pick("print"))calendar.print=true;const ownViews=own.views!==undefined||options.views!==undefined,addTimeline=()=>{if(!ownViews&&!calendar.views.includes("timeline"))calendar.views=[...calendar.views,"timeline"]};if(options.resources){const list=options.resources,tree=Array.isArray(list)?{protocol:PROTOCOL,type:"view",id:"resources",label:"Resources",rowHeight:34,pageSize:200,selection:"single",columns:[{id:"name",title:"Resource",kind:"text",width:200}],source:{kind:"inline"},roots:calResourceRoots(list)}:list;calendar.resources={view:tree};if(options.timeline!==false&&(options.timeline||options.preset==="scheduler"))addTimeline();if(options.preset==="scheduler")calendar.capacity={thresholds:[{at:3,tone:"warning"},{at:5,tone:"danger"}]}}else if(options.timeline)addTimeline();for(const[name,value]of Object.entries(own))if(!["toolbar","editable","create","drop"].includes(name))calendar[name]=value;if(calendar.toolbar===true)delete calendar.toolbar;if(calendar.details==="drawer")delete calendar.details;const search=calendar.toolbar===undefined||calendar.toolbar!==false&&calendar.toolbar.includes("search");const view={protocol:PROTOCOL,type:"grid",id:options.id??"calendar",label:options.label??"Calendar",rowHeight:34,pageSize:200,selection:"single",search,columns,source:{kind:"inline"},rows,calendar};if(options.live)view.live=options.live===true?{}:options.live;if(options.facets)view.facets=Array.isArray(options.facets)?{columns:options.facets}:options.facets;const hostOptions=Object.fromEntries(Object.entries(options).filter(([name])=>!CAL_OWN.has(name)));if(options.links)hostOptions.linkEvents=true;if(Object.keys(hooks).length)hostOptions.calendar=hooks;return createDataGrid(host,{...hostOptions,view})}
966
980
  function calResourceRoots(list){const nodes=new Map(list.map(item=>[String(item.id),{id:String(item.id),label:String(item.label??item.id),cells:{name:String(item.label??item.id)},expanded:true}])),roots=[];for(const item of list){const node=nodes.get(String(item.id)),parent=item.parent==null?null:nodes.get(String(item.parent));if(parent)(parent.children||=[]).push(node);else roots.push(node)}
967
981
  return roots}
968
- const GRID_EDITING=definePart(DataGrid,"editing","editing",()=>({DataGrid,FORMS_IMPL,h,setText,fill,gridButton,gridDecorateButton,GRID_ICONS,cellValue,cellText,isCellObject,gridFreeze,gridMomentFromParts,numberFormat,gridQuery,foldText,requireIdentifier,checkDocument,validateGridRows,inlineGridSource,PROTOCOL,boundedPattern,validateGridFacetPage,RECORD_IMPL}));const GRID_EDIT_INIT=DataGrid.prototype.initializeState;const GRID_EDIT_API=["beginEdit","endEdit","setCellValue","validate","commitRow","commitChanges","insertRow","isEditing","hasChanges","undo","redo","canUndo","canRedo","cancelEdit","revertChanges","getChanges","setReadOnly"];GRID_EDIT_API.forEach((name,index)=>{DataGrid.prototype[name]=index<7?function(...args){return this.loadEditing().then(()=>this[name](...args))}:index<15?()=>false:()=>[]});DataGrid.prototype.setReadOnly=function(value){this.editReadOnly=!!value};DataGrid.prototype.loadEditing=function(){return this.editLoad||=loadPart(GRID_EDITING).then(()=>this.startEditing()).catch(error=>{this.editLoad=null;this.emit("error",{error});throw error})};DataGrid.prototype.initializeState=function(){const ready=GRID_EDIT_INIT.call(this);return this.columns.some(column=>column.editable)?Promise.all([ready,this.loadEditing().catch(()=>{})]).then(([result])=>result):ready};DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{gridFacetPanel:"Filter by",gridFacetPanelHide:"Hide the filter panel",gridFacetPanelShow:"Show the filter panel",gridFacetShowMore:"Show {count} more",gridFacetShowFewer:"Show fewer",gridFacetEmptyValue:"(Empty)",gridFacetFrom:"From",gridFacetTo:"To",gridFacetHistogram:"Distribution of {column}",gridFacetBin:"{from} to {to}: {count} rows",gridFacetNoChart:"Too many values to chart",gridFacetClear:"Clear {column}",gridFacetCustom:"Another condition filters this column.",gridFacetResult:"{count} matching rows",gridFacetSelected:"{count} selected",gridFacetValueCount:"{value}, {count} rows",gridFacetCollapse:"Collapse {column}",gridFacetExpand:"Expand {column}",gridFacetInvalid:"Enter a valid value.",gridFacetReversed:"From must not be after To."}));const GRID_FACETS=definePart(DataGrid,"facets","facet panel",()=>({DataGrid,h,setText,fill,gridButton,gridIcon,gridQueryStart,gridQueryRows,gridColumnProjection,gridScalar,gridOrder,cellText,foldText,numberFormat,gridCellRenderer,gridFreeze}));Object.assign(DataGrid.prototype,{loadFacets(){return this.facetLoad||=loadPart(GRID_FACETS).then(()=>this.destroyed||this.startFacets()).catch(error=>{this.facetLoad=null;throw error})},setFacetPanelOpen(open){return this.loadFacets().then(()=>this.setFacetPanelOpen(open))},getFacetPanel(){return gridFreeze({open:this.facetOpen??null,columns:(this.facetColumns||[]).map(facet=>facet.column)})}});const FACET_STATE={get:DataGrid.prototype.getState,read:DataGrid.prototype.readGridState,apply:DataGrid.prototype.applyStatePresentation,init:DataGrid.prototype.initializeState};Object.assign(DataGrid.prototype,{getState(){const state=FACET_STATE.get.call(this);if((this.view.facets||this.opts.facets)&&this.facetOpen!==undefined)state.facets={open:this.facetOpen};return state},readGridState(input){const state=FACET_STATE.read.call(this,input);if(input.facets!==undefined){const facets=input.facets;if(!facets||typeof facets!=="object"||Array.isArray(facets)||Object.keys(facets).some(key=>key!=="open")||typeof facets.open!=="boolean")
982
+ const GRID_EDITING=definePart(DataGrid,"editing","editing",()=>({DataGrid,FORMS_IMPL,h,setText,fill,gridButton,gridDecorateButton,GRID_ICONS,cellValue,cellText,isCellObject,gridFreeze,gridMomentFromParts,numberFormat,gridQuery,foldText,requireIdentifier,checkDocument,validateGridRows,inlineGridSource,PROTOCOL,boundedPattern,validateGridFacetPage,RECORD_IMPL}));const GRID_EDIT_INIT=DataGrid.prototype.initializeState;const GRID_EDIT_API=["beginEdit","endEdit","setCellValue","validate","commitRow","commitChanges","insertRow","isEditing","hasChanges","undo","redo","canUndo","canRedo","cancelEdit","revertChanges","getChanges","setReadOnly"];GRID_EDIT_API.forEach((name,index)=>{DataGrid.prototype[name]=index<7?function(...args){return this.loadEditing().then(()=>this[name](...args))}:index<15?()=>false:()=>[]});DataGrid.prototype.setReadOnly=function(value){this.editReadOnly=!!value};DataGrid.prototype.loadEditing=function(){return this.editLoad||=loadPart(GRID_EDITING).then(()=>this.startEditing()).catch(error=>{this.editLoad=null;this.emit("error",{error});throw error})};DataGrid.prototype.initializeState=function(){const ready=GRID_EDIT_INIT.call(this);return this.columns.some(column=>column.editable)?Promise.all([ready,this.loadEditing().catch(()=>{})]).then(([result])=>result):ready};DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{gridFacetPanel:"Filter by",gridFacetPanelHide:"Hide the filter panel",gridFacetPanelShow:"Show the filter panel",gridFacetShowMore:"Show {count} more",gridFacetShowFewer:"Show fewer",gridFacetEmptyValue:"(Empty)",gridFacetFrom:"From",gridFacetTo:"To",gridFacetHistogram:"Distribution of {column}",gridFacetBin:"{from} to {to}: {count} rows",gridFacetNoChart:"Too many values to chart",gridFacetClear:"Clear {column}",gridFacetCustom:"Another condition filters this column.",gridFacetResult:"{count} matching rows",gridFacetSelected:"{count} selected",gridFacetValueCount:"{value}, {count} rows",gridFacetCollapse:"Collapse {column}",gridFacetExpand:"Expand {column}",gridFacetInvalid:"Enter a valid value.",gridFacetReversed:"From must not be after To."}));const GRID_FACETS=definePart(DataGrid,"facets","facet panel",()=>({DataGrid,h,setText,fill,gridButton,gridIcon,gridQueryStart,gridQueryRows,gridColumnProjection,gridScalar,gridOrder,gridKeyCompare,gridFacetKey,cellText,foldText,numberFormat,gridCellRenderer,gridFreeze}));Object.assign(DataGrid.prototype,{loadFacets(){return this.facetLoad||=loadPart(GRID_FACETS).then(()=>this.destroyed||this.startFacets()).catch(error=>{this.facetLoad=null;throw error})},setFacetPanelOpen(open){return this.loadFacets().then(()=>this.setFacetPanelOpen(open))},getFacetPanel(){return gridFreeze({open:this.facetOpen??null,columns:(this.facetColumns||[]).map(facet=>facet.column)})}});const FACET_STATE={get:DataGrid.prototype.getState,read:DataGrid.prototype.readGridState,apply:DataGrid.prototype.applyStatePresentation,init:DataGrid.prototype.initializeState};Object.assign(DataGrid.prototype,{getState(){const state=FACET_STATE.get.call(this);if((this.view.facets||this.opts.facets)&&this.facetOpen!==undefined)state.facets={open:this.facetOpen};return state},readGridState(input){const state=FACET_STATE.read.call(this,input);if(input.facets!==undefined){const facets=input.facets;if(!facets||typeof facets!=="object"||Array.isArray(facets)||Object.keys(facets).some(key=>key!=="open")||typeof facets.open!=="boolean")
969
983
  throw new Error("CanopyX: invalid saved facet panel state.");if(this.view.facets||this.opts.facets)state.facets={open:facets.open}}
970
984
  return state},applyStatePresentation(state){const applied=FACET_STATE.apply.call(this,state);if(state.facets&&state.facets.open!==this.facetOpen&&!this.destroyed){if(this.facetPanel)this.setFacetPanelOpen(state.facets.open).catch(error=>this.emit("error",{error}));else this.facetOpen=state.facets.open}
971
985
  return applied},initializeState(){if(this.initialState?.facets)this.facetOpen=this.initialState.facets.open;const ready=FACET_STATE.init.call(this);return this.view.facets||this.opts.facets?Promise.all([ready,this.loadFacets().catch(error=>this.emit("error",{error}))]).then(([result])=>result):ready}});const GRID_FORMAT=definePart(DataGrid,"formatting","conditional formatting",()=>({DataGrid,h,setText,setClass,fill,gridFreeze,gridDateInputMoment,cellValue,cellText,foldText,toneOf,numberFormat,gridButton,gridOption,gridInputLabel,gridIcon,gridDecorateButton,GRID_REPORTING,loadPart,definePart,announceMenu,boundedPattern,wildcardMatch,svgIcon}));Object.assign(DataGrid.prototype,{loadFormatting(){return this.formatLoad||=loadPart(GRID_FORMAT).then(()=>this.startFormatting(),error=>{this.formatLoad=null;throw error})},setFormatRules(rules){return this.loadFormatting().then(()=>this.setFormatRules(rules))},validateFormatRules(rules){return this.loadFormatting().then(()=>this.validateFormatRules(rules))},openFormatRules(){return this.loadFormatting().then(()=>this.openFormatRules())},getFormatRules(){return gridFreeze(JSON.parse(JSON.stringify(this.formatRules||this.view.formatRules||[])))}});DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{gridLiveOrderChanged:"Order changed",gridLiveResort:"Re-sort",gridLiveNewData:"New data",gridLiveRefresh:"Refresh",gridLiveOrderHint:"Rows keep their places while data changes. Re-sort to move them where the sort puts them.",gridLiveChanged:"Rows changed: {added} added, {updated} updated, {removed} removed",gridLiveSorted:"Rows moved to their sorted places.",gridLiveRecordRemoved:"This record was removed."}));const GRID_LIVE=definePart(DataGrid,"live","live data",()=>({DataGrid,h,setText,fill,gridButton,gridIcon,gridQuery,gridResultShape,gridQueryRows,gridCompare,gridOrder,gridIdOrder,validateGridRows,validateGridPage,validateGridCursorPage,gridFreeze,requireIdentifier,checkDocument,cellValue,PROTOCOL,GRID_REPORTING,VIEW_MODES,inlineGridSource}));const GRID_LIVE_API=["applyTransaction","addRows","updateRows","removeRows","setRows","flushTransactions","refreshRows","resort","poll"];for(const name of GRID_LIVE_API)DataGrid.prototype[name]=function(...args){return this.loadLive().then(()=>this[name](...args))};Object.assign(DataGrid.prototype,{loadLive(){if(this.view.rowIdentity==="ordinal")return Promise.reject(new Error("CanopyX: ordinal row identity is snapshot-local; keyed live updates require stable row keys."));return this.liveLoad||=loadPart(GRID_LIVE).then(()=>this.destroyed||this.startLive()).catch(error=>{this.liveLoad=null;throw error})},getLiveState(){return this.liveStatus?this.liveStatus():gridFreeze({orderChanged:false,newData:false,pending:0,polling:false,revision:this.snapshot?.revision??null})}});const GRID_LIVE_INIT=DataGrid.prototype.initializeState;DataGrid.prototype.initializeState=function(){const ready=GRID_LIVE_INIT.call(this);return this.view.live&&this.opts.live!==false||this.opts.live?Promise.all([ready,this.loadLive().catch(error=>this.emit("error",{error}))]).then(([result])=>result):ready};const GRID_PAGER_IMPL={},GRID_PAGER=definePart(DataGrid,"pager","pager controls",()=>({DataGrid,GRID_PAGER_IMPL,h,setText,fill,gridButton,gridOption,numberFormat,gridCountLabel}));const GRID_PAGER_INIT=DataGrid.prototype.initializeState;DataGrid.prototype.initializeState=function(){const ready=GRID_PAGER_INIT.call(this);return!this.pager||!this.view.pager||GRID_PAGER_IMPL.installed?ready:Promise.all([ready,loadPart(GRID_PAGER).then(()=>this.destroyed||this.buildPager())
972
- .catch(error=>{this.pager.hidden=this.opts.toolbar===false;this.emit("error",{error})})]).then(([result])=>result)};DataGrid.prototype.parts["record-panel"]=RECORD_PART;RECORD_IMPL.grid={DataGrid,gridCellRenderer,createDataGrid,gridFreeze,gridQuery,gridResultShape,validatePresenter:gridPresenter};DataGrid.prototype.openRecord=TreeGrid.prototype.openRecord;DataGrid.prototype.loadRecordPanel=function(){return this.recordLoad||=loadRecordPanel().then(()=>{this.version++;this.scheduleRender()},error=>this.emit("error",{error}))};DataGrid.prototype.recordNeeded=function(row){return!!this.view.record||this.columns.some(column=>column.presenter?.kind==="structured")||
986
+ .catch(error=>{this.pager.hidden=this.opts.toolbar===false;this.emit("error",{error})})]).then(([result])=>result)};const PRESENTERS_INIT=DataGrid.prototype.initializeState;DataGrid.prototype.initializeState=function(){const ready=PRESENTERS_INIT.call(this);return[...this.columns,...(this.view.record?.fields||[])].some(column=>column.presenter||column.wrap)?Promise.all([ready,this.loadPresenters()]).then(([result])=>result):ready};DataGrid.prototype.parts["record-panel"]=RECORD_PART;RECORD_IMPL.grid={DataGrid,gridCellRenderer,createDataGrid,gridFreeze,gridQuery,gridResultShape,validatePresenter:gridPresenter};DataGrid.prototype.openRecord=TreeGrid.prototype.openRecord;DataGrid.prototype.loadRecordPanel=function(){return this.recordLoad||=loadRecordPanel().then(()=>{this.version++;this.scheduleRender()},error=>this.emit("error",{error}))};DataGrid.prototype.recordNeeded=function(row){return!!this.view.record||this.columns.some(column=>column.presenter?.kind==="structured")||
973
987
  !!row&&Object.values(row.cells).some(cell=>isCellObject(cell)&&RECORD_STRUCTURE.some(name=>cell[name]!==undefined))};const GRID_RECORD_INIT=DataGrid.prototype.initializeState;DataGrid.prototype.initializeState=function(){const ready=GRID_RECORD_INIT.call(this);return this.columns.some(column=>column.presenter?.kind==="structured")?Promise.all([ready,this.loadRecordPanel()]).then(([result])=>result):ready};const GRID_DATA_IMPL={},GRID_DATA=definePart(DataGrid,"data","row data",()=>({GRID_DATA_IMPL,PROTOCOL,validateGridRows,inlineGridSource,loadSidecar,gridIdOrder}));function rowDataSource(grid){let inner=null;const source={reset:()=>{inner=null},query:(query,options)=>
974
988
  (inner||=loadPart(GRID_DATA).then(()=>GRID_DATA_IMPL.source(grid,source)).catch(error=>{inner=null;throw error})).then(rows=>rows.query(query,options))};return source}
975
989
  class MatrixHost{}
@@ -1000,7 +1014,7 @@ this.runGridHook(signal=>this.opts.onChart({query:this.getQuery(),selection:this
1000
1014
  {kind:"ids",ids:[...this.selected],revision:this.snapshot?.revision},signal}),this.dataLifetime.signal))),"chart",true));const clear=gridDecorateButton(gridButton("",()=>this.setSelection([])),"close",true);clear.classList.add("icon");clear.setAttribute("aria-label",this.labels.gridClearSelection);this.selectionBar.appendChild(clear);this.toolbarSeparator=h("span","cx-sep");const overflow=this.overflow=this.controlPanel(this.labels.gridMore,"cx-grid-overflow");const 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.gridAction(action,act));overflow.panel.append(this.toolbar.querySelector(".cx-grid-details"),this.toolbar.querySelector(".cx-grid-print")||
1001
1015
  Object.assign(gridButton(this.labels.gridPrint,()=>global.print()),{className:"cx-button cx-grid-print"}));(this.toolbar.querySelector(".cx-grid-export")||overflow.details).before(this.spacer,this.selectionBar,this.toolbarSeparator);for(const item of pluginItems(this,"toolbarItems"))this.spacer.before(this.gridAction(item,act));if(this.tools.more===false){overflow.details.remove();this.overflow=null}
1002
1016
  this.host.addEventListener("canopyx:select",()=>this.syncGridChrome(),{signal});this.syncGridChrome();signal.addEventListener("abort",()=>{this.headerSelectionFlyout?.dispose();this.headerMenusLifetime?.abort();this.closeGridPopover(false)},{once:true})},syncGridChrome(){if(!this.selectionBar)return;const count=this.querySelection?this.querySelection.matched===null?null:Math.max(0,this.querySelection.matched-this.selectionExcluded.size):this.selected.size;const selected=count===null||count>0;this.selectionBar.hidden=!selected;this.toolbarSeparator.hidden=!selected;this.host.classList.toggle("cx-has-selection",selected);gridCountLabel(this.selectedCount,count===null?this.labels.gridSelectionQueryUnknown:this.labels.gridSelectionCount,{count:numberFormat(this.lang).format(count),excluded:String(this.selectionExcluded?.size||0)});const filterSummary=this.toolbar.querySelector(".cx-grid-filters > summary"),active=gridFilterCount(this.acceptedQuery);if(filterSummary){filterSummary.classList.toggle("active",!!active);filterSummary.querySelector(".badge")?.remove();if(active){const badge=h("span","badge");setText(badge,String(active));filterSummary.appendChild(badge)}}
1003
- for(const button of this.selectionBar.querySelectorAll("button"))button.disabled=!!this.pendingQuery||!this.acceptedQuery;this.syncGridStatus?.()},updateGridPhone(){const phone=this.host.clientWidth<=640,autoRows=this.authoredAutoRows||phone&&(this.layoutMode||"fit")==="fit";this.host.classList.toggle("cx-phone",phone);if(phone===this.phone&&autoRows===this.autoRows)return;const anchor=this.gridRowAnchor();const changedRows=autoRows!==this.autoRows;this.phone=phone;this.autoRows=autoRows;if(changedRows){this.rowOffsets=null;this.rowHeights?.clear()}
1017
+ for(const button of this.selectionBar.querySelectorAll("button"))button.disabled=!!this.pendingQuery||!this.acceptedQuery;this.syncGridStatus?.()},updateGridPhone(){const phone=this.host.clientWidth<=640,mode=this.layoutMode||"fit",autoRows=mode!=="cards"&&(this.authoredAutoRows||phone&&mode==="fit");this.host.classList.toggle("cx-phone",phone);if(phone===this.phone&&autoRows===this.autoRows)return;const anchor=this.gridRowAnchor();const changedRows=autoRows!==this.autoRows;this.phone=phone;this.autoRows=autoRows;if(changedRows){this.rowOffsets=null;this.rowHeights?.clear()}
1004
1018
  this.rowWidthShape=null;if(!this.autoRows&&!this.rowProjection){const bounds=this.rowBounds();this.total=Math.max(0,bounds.last-bounds.first+1)*this.rowH;this.syncScrollRange(this.rowTop(anchor.index)+ Math.min(anchor.offset,this.rowH-1))}
1005
1019
  this.version++;this.scheduleRender();this.placeMenus(phone);this.syncPinnedShadows()},syncPinnedShadows(){const overflow=this.grid.scrollWidth>this.grid.clientWidth+1,pins=overflow&&(this.pinnedLeftWidth||this.pinnedRightWidth);this.host.classList.toggle("cx-scroll-x",overflow);this.host.classList.toggle("cx-scroll-left",!!pins&&this.grid.scrollLeft>0);this.host.classList.toggle("cx-scroll-right",!!pins&&this.grid.scrollLeft+this.grid.clientWidth<this.grid.scrollWidth-1)},gridAction(action,act){if(!action||typeof action.label!=="string"||typeof action.run!=="function")throw new Error("CanopyX: actions need a label and handler.");return gridButton(action.label,()=>act(()=>this.runGridHook(signal=>action.run({query:this.getQuery(),signal,api:this.host.canopyx}),this.dataLifetime.signal)))}});function gridColumnFiltered(query,id){const has=group=>group&&(group.filters.some(item=>item.column===id)||group.groups.some(has));return!!query&&(query.filters.some(item=>item.column===id)||!!has(query.filterGroup))}
1006
1020
  function gridColumnProjection(query,id){const project=group=>{if(!group)return undefined;const filters=group.filters.filter(item=>item.column!==id),groups=group.groups.map(project);if(group.operator==="or"&&(filters.length!==group.filters.length||groups.some(child=>!child)))return undefined;const children=groups.filter(Boolean);return filters.length||children.length?{operator:group.operator,filters,groups:children}:undefined};return{...query,filters:(query.filters||[]).filter(item=>item.column!==id),filterGroup:project(query.filterGroup)}}
@@ -1009,7 +1023,7 @@ if(this.gridPopover)this.gridPopover.position()}});const GRID_PIN_PREPARE=DataGr
1009
1023
  let start=0,end=0;for(const column of grid.cols){column.pinOffset=column.effectivePin==="left"?start:0;if(column.effectivePin==="left")start+=width(column)}
1010
1024
  for(const column of[...grid.cols].reverse())if(column.effectivePin==="right"){column.pinOffset=end;end+=width(column)}
1011
1025
  grid.pinnedLeftWidth=start;grid.pinnedRightWidth=end;grid.host.classList.toggle("cx-pins",used>0);grid.cols.forEach((column,index)=>grid.applyColumnPin(grid.headCells[index],column));for(const row of[...grid.rendered.values(),...grid.pool])if(row._kind==="node")grid.cols.forEach((column,index)=>{if(row.children[index])grid.applyColumnPin(row.children[index],column)})}
1012
- DataGrid.prototype.prepareState=function(){gridFitPrepare(this);return GRID_PIN_PREPARE.call(this)};DataGrid.prototype.applyWidths=function(widths){GRID_PIN_WIDTHS.call(this,widths);if(!this.view.reporting)gridPinGeometry(this);this.syncPinnedShadows()};DataGrid.prototype.applyColumnPin=function(cell,column){const pin=column.effectivePin||"none";if(pin==="none")cell.removeAttribute("data-cx-pin");else cell.dataset.cxPin=pin;cell.style.left=pin==="left"?column.pinOffset+"px":"";cell.style.right=pin==="right"?column.pinOffset+"px":"";const side=pin==="left"?this.cols.filter(item=>item.effectivePin==="left").at(-1):this.cols.find(item=>item.effectivePin==="right");cell.classList.toggle("cx-pin-edge",side===column)};DataGrid.prototype.newCell=function(index,width,kind){const cell=GRID_PIN_CELL.call(this,index,width,kind);if(kind&&this.cols[index])this.applyColumnPin(cell,this.cols[index]);return cell};DataGrid.prototype.setColumnPinned=function(id,pin){const column=this.columns.find(item=>item.id===id);if(!column||!["none","left","right"].includes(pin)||this.destroyed)throw new Error("CanopyX: invalid column pin.");column.pin=pin;this.columns=["left","none","right"].flatMap(side=>this.columns.filter(item=>(item.pin||"none")===side));this.buildHeader();this.render();this.syncColumnControls();this.stateChanged();this.emit("columnPin",{column:id,pin})};const GRID_PIN_STATE_COLUMN=gridStateColumn,GRID_PIN_STATE_COLUMNS=gridStateColumns;gridStateColumn=column=>({...GRID_PIN_STATE_COLUMN(column),pin:column.pin||"none"});gridStateColumns=(grid,input)=>{const result=GRID_PIN_STATE_COLUMNS(grid,input),sources=new Map(input.map(column=>[column.id,column]));for(const saved of result){const pin=sources.get(saved.id)?.pin??saved.pin??"none";if(!["none","left","right"].includes(pin))throw new Error("CanopyX: invalid saved pin.");saved.pin=pin}return result};const FILTER_EDITOR=definePart(DataGrid,"filter-editor","filter editor",()=>({DataGrid,h,setText,gridButton,gridInputLabel,gridOption,gridScalar,gridDateInputMoment,gridQuery,gridQueryStart,GRID_FILTER_LABELS,gridResultShape,gridQueryRows,gridOrder,gridColumnProjection,gridCellRenderer,cellValue,cellText,foldText,reachable,gridMatchesGroup,gridDecorateButton,gridIcon,numberFormat,numberText,fill,announceMenu,applyTone,toneOf,badgeElement,isCellObject,RECORD_IMPL,GRID_REPORTING,reportingRangeRows:typeof reportingRangeRows==="function"?reportingRangeRows:null}));function loadGridFilterEditor(){return loadPart(FILTER_EDITOR)}
1026
+ DataGrid.prototype.prepareState=function(){gridFitPrepare(this);return GRID_PIN_PREPARE.call(this)};DataGrid.prototype.applyWidths=function(widths){GRID_PIN_WIDTHS.call(this,widths);if(!this.view.reporting)gridPinGeometry(this);this.syncPinnedShadows()};DataGrid.prototype.applyColumnPin=function(cell,column){const pin=column.effectivePin||"none";if(pin==="none")cell.removeAttribute("data-cx-pin");else cell.dataset.cxPin=pin;cell.style.left=pin==="left"?column.pinOffset+"px":"";cell.style.right=pin==="right"?column.pinOffset+"px":"";const side=pin==="left"?this.cols.filter(item=>item.effectivePin==="left").at(-1):this.cols.find(item=>item.effectivePin==="right");cell.classList.toggle("cx-pin-edge",side===column)};DataGrid.prototype.newCell=function(index,width,kind){const cell=GRID_PIN_CELL.call(this,index,width,kind);if(kind&&this.cols[index])this.applyColumnPin(cell,this.cols[index]);return cell};DataGrid.prototype.setColumnPinned=function(id,pin){const column=this.columns.find(item=>item.id===id);if(!column||!["none","left","right"].includes(pin)||this.destroyed)throw new Error("CanopyX: invalid column pin.");column.pin=pin;this.columns=["left","none","right"].flatMap(side=>this.columns.filter(item=>(item.pin||"none")===side));this.buildHeader();this.render();this.syncColumnControls();this.stateChanged();this.emit("columnPin",{column:id,pin})};const GRID_PIN_STATE_COLUMN=gridStateColumn,GRID_PIN_STATE_COLUMNS=gridStateColumns;gridStateColumn=column=>({...GRID_PIN_STATE_COLUMN(column),pin:column.pin||"none"});gridStateColumns=(grid,input)=>{const result=GRID_PIN_STATE_COLUMNS(grid,input),sources=new Map(input.map(column=>[column.id,column]));for(const saved of result){const pin=sources.get(saved.id)?.pin??saved.pin??"none";if(!["none","left","right"].includes(pin))throw new Error("CanopyX: invalid saved pin.");saved.pin=pin}return result};const FILTER_EDITOR=definePart(DataGrid,"filter-editor","filter editor",()=>({DataGrid,h,setText,gridButton,gridInputLabel,gridOption,gridScalar,gridDateInputMoment,gridQuery,gridQueryStart,GRID_FILTER_LABELS,gridResultShape,gridQueryRows,gridOrder,gridKeyCompare,gridFacetKey,columnNumericTone,columnValueTone,gridColumnProjection,gridCellRenderer,cellValue,cellText,foldText,reachable,gridMatchesGroup,gridDecorateButton,gridIcon,numberFormat,numberText,fill,announceMenu,applyTone,toneOf,badgeElement,isCellObject,RECORD_IMPL,GRID_REPORTING,reportingRangeRows:typeof reportingRangeRows==="function"?reportingRangeRows:null}));function loadGridFilterEditor(){return loadPart(FILTER_EDITOR)}
1013
1027
  DataGrid.prototype.requirePart=requirePart;Object.assign(DataGrid.prototype,{buildGridFilters(){this.reportingFacetStops=new Set();this.reportingFacetSequence=0;if(this.tools.filters===false||!this.columns.some(column=>column.filterable!==false))return;this.reportingFilters=this.controlPanel(this.labels.gridFilters,"cx-grid-filters",panel=>this.renderGridFilters(panel))},async renderGridFilters(panel){const epoch=this.queryEpoch;setText(panel,this.labels.loading);try{await loadGridFilterEditor();if(epoch!==this.queryEpoch){panel.parentElement.open=false;return}if(!this.destroyed&&panel.isConnected&&panel.parentElement.open){this.renderGridFilters(panel);this.controlFlyouts.forEach(item=>item.position())}}
1014
1028
  catch(error){if(!this.destroyed&&panel.isConnected){setText(panel,this.labels.gridLoadFailed);panel.appendChild(gridButton(this.labels.gridRetry,()=>this.renderGridFilters(panel)));this.emit("error",{error})}}},async showReportingText(...args){const epoch=this.queryEpoch;try{await loadGridFilterEditor();if(!this.destroyed&&epoch===this.queryEpoch)this.showReportingText(...args)}catch(error){this.emit("error",{error})}},});for(const method of["openColumnMenu","openColumnFilter"])DataGrid.prototype[method]=async function(id,anchor){try{await loadGridFilterEditor();if(!this.destroyed)this[method](id,anchor?.isConnected?anchor:this.headRow.querySelector('[data-cx-column-menu="'+CSS.escape(id)+'"]'))}
1015
1029
  catch(error){this.setNotice(this.labels.gridLoadFailed,true);this.emit("error",{error})}};function gridOperationActive(grid,signal){if(grid.destroyed||signal?.aborted)throw new DOMException("Grid cancelled.","AbortError")}
@@ -1019,7 +1033,7 @@ const prepared=grid.calIcsFormatWriter&&provider?.write===grid.calIcsFormatWrite
1019
1033
  const gridExportSignal=(signal,options)=>AbortSignal.any([signal,options?.signal].filter(Boolean));Object.assign(DataGrid.prototype,{defaultExportColumns(){return this.visibleColumns().filter(column=>column.exportable!==false)},prepareExport(options){if(!this.view.reporting&&["fileName","locale","timeZone","onProgress"].some(key=>options?.[key]!==undefined))
1020
1034
  throw new Error("CanopyX: export metadata requires reporting.");if(this.destroyed||!this.acceptedQuery)throw new Error("CanopyX: export needs an accepted query.");if(!options||!["filtered","selected","all"].includes(options.scope))throw new Error("CanopyX: explicit export scope required.");const{scope,values,signal}=options,filtered=scope==="filtered";const selection=scope==="selected"?[...this.selected]:[];const columnIds=options.columns===undefined?this.defaultExportColumns().map(column=>column.id):options.columns;if(options.columns===undefined&&!columnIds.length)throw new Error(this.labels.gridNoExportColumns);const columns=Array.isArray(columnIds)?columnIds.map(id=>this.columns.find(column=>column.id===id)):[];if(!Array.isArray(columnIds)||!columnIds.length||new Set(columnIds).size!==columnIds.length||
1021
1035
  columns.some(column=>!column||column.exportable===false))throw new Error("CanopyX: invalid or unsupported export columns.");if(values!==undefined&&!["raw","display"].includes(values))throw new Error("CanopyX: export values must be raw/display.");if(signal!==undefined&&!(signal instanceof AbortSignal))throw new Error("CanopyX: export requires AbortSignal.");const query=gridQuery(this.view,{...this.acceptedQuery,offset:0,cursor:undefined,limit:this.pageSize,search:filtered?this.acceptedQuery.search:"",filterGroup:filtered?this.acceptedQuery.filterGroup:undefined,filters:filtered?this.acceptedQuery.filters:[]});const{revision,total,matched}=this.snapshot;const request=gridFreeze({scope,query,revision,total,matched,recordCount:scope==="selected"?selection.length:
1022
- filtered?matched:total,selection,columns:columns.map(({id,title,kind,format})=>({id,title,kind,...(format?{format:{...format}}:{})})),presentation:GRID_REPORTING.exportRecord?"semantic":"text",values:values||"display",timeZone:this.local?"local":"utc",...GRID_REPORTING.exportRequest?.(this,options)});return Object.freeze({request,rows:options=>this.exportRows(request,gridExportSignal(signal,options))})}});DataGrid.drawerHooks=[];DataGrid.activeDrawers=new Map();DataGrid.applyDrawerHooks=(grid,dialog)=>{const applied=dialog._cxDrawerHooks||=new Set();for(const entry of DataGrid.drawerHooks)if(!applied.has(entry)){applied.add(entry);try{entry.hook.call(grid,dialog)}catch(error){grid.emit("error",{error})}}};DataGrid.refreshDrawerHooks=(grid,dialog)=>{if(dialog._cxHooksFrame)return;dialog._cxHooksFrame=requestAnimationFrame(()=>{dialog._cxHooksFrame=0;if(grid.destroyed||!dialog.isConnected)return;DataGrid.applyDrawerHooks(grid,dialog);if(dialog._cxRecord)dialog.dispatchEvent(new CustomEvent("cx-drawer-paint",{detail:{id:dialog._cxRecord.id,index:dialog._cxIndex??null}}))})};DataGrid.drawerHook=(order,hook)=>{DataGrid.drawerHooks.push({order,hook});DataGrid.drawerHooks.sort((a,b)=>a.order-b.order);for(const[dialog,grid]of DataGrid.activeDrawers)DataGrid.refreshDrawerHooks(grid,dialog)};Object.assign(DataGrid.prototype,{focusRing:focusDrawerTitle,scrollToRow(index){if(this.destroyed||!this.acceptedQuery||this.pendingQuery||!Number.isInteger(index)||
1036
+ filtered?matched:total,selection,columns:columns.map(({id,title,kind,format,valueLabels})=>({id,title,kind,...(valueLabels?{valueLabels:{...valueLabels}}:{}),...(format?{format:{...format}}:{})})),presentation:GRID_REPORTING.exportRecord?"semantic":"text",values:values||"display",timeZone:this.local?"local":"utc",...GRID_REPORTING.exportRequest?.(this,options)});return Object.freeze({request,rows:options=>this.exportRows(request,gridExportSignal(signal,options))})}});DataGrid.drawerHooks=[];DataGrid.activeDrawers=new Map();DataGrid.applyDrawerHooks=(grid,dialog)=>{const applied=dialog._cxDrawerHooks||=new Set();for(const entry of DataGrid.drawerHooks)if(!applied.has(entry)){applied.add(entry);try{entry.hook.call(grid,dialog)}catch(error){grid.emit("error",{error})}}};DataGrid.refreshDrawerHooks=(grid,dialog)=>{if(dialog._cxHooksFrame)return;dialog._cxHooksFrame=requestAnimationFrame(()=>{dialog._cxHooksFrame=0;if(grid.destroyed||!dialog.isConnected)return;DataGrid.applyDrawerHooks(grid,dialog);if(dialog._cxRecord)dialog.dispatchEvent(new CustomEvent("cx-drawer-paint",{detail:{id:dialog._cxRecord.id,index:dialog._cxIndex??null}}))})};DataGrid.drawerHook=(order,hook)=>{DataGrid.drawerHooks.push({order,hook});DataGrid.drawerHooks.sort((a,b)=>a.order-b.order);for(const[dialog,grid]of DataGrid.activeDrawers)DataGrid.refreshDrawerHooks(grid,dialog)};Object.assign(DataGrid.prototype,{focusRing:focusDrawerTitle,scrollToRow(index){if(this.destroyed||!this.acceptedQuery||this.pendingQuery||!Number.isInteger(index)||
1023
1037
  index<(this.cursor?this.pageOffset:0)||index>=this.rowCount())
1024
1038
  throw new Error("CanopyX: invalid accepted row position.");return this.focusResult(index,false)},async runGridHook(run,signal,timeout=this.requestTimeoutMs){const controller=new AbortController();let rejectHook;const cancelled=new Promise((resolve,reject)=>{rejectHook=reject});const abort=()=>{controller.abort();rejectHook(new DOMException("Grid cancelled.","AbortError"))};this.lifetime.signal.addEventListener("abort",abort,{once:true});signal?.addEventListener("abort",abort,{once:true});const timer=setTimeout(()=>{controller.abort();rejectHook(new Error("CanopyX: operation timed out."))},timeout);try{if(this.destroyed||signal?.aborted)abort();return await Promise.race([Promise.resolve().then(()=>{gridOperationActive(this,controller.signal);return run(controller.signal)}),cancelled])}finally{clearTimeout(timer);controller.abort();this.lifetime.signal.removeEventListener("abort",abort);signal?.removeEventListener("abort",abort)}},openDetails(id){requireIdentifier(id,"detail row ID");if(this.destroyed||!this.acceptedQuery||this.pendingQuery)
1025
1039
  throw new Error("CanopyX: details require an accepted query.");const row=[...this.rowCache.values()].find(item=>item.key===id);if(!row)throw new Error("CanopyX: details require a loaded record.");if(typeof this.opts.onDetails!=="function"){const epoch=this.queryEpoch,returnFocus=document.activeElement;return Promise.all([loadGridFilterEditor(),this.recordNeeded(row.h)&&loadRecordPanel()]).then(()=>{if(!this.destroyed&&!this.pendingQuery&&epoch===this.queryEpoch)this.openGridDrawer(row.h,row._ri,returnFocus)})}
@@ -1,4 +1,4 @@
1
- (function(global){"use strict";const installed=new WeakSet();const part={version:"0970f2edbcb32de8",requires:["detail-rows"],install(context){if(installed.has(context.DataGrid.prototype))return;const{DataGrid,GRID_ROWS,GRID_REPORTING,h,setText,fill,numberFormat,formatValue,cellValue,cellText,isCellObject,gridScalar,gridQuery,gridFreeze,gridOrder,gridIdOrder,gridQueryRows,gridButton,gridDecorateButton,gridCellRenderer,gridPresenterTone,GRID_TONE_RANK,validateGridRows,validateGridPage,checkDocument,requireIdentifier,validStructuralCount,PROTOCOL,gridOperationActive,reportingGroupKey,reportingGroupCompare,reportingSummaryEnabled,reportingDynamicGroups,GROUP_OPERATIONS,reportingAggregateParts,disposeRowHostCells,quietControls,TreeGrid}=context;const groupCounting=operation=>operation==="count"||operation==="distinctCount";function groupCustomAggregates(grid){const found=new Map();for(const plugin of grid.plugins)for(const[name,entry]of Object.entries(plugin.aggregates||{})){const definition=typeof entry==="function"?{compute:entry}:entry;if(!/^[a-z][a-zA-Z\d]{0,31}$/.test(name) || GROUP_OPERATIONS.includes(name) || !definition || typeof definition.compute !== "function" ||
1
+ (function(global){"use strict";const installed=new WeakSet();const part={version:"0e0a3529c0b099d7",requires:["detail-rows"],install(context){if(installed.has(context.DataGrid.prototype))return;const{DataGrid,GRID_ROWS,GRID_REPORTING,h,setText,fill,numberFormat,formatValue,cellValue,cellText,isCellObject,gridScalar,gridQuery,gridFreeze,gridOrder,gridIdOrder,gridQueryRows,gridButton,gridDecorateButton,gridCellRenderer,gridPresenterTone,GRID_TONE_RANK,validateGridRows,validateGridPage,checkDocument,requireIdentifier,validStructuralCount,PROTOCOL,gridOperationActive,reportingGroupKey,reportingGroupCompare,reportingSummaryEnabled,reportingDynamicGroups,GROUP_OPERATIONS,reportingAggregateParts,disposeRowHostCells,quietControls,TreeGrid}=context;const groupCounting=operation=>operation==="count"||operation==="distinctCount";function groupCustomAggregates(grid){const found=new Map();for(const plugin of grid.plugins)for(const[name,entry]of Object.entries(plugin.aggregates||{})){const definition=typeof entry==="function"?{compute:entry}:entry;if(!/^[a-z][a-zA-Z\d]{0,31}$/.test(name) || GROUP_OPERATIONS.includes(name) || !definition || typeof definition.compute !== "function" ||
2
2
  definition.label!==undefined&&(typeof definition.label!=="string"||!definition.label.includes("{value}")||definition.label.length>64))
3
3
  throw new Error("CanopyX: plugin '"+plugin.name+"' registers an invalid aggregate '"+name+"'.");found.set(name,definition)}
4
4
  return found}
@@ -56,7 +56,7 @@ const group=row.group,level=row.level,collapsed=this.collapsedGroups.has(group.k
56
56
  else{element.removeAttribute("aria-level");element.removeAttribute("aria-expanded")}
57
57
  element.style.height=this.rowH+"px";element.style.width=this.rowWidth+"px";element.style.setProperty("--cx-group-level",String(level-1));const priorButton=previous?.[0].cell.querySelector(".cx-grid-group-toggle"),button=priorButton||h("button","cx-grid-group-toggle");if(!priorButton){button.type="button";button.tabIndex=-1}
58
58
  if(button.disabled!==!!this.pendingQuery)button.disabled=!!this.pendingQuery;button.setAttribute("aria-expanded",String(!collapsed));button.setAttribute("aria-label",collapsed?this.labels.gridGroupExpand:this.labels.gridGroupCollapse);if(button.textContent!==(collapsed?"▸":"▾"))setText(button,collapsed?"▸":"▾");if(!priorButton)button.addEventListener("click",()=>{if(this.pendingQuery)return;try{this.setFocus(row,false);this.setGroupCollapsed(group.key,!this.collapsedGroups.has(group.key));this.setFocus(this.focused,true)}
59
- catch(error){this.emit("error",{error})}});const value=group.value===null?this.labels.gridGroupMissing:formatValue(group.value,groupColumn.kind,this.fmt,groupColumn.format),count=numberFormat(this.lang).format(group.count);const label=fill(this.labels.gridGroupHeading,{column:groupColumn.title,value,count}),cells=[];this.cols.forEach((column,index)=>{const cell=previous?.[index].cell||this.cell(element,index,column.width,column.kind);cells.push({cell,content:cell});if(index===0){const priorHeading=cell.querySelector(".cx-grid-group-label"),heading=priorHeading||h("span","cx-grid-group-label");const text=heading.querySelector(".cx-grid-group-text")||h("span","cx-grid-group-text"),badge=heading.querySelector(".cx-grid-group-count")||h("span","cx-grid-group-count");text.replaceChildren();if(levels.length>1){const name=h("span","cx-grid-group-column");setText(name,groupColumn.title);text.append(name,document.createTextNode(" "))}
59
+ catch(error){this.emit("error",{error})}});const value=group.value===null?this.labels.gridGroupMissing:cellText(group.value,groupColumn,this.fmt),count=numberFormat(this.lang).format(group.count);const label=fill(this.labels.gridGroupHeading,{column:groupColumn.title,value,count}),cells=[];this.cols.forEach((column,index)=>{const cell=previous?.[index].cell||this.cell(element,index,column.width,column.kind);cells.push({cell,content:cell});if(index===0){const priorHeading=cell.querySelector(".cx-grid-group-label"),heading=priorHeading||h("span","cx-grid-group-label");const text=heading.querySelector(".cx-grid-group-text")||h("span","cx-grid-group-text"),badge=heading.querySelector(".cx-grid-group-count")||h("span","cx-grid-group-count");text.replaceChildren();if(levels.length>1){const name=h("span","cx-grid-group-column");setText(name,groupColumn.title);text.append(name,document.createTextNode(" "))}
60
60
  text.appendChild(document.createTextNode(value));setText(badge,count);if(!priorHeading)heading.append(text,badge);if(!priorButton)cell.append(button);this.paintGroupSelection(cell,group);if(!priorHeading)cell.append(heading);cell.title=label;this.paintHiddenAggregates(heading,group.aggregates,cell,column.id,label);return}
61
61
  const aggregates=(this.view.reporting.aggregates||[]).filter(item=>item.column===column.id);if(aggregates.length)this.paintAggregates(cell,column,aggregates,group.aggregates);else{cell.replaceChildren();if(Object.hasOwn(group.cells||{},column.id)){const options=column.presenter||this.view.reporting.presenters?.[column.id];if(options)gridCellRenderer(this,column,options)({id:group.key,cells:group.cells},cell);else setText(cell,cellText(group.cells[column.id],column,this.fmt))}}});let room=this.cols[0].renderWidth??this.cols[0].width;for(let index=1;index<cells.length&&!cells[index].cell.textContent;index++)room +=this.cols[index].renderWidth??this.cols[index].width;const heading=cells[0].cell.querySelector(".cx-grid-group-label");heading.style.maxWidth=Math.max(40,room-44 -(level-1)*16 -(this.view.reporting.selectionControls&&this.multi?22:0))+ "px";element._cells=cells;quietControls(element);this.paintGridHighlights(element,row)},paintGroupSelection(cell,group){if(!this.view.reporting.selectionControls||!this.multi)return;const previous=cell.querySelector(".cx-grid-group-select"),check=previous||h("input","cx-grid-row-select cx-grid-group-select");if(!previous){check.type="checkbox";check.tabIndex=-1}
62
62
  const state=this.groupSelection(group);check.checked=state===true;check.indeterminate=state==="mixed";check.disabled=!!this.pendingQuery;check.setAttribute("aria-label",fill(this.labels.gridSelectGroup,{group:group.value===null?this.labels.gridGroupMissing:String(group.value)}));if(!previous)check.addEventListener("click",event=>{event.preventDefault();event.stopPropagation();this.runReportingSelection(()=>this.selectRange(group.offset,group.offset+group.count-1,{selected:this.groupSelection(group)!==true,additive:true}))});if(!previous)cell.appendChild(check)},groupSelection(group){let selected=0,loaded=0;for(const[ordinal,record]of this.rowCache){if(ordinal<group.offset||ordinal>=group.offset+group.count)continue;loaded++;if(this.reportingRowSelected(record))selected++}