@evotecit/canopyx 0.3.11 → 0.3.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/CanopyX.Html/Assets/canopyx-calendar-edit.js +36 -18
  2. package/CanopyX.Html/Assets/canopyx-calendar-ics.js +7 -5
  3. package/CanopyX.Html/Assets/canopyx-calendar.css +124 -116
  4. package/CanopyX.Html/Assets/canopyx-calendar.js +74 -54
  5. package/CanopyX.Html/Assets/canopyx-cell-range.css +8 -8
  6. package/CanopyX.Html/Assets/canopyx-cell-range.js +1 -1
  7. package/CanopyX.Html/Assets/canopyx-changes.css +113 -113
  8. package/CanopyX.Html/Assets/canopyx-changes.js +7 -10
  9. package/CanopyX.Html/Assets/canopyx-column-groups.css +5 -5
  10. package/CanopyX.Html/Assets/canopyx-column-groups.js +1 -1
  11. package/CanopyX.Html/Assets/canopyx-data.js +2 -2
  12. package/CanopyX.Html/Assets/canopyx-detail-rows.css +9 -9
  13. package/CanopyX.Html/Assets/canopyx-detail-rows.js +2 -2
  14. package/CanopyX.Html/Assets/canopyx-editing.css +18 -18
  15. package/CanopyX.Html/Assets/canopyx-editing.js +1 -1
  16. package/CanopyX.Html/Assets/canopyx-enhance.js +2 -2
  17. package/CanopyX.Html/Assets/canopyx-export.js +8 -4
  18. package/CanopyX.Html/Assets/canopyx-facets.css +33 -33
  19. package/CanopyX.Html/Assets/canopyx-facets.js +10 -11
  20. package/CanopyX.Html/Assets/canopyx-filter-editor.css +57 -57
  21. package/CanopyX.Html/Assets/canopyx-filter-editor.js +15 -11
  22. package/CanopyX.Html/Assets/canopyx-flow-checks.css +11 -11
  23. package/CanopyX.Html/Assets/canopyx-flow-checks.js +1 -1
  24. package/CanopyX.Html/Assets/canopyx-flow-command.css +7 -7
  25. package/CanopyX.Html/Assets/canopyx-flow-command.js +1 -1
  26. package/CanopyX.Html/Assets/canopyx-flow-dialog.css +7 -7
  27. package/CanopyX.Html/Assets/canopyx-flow-dialog.js +1 -1
  28. package/CanopyX.Html/Assets/canopyx-flow-drafts.css +7 -7
  29. package/CanopyX.Html/Assets/canopyx-flow-drafts.js +1 -1
  30. package/CanopyX.Html/Assets/canopyx-flow-entry.css +17 -76
  31. package/CanopyX.Html/Assets/canopyx-flow-entry.js +9 -3
  32. package/CanopyX.Html/Assets/canopyx-flow-host.css +4 -4
  33. package/CanopyX.Html/Assets/canopyx-flow-host.js +1 -1
  34. package/CanopyX.Html/Assets/canopyx-flow-module.mjs +9 -3
  35. package/CanopyX.Html/Assets/canopyx-flow-pick.css +4 -4
  36. package/CanopyX.Html/Assets/canopyx-flow-pick.js +1 -1
  37. package/CanopyX.Html/Assets/canopyx-flow-preview.css +6 -6
  38. package/CanopyX.Html/Assets/canopyx-flow-preview.js +1 -1
  39. package/CanopyX.Html/Assets/canopyx-flow-records.css +3 -3
  40. package/CanopyX.Html/Assets/canopyx-flow-records.js +1 -1
  41. package/CanopyX.Html/Assets/canopyx-flow-tasks.css +17 -17
  42. package/CanopyX.Html/Assets/canopyx-flow-tasks.js +1 -1
  43. package/CanopyX.Html/Assets/canopyx-flow.css +79 -79
  44. package/CanopyX.Html/Assets/canopyx-flow.js +1 -1
  45. package/CanopyX.Html/Assets/canopyx-format-editor.css +23 -23
  46. package/CanopyX.Html/Assets/canopyx-format-editor.js +2 -3
  47. package/CanopyX.Html/Assets/canopyx-formatting.css +17 -17
  48. package/CanopyX.Html/Assets/canopyx-formatting.js +5 -5
  49. package/CanopyX.Html/Assets/canopyx-forms.css +5 -5
  50. package/CanopyX.Html/Assets/canopyx-forms.js +1 -1
  51. package/CanopyX.Html/Assets/canopyx-grid-module.mjs +134 -77
  52. package/CanopyX.Html/Assets/canopyx-grid-options.css +10 -0
  53. package/CanopyX.Html/Assets/canopyx-grid-options.js +47 -0
  54. package/CanopyX.Html/Assets/canopyx-grid.css +199 -261
  55. package/CanopyX.Html/Assets/canopyx-grid.js +134 -77
  56. package/CanopyX.Html/Assets/canopyx-grouping.css +17 -17
  57. package/CanopyX.Html/Assets/canopyx-grouping.js +12 -9
  58. package/CanopyX.Html/Assets/canopyx-highlight.css +14 -14
  59. package/CanopyX.Html/Assets/canopyx-highlight.js +2 -2
  60. package/CanopyX.Html/Assets/canopyx-interactive.css +94 -155
  61. package/CanopyX.Html/Assets/canopyx-interactive.js +58 -24
  62. package/CanopyX.Html/Assets/canopyx-labels-de.js +5 -0
  63. package/CanopyX.Html/Assets/canopyx-labels-es.js +5 -0
  64. package/CanopyX.Html/Assets/canopyx-labels-fr.js +5 -0
  65. package/CanopyX.Html/Assets/canopyx-labels-it.js +5 -0
  66. package/CanopyX.Html/Assets/canopyx-labels-pl.js +5 -0
  67. package/CanopyX.Html/Assets/canopyx-layouts.css +17 -17
  68. package/CanopyX.Html/Assets/canopyx-layouts.js +4 -12
  69. package/CanopyX.Html/Assets/canopyx-link.css +7 -7
  70. package/CanopyX.Html/Assets/canopyx-link.js +1 -1
  71. package/CanopyX.Html/Assets/canopyx-live.css +9 -9
  72. package/CanopyX.Html/Assets/canopyx-live.js +2 -2
  73. package/CanopyX.Html/Assets/canopyx-matrix.css +74 -74
  74. package/CanopyX.Html/Assets/canopyx-matrix.js +3 -4
  75. package/CanopyX.Html/Assets/canopyx-module.mjs +58 -24
  76. package/CanopyX.Html/Assets/canopyx-pager.css +2 -2
  77. package/CanopyX.Html/Assets/canopyx-pager.js +1 -1
  78. package/CanopyX.Html/Assets/canopyx-presenters.js +11 -0
  79. package/CanopyX.Html/Assets/canopyx-record-panel.css +49 -49
  80. package/CanopyX.Html/Assets/canopyx-record-panel.js +13 -11
  81. package/CanopyX.Html/Assets/canopyx-reporting-module.mjs +142 -84
  82. package/CanopyX.Html/Assets/canopyx-reporting.css +214 -276
  83. package/CanopyX.Html/Assets/canopyx-reporting.js +142 -84
  84. package/CanopyX.Html/Assets/canopyx-timeline.css +28 -28
  85. package/CanopyX.Html/Assets/canopyx-timeline.js +11 -10
  86. package/CanopyX.Html/Assets/canopyx-tree-tools.css +47 -46
  87. package/CanopyX.Html/Assets/canopyx-tree-tools.js +5 -4
  88. package/CanopyX.Html/Assets/canopyx.css +81 -142
  89. package/CanopyX.Html/Assets/canopyx.js +58 -24
  90. package/JavaScript/calendar.d.ts +15 -0
  91. package/JavaScript/grid.d.ts +29 -4
  92. package/JavaScript/hosts.d.ts +11 -0
  93. package/JavaScript/locales/de.mjs +5 -0
  94. package/JavaScript/locales/es.mjs +5 -0
  95. package/JavaScript/locales/fr.mjs +5 -0
  96. package/JavaScript/locales/it.mjs +5 -0
  97. package/JavaScript/locales/pl.mjs +5 -0
  98. package/JavaScript/plugins.d.ts +4 -0
  99. package/JavaScript/protocol.d.ts +14 -1
  100. package/JavaScript/records.d.ts +2 -0
  101. package/README.md +6 -2
  102. package/package.json +7 -1
@@ -26,14 +26,15 @@ function checkPage(doc,node){checkDocument(doc,"page");if(!Array.isArray(doc.ite
26
26
  if(!Object.hasOwn(doc,"next"))throw new Error("CanopyX: page continuation is required.");if(doc.next!==null)requireIdentifier(doc.next,"page continuation");const parent=node?node.id:null;if(doc.parent!==parent)throw new Error("CanopyX: page parent does not match the requested node.");return doc}
27
27
  function isCellObject(cell){return cell!==null&&typeof cell==="object"}
28
28
  function cellValue(cell){return isCellObject(cell)?(cell.value===undefined?null:cell.value):(cell===undefined?null:cell)}
29
- const NO_TONE={cls:"",host:null};const tones=new Map();function toneOf(name){let tone=typeof name==="string"?tones.get(name):NO_TONE;if(!tone){if(!/^[a-z][a-z0-9-]{0,31}$/.test(name) || name.endsWith("-bg")) {
29
+ const NO_TONE={cls:"",host:null};const tones=new Map();function toneVariable(name,background=false,fallback){const role={success:"good",warning:"warn",danger:"bad"}[name]||name;const key="--hfx-color-status-"+role +(background?"-bg":"-fg");return "var("+key +(STATUS_FALLBACKS[key]||fallback?"," +(STATUS_FALLBACKS[key]||fallback):"")+ ")"}
30
+ function toneOf(name){let tone=typeof name==="string"?tones.get(name):NO_TONE;if(!tone){if(!/^[a-z][a-z0-9-]{0,31}$/.test(name) || name.endsWith("-bg")) {
30
31
  return NO_TONE}
31
32
  const host=!/^(neutral|info|success|warning|danger|muted)$/.test(name);
32
33
  tone={cls:" cx-tone-"+name +(host?" cx-toned":""),host:host?name:null};if(tones.size<256)tones.set(name,tone)}
33
34
  return tone}
34
35
  function applyTone(element,base,tone){element.className=base+tone.cls;toneColors(element,tone)}
35
36
  function toneColors(element,tone){if((element._tone||null)===tone.host){return}
36
- element._tone=tone.host;if(tone.host){element.style.setProperty("--cx-t","var(--cx-tone-"+tone.host+")");element.style.setProperty("--cx-t-bg","var(--cx-tone-"+tone.host+"-bg)")}else{element.style.removeProperty("--cx-t");element.style.removeProperty("--cx-t-bg")}}
37
+ element._tone=tone.host;if(tone.host){element.style.setProperty("--cx-t",toneVariable(tone.host));element.style.setProperty("--cx-t-bg",toneVariable(tone.host,true))}else{element.style.removeProperty("--cx-t");element.style.removeProperty("--cx-t-bg")}}
37
38
  function pad2(value){return value<10?"0"+value:String(value)}
38
39
  const dateTexts=new Map();function dateText(value){let texts=dateTexts.get(value);if(texts===undefined){const time=Date.parse(value);const d=new Date(time);texts=isNaN(time)?null:[String(d.getUTCFullYear()).padStart(4,"0")+ "-"+pad2(d.getUTCMonth()+ 1)+ "-"+pad2(d.getUTCDate())+ " "+pad2(d.getUTCHours())+ ":"+pad2(d.getUTCMinutes()),String(d.getFullYear()).padStart(4,"0")+ "-"+pad2(d.getMonth()+ 1)+ "-"+pad2(d.getDate())+ " "+pad2(d.getHours())+ ":"+pad2(d.getMinutes())];if(dateTexts.size>=DATE_CACHE)dateTexts.clear();dateTexts.set(value,texts)}
39
40
  return texts}
@@ -46,9 +47,10 @@ if(typeof value==="boolean"){return value?fmt.labels.yes:fmt.labels.no}
46
47
  if(typeof value==="number"&&kind==="number"){return numberText(value,fmt.lang,format)}
47
48
  if(typeof value==="string"&&kind==="datetime"){return formatDate(value,fmt)}
48
49
  return String(value)}
49
- function cellText(cell,column,fmt){if(isCellObject(cell)&&typeof cell.text==="string"){return cell.text}
50
+ 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}
50
51
  return formatValue(cellValue(cell),column.kind,fmt,column.format)}
51
- 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}
52
+ 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}}
53
+ 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}
52
54
  if(value===null||value===""){return{rank:2,value:0}}
53
55
  if(typeof value==="boolean"){return{rank:0,value:value?1:0}}
54
56
  if(typeof value==="number"){return{rank:0,value}}
@@ -56,7 +58,20 @@ if(column.kind==="datetime"){const time=Date.parse(value);if(!isNaN(time)){retur
56
58
  return{rank:1,value:String(value)}}
57
59
  function compareKeys(a,b,direction){if(a.rank!==b.rank){return a.rank-b.rank}
58
60
  if(a.rank===2){return 0}
59
- 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}
61
+ const order=a.category!==undefined?a.category-b.category||
62
+ (a.type<b.type?-1:a.type>b.type?1:a.value<b.value?-1:a.value>b.value?1:0):
63
+ a.rank===0?(a.value<b.value?-1:a.value>b.value?1:0):collator.compare(a.value,b.value);return order*direction}
64
+ function columnNumericTone(column,raw){return typeof raw==="number"&&Number.isFinite(raw)?column.numericTones?.find(rule=>
65
+ rule.operator==="atMost"?raw<=rule.value:rule.operator==="atLeast"?raw>=rule.value:
66
+ rule.operator==="below"?raw<rule.value:raw>rule.value):undefined}
67
+ 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)}
68
+ 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");
69
+ 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||
70
+ Object.entries(map).some(([key,value])=>key.length>4096||(name==="valueTones"?!tone(value):typeof value!=="string"||value.length>4096)))fail()}
71
+ if(column.valueOrder!==undefined&&(column.kind!=="text"||!Array.isArray(column.valueOrder)||column.valueOrder.length>512||
72
+ 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||
73
+ column.numericTones.some(rule=>!rule||!["atMost","atLeast","below","above"].includes(rule.operator)||!Number.isFinite(rule.value)||
74
+ !tone(rule.tone)||typeof rule.label!=="string"||!rule.label.trim()||rule.label.length>4096)))fail()}
60
75
  function fill(template,values){return template.replace(/\{(\w+)\}/g, (match, name) => (values && Object.hasOwn(values, name) ? String(values[name]) : match));
61
76
  }
62
77
  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];
@@ -76,6 +91,12 @@ function trusted(kind,value){if(trustPolicy===undefined){try{trustPolicy=global.
76
91
  catch(_){trustPolicy=null}}
77
92
  return trustPolicy?trustPolicy["create"+kind](value):value}
78
93
  function hostHtml(element,html,sanitize,kind){const text=String(html??""),value=sanitize?sanitize(text,{kind}):text;if(value?.nodeType)element.replaceChildren(value);else if(typeof value==="string")element.innerHTML=trusted("HTML",value);else if(global.trustedTypes?.isHTML?.(value))element.innerHTML=value;else throw new Error("CanopyX: invalid sanitizeHtml result.")}
94
+ const STATUS_FALLBACKS={"--hfx-color-status-bad-bg":"light-dark(#f9e4e4,#3c272a)","--hfx-color-status-bad-fg":"light-dark(#b8292a,#f47171)","--hfx-color-status-good-bg":"light-dark(#e2f0e9,#1f362f)","--hfx-color-status-good-fg":"light-dark(#177345,#4cc78a)","--hfx-color-status-info-bg":"light-dark(#e4ecfa,#262f41)","--hfx-color-status-info-fg":"light-dark(#2b5fc0,#74a2f7)","--hfx-color-status-neutral-bg":"light-dark(#eeeff0,#2a2c31)","--hfx-color-status-neutral-fg":"light-dark(#5b6069,#a0a5ae)","--hfx-color-status-warn-bg":"light-dark(#f8efde,#3b3322)","--hfx-color-status-warn-fg":"light-dark(#8c5c05,#eeb640)"};const MODE_ATTRIBUTES=["data-theme","data-cx-theme","data-hfx-mode","data-bs-theme","data-hfx-theme","data-hfx-tokens"];const THEME_ATTRIBUTES=[...MODE_ATTRIBUTES,"data-hfx-style","data-hfx-density","data-cx-fallback-mode","style","class"];function watchTheme(host,signal){const attributes=THEME_ATTRIBUTES;const previous=host.getAttribute("data-cx-fallback-mode");const refresh=()=>{const parent=host.parentElement&&getComputedStyle(host.parentElement);const inherited=parent?.colorScheme;let mode=null;if(!parent?.getPropertyValue("--hfx-color-surface").trim()){outer:for(let owner=host;owner;owner=owner.parentElement)for(const attribute of MODE_ATTRIBUTES){const value=owner.getAttribute(attribute);if(value==="light"||value==="dark"){mode=value;break outer}}}
95
+ if(parent?.getPropertyValue("--hfx-color-surface").trim()||!mode&&inherited&&inherited!=="normal"){if(host.hasAttribute("data-cx-fallback-mode"))host.removeAttribute("data-cx-fallback-mode")}else if(host.getAttribute("data-cx-fallback-mode")!==(mode||"auto"))host.setAttribute("data-cx-fallback-mode",mode||"auto")};const observer=new MutationObserver(refresh);for(let owner=host;owner;owner=owner.parentElement)observer.observe(owner,{attributes:true,attributeFilter:attributes});refresh();const dispose=()=>{observer.disconnect();if(previous===null)host.removeAttribute("data-cx-fallback-mode");else host.setAttribute("data-cx-fallback-mode",previous)};signal?.addEventListener("abort",dispose,{once:true});return dispose}
96
+ function overlayTheme(host,element,inherit=false){for(const name of["data-hfx-style","data-hfx-mode","data-hfx-density"]){const owner=host.closest("["+name+"]");if(owner&&!inherit)element.setAttribute(name,owner.getAttribute(name));else element.removeAttribute(name)}
97
+ const theme=getComputedStyle(host),parent=inherit&&host.parentElement&&getComputedStyle(host.parentElement);element.style.colorScheme=theme.colorScheme;const copied=[];for(const name of theme)if((name.startsWith("--cx-")||name.startsWith("--hfx-"))&&(!parent||theme.getPropertyValue(name)!==parent.getPropertyValue(name))){element.style.setProperty(name,theme.getPropertyValue(name));copied.push(name)}
98
+ return copied}
99
+ function watchOverlayTheme(host,element,signal){if(signal?.aborted)return()=>{};let copied=[];const refresh=()=>{for(const name of copied)element.style.removeProperty(name);copied=overlayTheme(host,element,element.parentElement===host.parentElement)};const observer=new MutationObserver(refresh);for(let owner=host;owner;owner=owner.parentElement)observer.observe(owner,{attributes:true,attributeFilter:THEME_ATTRIBUTES});const media=["(prefers-color-scheme:dark)","(prefers-contrast:more)","(forced-colors:active)"].map(query=>matchMedia(query));for(const query of media)query.addEventListener("change",refresh);const dispose=()=>{observer.disconnect();for(const query of media)query.removeEventListener("change",refresh);signal?.removeEventListener("abort",dispose)};signal?.addEventListener("abort",dispose,{once:true});dispose.refresh=refresh;refresh();return dispose}
79
100
  DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{recordBack:"Back",recordBackTo:"Back to {record}",recordTrail:"Record trail",recordShowing:"Showing {record}",recordTabs:"Record views",recordSections:"Jump to a section",recordOtherFields:"Other fields",recordShowEmpty:"Show empty fields ({count})",recordHideEmpty:"Hide empty fields",recordActions:"Record actions",recordCopyValues:"Copy values",recordCopyJson:"Copy as JSON",recordCopyLink:"Copy link",recordCopied:"Copied to the clipboard",recordPrint:"Print record",recordExportCsv:"Export CSV",recordExportJson:"Export JSON",recordOpenAll:"Open all in grid",recordLoadMore:"Load more",recordCount:"{shown} of {total}",recordItems:"{count} items",recordMore:"+{count}",recordShowAll:"Show all {count}",recordRetry:"Retry",recordLoadFailed:"Could not load the record details: {error}",recordUnavailable:"Record {id} is not available here.",recordField:"Field",recordValue:"Value",recordSection:"Section",recordBefore:"Before",recordAfter:"After",recordAdded:"Added",recordRemoved:"Removed",recordChanged:"{count} changed fields"}));function boundedPattern(source,exact=true,whole=false){const bad=()=>{throw new Error("CanopyX: pattern requires literals, character classes and at most one variable repetition anchored at the start; groups, alternatives and backreferences are unsupported.")};if(typeof source!=="string"||source.length>256)bad();let width=0,variable=0;for(let i=0;i<source.length;){const unit=source[i++];if(unit==="^"&&i===1||unit==="$"&&i===source.length)continue;if(unit==="\\"){const escape=source[i++];if(!escape||!/^[dDsSwWbBnrtfv\\.^$*+?{}\[\]()|/]$/.test(escape)) bad();
80
101
  }else if(unit==="["){let closed=false;while(i<source.length){const c=source[i++];if(c==="\\"){const escape=source[i++];if(!escape||!/^[dDsSwWbnrtfv\\.^$*+?{}\[\]()|/-]$/.test(escape)) bad(); }
81
102
  else if(c==="]"){closed=true;break}}
@@ -119,7 +140,8 @@ if(column.kind==="datetime"){const date=typeof value==="string"&&/^\d{4}-\d\d-\d
119
140
  if(!Number.isFinite(date))
120
141
  throw new Error("CanopyX: date grid cells need ISO dates with an explicit time zone.");return date}
121
142
  if(typeof value!=="string"&&typeof value!=="boolean")throw new Error("CanopyX: text grid cells need strings or booleans.");return value}
122
- 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}
143
+ function gridExactTokens(column){return column.kind==="text"&&(column.valueOrder?.length||Object.keys(column.valueLabels||{}).length)}
144
+ 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}
123
145
  return false}
124
146
  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))
125
147
  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,9 +213,9 @@ throw new Error("CanopyX: unknown source kind '"+kind+"'.")}
191
213
  async function remoteJson(url,type,timeoutMs,lifetime,signal){const controller=new AbortController();const signals=Array.from(new Set([lifetime,signal].filter(Boolean)));const abort=()=>controller.abort();signals.forEach((item)=>{if(item.aborted)abort();else item.addEventListener("abort",abort,{once:true})});let timedOut=false;const timer=setTimeout(()=>{timedOut=true;abort()},timeoutMs);try{const response=await fetch(url,{headers:{Accept:"application/json"},signal:controller.signal});if(!response.ok){if(response.body)await response.body.cancel().catch(()=>{});throw new Error(response.status+" "+response.statusText)}
192
214
  return checkDocument(await response.json(),type)}catch(error){if(timedOut)throw new Error("CanopyX: remote request timed out after "+timeoutMs+" milliseconds.");throw error}finally{abort();clearTimeout(timer);signals.forEach((item)=>item.removeEventListener("abort",abort))}}
193
215
  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.")}
194
- 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"))
216
+ 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||40;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"))
195
217
  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.")}
196
- 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||[]}
218
+ 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||[]}
197
219
  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()}
198
220
  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()}}
199
221
  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
@@ -258,10 +280,9 @@ value.sort===undefined||typeof value!=="object")throw new Error("CanopyX: query
258
280
  const named=new Set(value.filters);if(named.size!==value.filters.length||value.filters.some(id=>!(grid.view.filters||[]).some(f=>f.id===id)))
259
281
  throw new Error("CanopyX: query filters must be unique declared IDs.");const filters=Object.freeze((grid.view.filters||[]).filter(f=>named.has(f.id)).map(f=>f.id));return Object.freeze({version:1,sort,filters})}
260
282
  function snapshotRevision(value,expected){requireIdentifier(value&&value.revision,"dataset revision");if(expected!=null&&value.revision!==expected)throw new Error("CanopyX: dataset revision changed; reload the roots before continuing.");return value.revision}
261
- 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")}
262
- 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")}
283
+ 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");watchTheme(host,this.lifetime.signal);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")}
263
284
  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++}
264
- 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)}
285
+ 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)}
265
286
  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}}
266
287
  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}}
267
288
  return measured}});function columnWidth(column,width){return Math.min(column.maxW,Math.max(column.minW,width))}
@@ -311,13 +332,13 @@ this.paintSlot(slot,node,this.cols[i],this.columnIndex[i],w)}},paintRowState(row
311
332
  const expander=this.expandable(w)?"cx-exp":"cx-exp cx-leaf";if(slot.expCls!==expander){slot.exp.className=expander;slot.expCls=expander}
312
333
  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()}
313
334
  slot.iconEl=key?this.iconTemplates.get(key).cloneNode(true):null;if(slot.iconEl){slot.cell.insertBefore(slot.iconEl,slot.content)}
314
- 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)?
335
+ 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)?
315
336
  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}
316
337
  const hosted=column.render?this.paintHostSlot(slot,node,column,index,w):null;if(hosted==="host"){return}
317
338
  const decorated=hosted==="decorated";const text=cellText(value,column,this.fmt);if(slot.text.data!==text){slot.text.data=text}
318
- 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}
339
+ 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}
319
340
  slot.cls=cls}
320
- 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")}
341
+ 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")}
321
342
  slot.title=title}
322
343
  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)}
323
344
  const tone=toneOf(badge.tone||"neutral");if(span._cls!==tone.cls){applyTone(span,"cx-badge",tone);span._cls=tone.cls}
@@ -506,7 +527,7 @@ if(active>=0){list.children[active].setAttribute("aria-selected","false")}
506
527
  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=""}
507
528
  close()}else{return}
508
529
  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)}}}
509
- 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);
530
+ const PART_URL=typeof document!=="undefined"&&document.currentScript?.src;const PARTS={"tree-tools":["ee95c5cc39223ef4","canopyx-tree-tools.ab224d048d87d4a8.js","canopyx-tree-tools.3a4ac9c0bfe85039.css"],"presenters":["4337e3756b443220","canopyx-presenters.c8c9d0651df602b1.js"],"filter-editor":["e0db9c3f94866fa2","canopyx-filter-editor.bd27d6fec3d8b005.js","canopyx-filter-editor.0aa102aa92982a0f.css"],"export":["9203882f58fa0155","canopyx-export.cedfec6462c161b4.js"],"history":["7d9901d2fe04df72","canopyx-history.9432e724bf14c9ed.js"],"pager":["3dcab112113081dd","canopyx-pager.15bb475e4365fe79.js","canopyx-pager.e39f321db5bdfde4.css"],"enhance":["a101e32b0f8a1644","canopyx-enhance.dd25035ab5f23d01.js"],"data":["d74a01c46f1c40cc","canopyx-data.afe3b097f19b5797.js"],"forms":["0d77c25f4fa14425","canopyx-forms.3b18e30a2aeb56dd.js","canopyx-forms.e3a0e1f016287057.css"],"flow":["e7dea789e4893860","canopyx-flow.bce98a6e89aa358e.js","canopyx-flow.68af38159226dd08.css"],"flow-host":["6f335df747cc5f05","canopyx-flow-host.ea0be90307b19d0f.js","canopyx-flow-host.87b00b9ed5899f1f.css"],"flow-checks":["3ca22040c60d5689","canopyx-flow-checks.7856290d3c486f84.js","canopyx-flow-checks.d3b182bf1d633e48.css"],"flow-options":["60450342239ded26","canopyx-flow-options.d31458a54aa4b1e7.js"],"flow-pick":["e5f79a9e81e93898","canopyx-flow-pick.e17b209908086225.js","canopyx-flow-pick.7ec005490120da23.css"],"flow-records":["d02b7dc1c7f75805","canopyx-flow-records.5efc3b14cf70b524.js","canopyx-flow-records.cf62ae7260a46ec4.css"],"flow-drafts":["40dc8e50169fa271","canopyx-flow-drafts.67fb3ab7fbc22606.js","canopyx-flow-drafts.f8535eb8992ea36a.css"],"flow-preview":["3d8ffe456323db95","canopyx-flow-preview.4731603add2f8e84.js","canopyx-flow-preview.f1c740bc97130a7d.css"],"flow-command":["a6c75cf736c93444","canopyx-flow-command.f3608c38cc18f333.js","canopyx-flow-command.279d6ad310e39e97.css"],"flow-tasks":["8d9ea504e81e8fcd","canopyx-flow-tasks.eeb43b791491b43b.js","canopyx-flow-tasks.5c0dc5743e02c670.css"],"flow-dialog":["a9b5bce11baa2499","canopyx-flow-dialog.271f746b459ec0da.js","canopyx-flow-dialog.7f5a8ca5841006af.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":["da5c61ff2cb9ebda","canopyx-matrix.ed85d343a2f623b2.js","canopyx-matrix.195d1a1dda7a6f14.css"],"changes":["2810fb06a78b85e3","canopyx-changes.b4d09ab480688573.js","canopyx-changes.4bc51f4c6ae04082.css"],"editing":["579a74b205923fd5","canopyx-editing.ecebf88153edf03a.js","canopyx-editing.e0a3e646f4093e3b.css"],"column-groups":["cd6d93e033719439","canopyx-column-groups.922e21b9bdf57efa.js","canopyx-column-groups.6a6c9704c4ee7884.css"],"cell-range":["91e39c68baaf1d09","canopyx-cell-range.a12cda7cbddf4aea.js","canopyx-cell-range.ce87ff1c2023feae.css"],"links":["f1ab7e32b501ce37","canopyx-links.d96addeefb3eccf5.js"],"search":["521eebd6e1bbbd35","canopyx-search.14c69f4551c69f23.js"],"formatting":["d3795e4b933d83a8","canopyx-formatting.ec13b95ea1f2b023.js","canopyx-formatting.922dc9fc7e6d35a7.css"],"format-editor":["b8c229ddfc1f218b","canopyx-format-editor.4a220f27a369d34e.js","canopyx-format-editor.dbdf4a154e7e5f48.css"],"link":["e7268bbe59e2dfa8","canopyx-link.e883be9525ead7b7.js","canopyx-link.b872151e9cbbd0ce.css"],"detail-rows":["e4150bb67f40d597","canopyx-detail-rows.e7f93158e19cbb28.js","canopyx-detail-rows.cabc50f51ed091ad.css"],"grouping":["eedafc8438ac1b2b","canopyx-grouping.e7767e781127573d.js","canopyx-grouping.98fa290cd1652f71.css"],"highlight":["459b28e174406d32","canopyx-highlight.10ef4bb28c5a8f5b.js","canopyx-highlight.ab1040f93cbb5dbb.css"],"layouts":["606fcf6dcd00d420","canopyx-layouts.606c8fe836149ffe.js","canopyx-layouts.56a636b0f1a03185.css"],"facets":["2ffa91f40c9b9b21","canopyx-facets.2ad845e5213e7f5b.js","canopyx-facets.8d4c02348420a425.css"],"live":["42ad4b814f47bd00","canopyx-live.3cc50651bc9d2bc9.js","canopyx-live.39fe32cd642f60d2.css"],"record-panel":["94adeb844689e329","canopyx-record-panel.d0d71d38743e3476.js","canopyx-record-panel.66edd824ab6111c1.css"],"calendar":["463aadb3a2169631","canopyx-calendar.3f539daa1b0a1b6f.js","canopyx-calendar.2d299b0318447276.css"],"calendar-recurrence":["64bcc24d785bd1af","canopyx-calendar-recurrence.4b7f430c2a64de23.js"],"calendar-edit":["29a711a1cfd4be9a","canopyx-calendar-edit.ef7728c17ca4851b.js"],"calendar-ics":["ac8b2950fccbfb0f","canopyx-calendar-ics.4a18c1c4a1520418.js"],"timeline":["22c9e15c108aeaa1","canopyx-timeline.2b5fe21a0f24aa08.js","canopyx-timeline.e3c962ae517931d2.css"],"grid-options":["e74170bbb841519c","canopyx-grid-options.c5fa91fc19205d5a.js","canopyx-grid-options.9c393c5122332461.css"]},PART_CODE=new Map(),partName=name=>typeof name==="string"&&/^[a-z][a-z\d-]{0,31}$/.test(name);
510
531
  function registerPart(name,part){if(!partName(name)||!part||typeof part.version!=="string"||typeof part.install!=="function"||
511
532
  part.requires!==undefined&&!(Array.isArray(part.requires)&&part.requires.every(partName)))throw new Error("CanopyX: invalid part.");PART_CODE.set(name,part)}
512
533
  function definePart(View,name,label,context){const parts=View.prototype.parts||={};return parts[name]={name,label,context,parts}}
@@ -516,7 +537,7 @@ const load=(element,attribute,file,kind)=>new Promise((resolve,reject)=>{const u
516
537
  .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")
517
538
  .finally(()=>script.remove()).catch(error=>{part.scriptReady=null;throw error}));await Promise.all([style,code])}}
518
539
  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})}
519
- 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)}
540
+ 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,overlayTheme}));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)}
520
541
  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")
521
542
  throw new Error("CanopyX: invalid state column.");seen.add(c.id);return{id:c.id,width:c.width,hidden:c.hidden}}
522
543
  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})})}
@@ -530,9 +551,9 @@ catch(error){/* Nodes removed since the snapshot are skipped. */ }
530
551
  }},applyStatePosition(state,current){if(!state.version)return;const valid=path=>{const w=path&&this.keyMap.get(path[path.length-1]);return w&&JSON.stringify(this.pathOf(w))===JSON.stringify(path)?w:null};this.setSelection(state.selection.map(valid).filter(Boolean).map(w=>w.key));if(this.destroyed||current.signal.aborted)return;const focused=valid(state.focus);if(focused&&this.indexOf(focused)>=0)this.setFocus(focused,false);const anchor=state.anchor&&valid(state.anchor.path);if(anchor)this.restoreScrollAnchor({id:anchor.key,offset:state.anchor.offset})}});const PLUGINS=new Map();function plugin(value){const item=Object.freeze({...value}),fn=handler=>typeof handler==="function";const entry=menu=>action=>action&&typeof action.label==="string"&&
531
552
  (fn(action.run)&&action.render===undefined||menu&&fn(action.render)&&action.run===undefined);if(!value||!partName(item.name)||Object.hasOwn(PARTS,item.name)||[item.init,item.destroy].some(hook=>hook!==undefined&&!fn(hook))||
532
553
  ["requires","views","toolbarItems","menuItems","exportFormats","recordActions"].some(key=>item[key]!==undefined&&!Array.isArray(item[key]))||
533
- ["cellRenderers","columnTypes","editors","events","aggregates","detailRenderers","drawerSections"].some(key=>item[key]!==undefined&&Object(item[key])!==item[key])||
554
+ ["cellRenderers","columnTypes","editors","events","aggregates","detailRenderers","drawerSections","filterOperators","sortComparators"].some(key=>item[key]!==undefined&&Object(item[key])!==item[key])||
534
555
  !(item.requires||[]).every(partName)||!(item.views||[]).every(kind=>kind==="tree"||kind==="grid")||
535
- ![...Object.values(item.cellRenderers||{}),...Object.values(item.events||{}),...Object.values(item.detailRenderers||{}),...Object.values(item.drawerSections||{})].every(fn)||
556
+ ![...Object.values(item.cellRenderers||{}),...Object.values(item.events||{}),...Object.values(item.detailRenderers||{}),...Object.values(item.drawerSections||{}),...Object.values(item.filterOperators||{}),...Object.values(item.sortComparators||{})].every(fn)||
536
557
  !(item.toolbarItems||[]).every(entry())||!(item.recordActions||[]).every(entry())||!(item.menuItems||[]).every(entry(true)))
537
558
  throw new Error("CanopyX: invalid plugin '"+item.name+"'.");item.exportFormats?.forEach(exportFormat);return item}
538
559
  function use(value){const item=plugin(value);if(PLUGINS.has(item.name))throw new Error("CanopyX: plugin '"+item.name+"' is already registered.");PLUGINS.set(item.name,item);const formats=item.exportFormats?.map(registerExportFormat)||[];return()=>{if(PLUGINS.get(item.name)===item){PLUGINS.delete(item.name);formats.forEach(dispose=>dispose())}}}
@@ -570,14 +591,27 @@ finally{navigation.dispose()}
570
591
  if(navigation.cancelled())return null;if(this.queryAware)snapshotRevision(doc,this.datasetRevision);checkDocument(doc,"counts");this.applyCounts(Object.assign({},doc,{items:doc.items.filter(item=>{const captured=mine.get(item.id);return captured&&this.keyMap.get(item.id)===captured.w&&captured.w.countRevision===captured.revision})}),true);return doc}});const LINKS=definePart(TreeGrid,"links","deep links",()=>({TreeGrid,navigationScope}));for(const name of["openDeepLink","writeDeepLink"])TreeGrid.prototype[name]=function(...args){return this.view.deepLink?loadPart(LINKS).then(()=>this[name](...args),error=>this.emit("error",{error})):Promise.resolve()};TreeGrid.prototype.readLocation=function(){if(this.destroyed)return Promise.resolve();if(this.initializing){if(this.linkOpening&&this.currentLink()!==this.link){this.linkOpening.abort();this.link=null;// Deferred reopening must not reuse the canceled link if the address changes back.
571
592
  }
572
593
  this.linkChanged=this.dataLifetime.signal;return this.ready.then(()=>undefined,()=>undefined)}
573
- return this.openDeepLink()};DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{linkFilteredBy:"Filtered by {source}: {values}",linkRemoveFilter:"Remove the filter from {source}: {values}",linkFiltered:"Filtered by {source}: {count} rows",linkHighlighted:"{count} rows highlighted from {source}",linkHighlightedRows:"{count} rows highlighted",linkCleared:"Linked filters removed"}));const LINK_IMPL={TreeGrid,queryOwn:Symbol("own conditions")},LINK_PART=definePart(TreeGrid,"link","linked views",()=>({LINK_IMPL,h,setText,filterChipContent,fill,numberFormat,cellValue,setAttr,cellMatches}));const LINK_METHODS=["setExternalFilter","clearExternalFilters","setHighlight","clearHighlight","startLinkEvents"];function linkMethods(View){for(const name of LINK_METHODS)(View.prototype[name]=function(...args){return this.destroyed?Promise.resolve(/Highlight/.test(name) ? 0 : name === "startLinkEvents" ? undefined : false) : loadPart(LINK_PART).then(() => this[name](...args));
594
+ return this.openDeepLink()};function sharedDensity(host){const value=host.closest("[data-hfx-density]")?.getAttribute("data-hfx-density");return value==="compact"||value==="comfortable"?value:null}
595
+ function watchSharedDensity(view){let previous=sharedDensity(view.host);const metrics=()=>{if(previous)view.host.style.setProperty("--cx-compact",previous==="compact"?"1":"0");else view.host.style.removeProperty("--cx-compact")};metrics();const observer=new MutationObserver(()=>{const current=sharedDensity(view.host);if(current===previous||view.destroyed)return;previous=current;metrics();refreshSharedDensity(view)});for(let owner=view.host;owner;owner=owner.parentElement){observer.observe(owner,{attributes:true,attributeFilter:["data-hfx-density"]})}
596
+ view.lifetime.signal.addEventListener("abort",()=>observer.disconnect(),{once:true})}
597
+ function layoutAnchor(view){const rows=view.rowProjection||view,top=view.logicalTop(),count=rows.rowCount();if(!count)return null;const index=rows.rowAt(top),height=(view.autoRows?null:view.rowH)||1;const offset=Math.max(0,top-rows.rowTop(index));return{index,offset,share:Math.max(0,Math.min(1,offset / height)) };
598
+ }
599
+ function layoutRows(view,anchor){const rows=view.rowProjection||view;for(const row of[...view.rowCache.values(),...view.placeholders.values()])row.hpx=view.rowH;if(view.autoRows){for(const[index,height]of view.rowHeights)if(height<view.rowH)view.rowHeights.set(index,view.rowH);view.rowOffsets=null;view.measureNeeded=true;view.render()}
600
+ else{const bounds=view.rowBounds(),count=view.rowProjection?rows.rowCount():Math.max(0,bounds.last-bounds.first+1);view.total=count*view.rowH;view.syncScrollRange(anchor?rows.rowTop(anchor.index)+ anchor.share*view.rowH:0)}
601
+ if(anchor&&view.autoRows){const top=rows.rowTop(anchor.index),height=rows.rowTop(anchor.index+1)- top;view.setLogicalTop(top+Math.min(anchor.offset,Math.max(0,height-1)))}
602
+ view.render()}
603
+ function layoutApplyTree(view){const before=view.rowH,after=densityRowHeight(view,view.density);if(before!==after){const anchor=view.captureScrollAnchor();view.rowH=after;const status=row=>{if(row&&row.hpx===before)row.hpx=after};status(view.root._status);for(const row of view.keyMap.values()){if(!row.h?.detail&&row.hpx===before)row.hpx=after;status(row._status)}
604
+ for(const row of view.rows)if(row.status)status(row);view.retop();if(anchor)view.restoreScrollAnchor(anchor)}
605
+ view.fitKey=null;view.version++;if(view.fitReady)view.applyWidths();view.render()}
606
+ function refreshSharedDensity(view){if(!view.grid)return;if(view.kind==="grid"){view.fitKey=null;view.fitFont=null;if(view.layoutMode==="cards"&&VIEW_MODES.refreshCardDensity)VIEW_MODES.refreshCardDensity(view);else{const anchor=layoutAnchor(view);view.rowH=densityRowHeight(view,view.density);view.version++;layoutRows(view,anchor);view.applyWidths()}}else layoutApplyTree(view);view.host.style.setProperty("--cx-row-h",view.rowH+"px");view.fitHeight?.()}
607
+ DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{linkFilteredBy:"Filtered by {source}: {values}",linkRemoveFilter:"Remove the filter from {source}: {values}",linkFiltered:"Filtered by {source}: {count} rows",linkHighlighted:"{count} rows highlighted from {source}",linkHighlightedRows:"{count} rows highlighted",linkCleared:"Linked filters removed"}));const LINK_IMPL={TreeGrid,queryOwn:Symbol("own conditions")},LINK_PART=definePart(TreeGrid,"link","linked views",()=>({LINK_IMPL,h,setText,filterChipContent,fill,numberFormat,cellValue,setAttr,cellMatches}));const LINK_METHODS=["setExternalFilter","clearExternalFilters","setHighlight","clearHighlight","startLinkEvents"];function linkMethods(View){for(const name of LINK_METHODS)(View.prototype[name]=function(...args){return this.destroyed?Promise.resolve(/Highlight/.test(name) ? 0 : name === "startLinkEvents" ? undefined : false) : loadPart(LINK_PART).then(() => this[name](...args));
574
608
  }).linkStub=true;View.prototype.getExternalFilters=function(){return(this.linkCommitted||[]).map(item=>JSON.parse(JSON.stringify(item)))};View.prototype.getHighlight=function(){return Array.from(this.linkHighlight||[])};View.prototype.linkStart=function(){if(this.opts.linkEvents===true)return loadPart(LINK_PART).then(()=>this.linkWatch()).catch(error=>{this.emit("error",{error});throw error})}}
575
609
  linkMethods(TreeGrid);function linkGridPart(View){(Object.hasOwn(View.prototype,"parts")?View.prototype.parts:View.prototype.parts={}).link=LINK_PART}
576
610
  function linkReady(grid,ready){return Promise.all([ready,grid.linkStart()]).then(([result])=>result)}
577
611
  function linkApi(grid){const api={};for(const name of LINK_METHODS.concat("getExternalFilters","getHighlight"))api[name]=(...args)=>grid[name](...args);return api}
578
- 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)}
612
+ 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)}
579
613
  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}))}
580
- 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");
614
+ 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:-8,default:0,comfortable:0},grid:{compact:-8,default:0,comfortable:0}};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");
581
615
  if(!options||typeof options!=="object"||Array.isArray(options)||Object.keys(options).some(key=>!HIGHLIGHT_KEYS.includes(key))||
582
616
  HIGHLIGHT_KEYS.slice(0,5).some(key=>options[key]!==undefined&&typeof options[key]!=="boolean")||
583
617
  options.minLength!==undefined&&(!Number.isInteger(options.minLength)||options.minLength<1||options.minLength>32)||
@@ -593,12 +627,12 @@ function readModeState(view,state){const result={};if(state.layout!==undefined){
593
627
  throw new Error("CanopyX: invalid saved layout.");if(options)result.layout={mode:options.modes.includes(layout.mode)?layout.mode:options.mode,density:layout.density}}
594
628
  if(state.highlight!==undefined){if(typeof state.highlight!=="boolean")throw new Error("CanopyX: invalid saved highlight choice.");if(view.highlightOptions)result.highlight=state.highlight}
595
629
  return result}
596
- function densityRowHeight(view,density){const steps=DENSITY_STEP[view.kind];return Math.max(20,Math.min(64,view.baseRowH+steps[density]- steps[view.declaredDensity]))}
597
- const VIEW_MODE_METHODS={prepareViewModes(){const view=this.view,columns=this.columns||view.columns;this.highlightOptions=readSearchHighlight(view.searchHighlight,columns);this.declaredDensity=this.kind==="grid"?view.density||"default":"default";this.layoutOptions=readLayout(view.layout,this.kind,this.declaredDensity);this.baseRowH=this.rowH;this.adoptModes({layout:this.layoutOptions||{mode:"fit",density:this.declaredDensity},highlight:!!this.highlightOptions?.enabled})},adoptModes(choice){if(choice.layout){this.layoutMode=choice.layout.mode;this.density=choice.layout.density}
630
+ function densityRowHeight(view,density){const shared=sharedDensity(view.host);if(shared)return shared==="compact"?32:40;const steps=DENSITY_STEP[view.kind];return Math.max(20,Math.min(64,view.baseRowH+steps[density]- steps[view.declaredDensity]))}
631
+ const VIEW_MODE_METHODS={prepareViewModes(){const view=this.view,columns=this.columns||view.columns;this.highlightOptions=readSearchHighlight(view.searchHighlight,columns);this.declaredDensity=this.kind==="grid"?view.density||"default":"default";this.layoutOptions=readLayout(view.layout,this.kind,this.declaredDensity);this.baseRowH=this.rowH;this.adoptModes({layout:this.layoutOptions||{mode:"fit",density:this.declaredDensity},highlight:!!this.highlightOptions?.enabled});watchSharedDensity(this)},adoptModes(choice){if(choice.layout){this.layoutMode=choice.layout.mode;this.density=choice.layout.density}
598
632
  if(choice.highlight!==undefined)this.highlightOn=choice.highlight;this.rowH=densityRowHeight(this,this.density);if(this.layoutMode==="fit")this.host.removeAttribute("data-cx-layout");else this.host.setAttribute("data-cx-layout",this.layoutMode)},modeState(state){if(this.layoutOptions)state.layout={mode:this.layoutMode,density:this.density};if(this.highlightOptions)state.highlight=!!this.highlightOn;return state},applyModeState(state){if(state.layout&&(state.layout.mode!==this.layoutMode||state.layout.density!==this.density))
599
633
  this.setLayout(state.layout).catch(error=>this.emit("error",{error}));if(state.highlight!==undefined&&state.highlight!==!!this.highlightOn)
600
634
  this.setSearchHighlight(state.highlight).catch(error=>this.emit("error",{error}))},startViewModes(){const parts=[this.highlightOptions&&"highlight",this.layoutOptions&&"layouts"].filter(Boolean);return Promise.all(parts.map(name=>this.requirePart(name).then(()=>this.destroyed||VIEW_MODES[name+"Start"](this))
601
- .catch(error=>this.emit("error",{error}))))},getLayout(){return Object.freeze({mode:this.layoutMode,density:this.density,modes:this.layoutOptions?this.layoutOptions.modes:Object.freeze(["fit"])})},setLayout(change){if(!this.layoutOptions)return Promise.reject(new Error("CanopyX: this view declares no layout modes."));return this.requirePart("layouts").then(()=>VIEW_MODES.setLayout(this,change))},getMatches(){return VIEW_MODES.matches?VIEW_MODES.matches(this):Object.freeze({enabled:!!this.highlightOn,total:0,current:0,complete:true})},setSearchHighlight(enabled){if(typeof enabled!=="boolean")return Promise.reject(new Error("CanopyX: the highlight switch is a boolean."));if(!this.highlightOptions)return Promise.reject(new Error("CanopyX: this view declares no search highlighting."));return this.requirePart("highlight").then(()=>VIEW_MODES.setHighlight(this,enabled))},nextMatch(options){return this.stepMatch(1,options)},previousMatch(options){return this.stepMatch(-1,options)},stepMatch(direction,options){if(!this.highlightOptions)return Promise.reject(new Error("CanopyX: this view declares no search highlighting."));return this.requirePart("highlight").then(()=>VIEW_MODES.step(this,direction,options?.focus!==false))}};Object.assign(TreeGrid.prototype,VIEW_MODE_METHODS);const viewModeContext=()=>({VIEW_MODES,TreeGrid,h,setText,fill,numberFormat,foldText,cellText,cellValue,isCellObject,setAttr,toneOf,watchFlyout,densityRowHeight,MAX_PROTOCOL_INTEGER,LAYOUT_DENSITIES,plural,svgIcon});definePart(TreeGrid,"highlight","search highlighting",viewModeContext);definePart(TreeGrid,"layouts","layout modes",viewModeContext);const MODES_TOOLBAR=TreeGrid.prototype.buildToolbar;TreeGrid.prototype.buildToolbar=function(){MODES_TOOLBAR.call(this);if(this.highlightOptions||this.layoutOptions)this.modesReady=Promise.resolve(this.toolsReady).then(()=>this.destroyed||this.startViewModes());this.lifetime.signal.addEventListener("abort",()=>this.host.removeAttribute("data-cx-layout"),{once:true})};Object.assign(TreeGrid.prototype,{destroy(){if(this.destroyed)return;this.destroyed=true;for(const row of[...this.rendered.values(),...this.pool])disposeRowHostCells(row);this.lifetime.abort();this.dataLifetime.abort();if(this.queryController)this.queryController.abort();if(this.restoreController)this.restoreController.abort();if(this.cancelResize)this.cancelResize();clearTimeout(this.saveTimer);clearTimeout(this.layoutTimer);if(this.cancelSearch)this.cancelSearch();if(this.disposeSearchFlyout)this.disposeSearchFlyout();cancelAnimationFrame(this.rafId);this.resizeObserver.disconnect();if(this.detailObserver)this.detailObserver.disconnect();this.grid.removeEventListener("scroll",this.onScroll);this.grid.removeEventListener("wheel",this.onScaledWheel);this.grid.removeEventListener("touchstart",this.onScaledTouchStart);this.grid.removeEventListener("touchmove",this.onScaledTouchMove);this.grid.removeEventListener("touchend",this.onScaledTouchEnd);this.grid.removeEventListener("touchcancel",this.onScaledTouchEnd);global.removeEventListener("beforeprint",this.onPrint);global.removeEventListener("hashchange",this.onHash);global.removeEventListener("popstate",this.onHash);if(this.linkOpening)this.linkOpening.abort();[this.toolbar,this.grid,this.live,this.outline].forEach(element=>element.remove());this.host.classList.remove("cx-pin-tree");this.host.removeAttribute("data-cx-ready");this.host.removeAttribute("data-canopyx-mounted");this.keyMap.clear();this.selected.clear();this.rendered.clear();this.pool.length=0;if(this.inactiveCache)this.inactiveCache.clear();if(this.inlineRetained)this.inlineRetained.clear();this.rows=[];this.tops=[0];this.total=0;this.root.children=null;this.root.inlineCache=null;this.root.inlineOrder=null;this.focused=null;this.anchor=null;this.source=null;this.touchScroll=null;this.opts={};for(const column of this.columns)column.render=null;this.filter=null;this.declaredFilter=null;this.pendingRestorationToggles=null;this.scrolledCell=null;this.focusHandoff=null;this.cancelResize=null;this.cancelSearch=null;this.disposeSearchFlyout=null;this.canvas.replaceChildren();this.outline.replaceChildren()}});const ROW_HELPERS={};const GRID_REPORTING={};for(const name of["buildHeader","visibleColumns","applyWidths","setColumnWidth","startResize","cell","newCell","paintSlot","paintBadges","cellTip","paintHostSlot","setSlotContent","setTimeZone","rowCells","heldCell","restoreCell","focusCell","revealInRow","revealInCell","settleCell"])
635
+ .catch(error=>this.emit("error",{error}))))},getLayout(){return Object.freeze({mode:this.layoutMode,density:this.density,modes:this.layoutOptions?this.layoutOptions.modes:Object.freeze(["fit"])})},setLayout(change){if(!this.layoutOptions)return Promise.reject(new Error("CanopyX: this view declares no layout modes."));return this.requirePart("layouts").then(()=>VIEW_MODES.setLayout(this,change))},getMatches(){return VIEW_MODES.matches?VIEW_MODES.matches(this):Object.freeze({enabled:!!this.highlightOn,total:0,current:0,complete:true})},setSearchHighlight(enabled){if(typeof enabled!=="boolean")return Promise.reject(new Error("CanopyX: the highlight switch is a boolean."));if(!this.highlightOptions)return Promise.reject(new Error("CanopyX: this view declares no search highlighting."));return this.requirePart("highlight").then(()=>VIEW_MODES.setHighlight(this,enabled))},nextMatch(options){return this.stepMatch(1,options)},previousMatch(options){return this.stepMatch(-1,options)},stepMatch(direction,options){if(!this.highlightOptions)return Promise.reject(new Error("CanopyX: this view declares no search highlighting."));return this.requirePart("highlight").then(()=>VIEW_MODES.step(this,direction,options?.focus!==false))}};Object.assign(TreeGrid.prototype,VIEW_MODE_METHODS);const viewModeContext=()=>({VIEW_MODES,TreeGrid,h,setText,fill,numberFormat,foldText,cellText,cellValue,isCellObject,setAttr,toneOf,toneVariable,watchFlyout,densityRowHeight,layoutAnchor,layoutRows,layoutApplyTree,MAX_PROTOCOL_INTEGER,LAYOUT_DENSITIES,plural,svgIcon});definePart(TreeGrid,"highlight","search highlighting",viewModeContext);definePart(TreeGrid,"layouts","layout modes",viewModeContext);const MODES_TOOLBAR=TreeGrid.prototype.buildToolbar;TreeGrid.prototype.buildToolbar=function(){MODES_TOOLBAR.call(this);if(this.highlightOptions||this.layoutOptions)this.modesReady=Promise.resolve(this.toolsReady).then(()=>this.destroyed||this.startViewModes());this.lifetime.signal.addEventListener("abort",()=>this.host.removeAttribute("data-cx-layout"),{once:true})};Object.assign(TreeGrid.prototype,{destroy(){if(this.destroyed)return;this.destroyed=true;for(const row of[...this.rendered.values(),...this.pool])disposeRowHostCells(row);this.lifetime.abort();this.dataLifetime.abort();if(this.queryController)this.queryController.abort();if(this.restoreController)this.restoreController.abort();if(this.cancelResize)this.cancelResize();clearTimeout(this.saveTimer);clearTimeout(this.layoutTimer);if(this.cancelSearch)this.cancelSearch();if(this.disposeSearchFlyout)this.disposeSearchFlyout();cancelAnimationFrame(this.rafId);this.resizeObserver.disconnect();if(this.detailObserver)this.detailObserver.disconnect();this.grid.removeEventListener("scroll",this.onScroll);this.grid.removeEventListener("wheel",this.onScaledWheel);this.grid.removeEventListener("touchstart",this.onScaledTouchStart);this.grid.removeEventListener("touchmove",this.onScaledTouchMove);this.grid.removeEventListener("touchend",this.onScaledTouchEnd);this.grid.removeEventListener("touchcancel",this.onScaledTouchEnd);global.removeEventListener("beforeprint",this.onPrint);global.removeEventListener("hashchange",this.onHash);global.removeEventListener("popstate",this.onHash);if(this.linkOpening)this.linkOpening.abort();[this.toolbar,this.grid,this.live,this.outline].forEach(element=>element.remove());this.host.classList.remove("cx-pin-tree");this.host.removeAttribute("data-cx-ready");this.host.removeAttribute("data-canopyx-mounted");this.keyMap.clear();this.selected.clear();this.rendered.clear();this.pool.length=0;if(this.inactiveCache)this.inactiveCache.clear();if(this.inlineRetained)this.inlineRetained.clear();this.rows=[];this.tops=[0];this.total=0;this.root.children=null;this.root.inlineCache=null;this.root.inlineOrder=null;this.focused=null;this.anchor=null;this.source=null;this.touchScroll=null;this.opts={};for(const column of this.columns)column.render=null;this.filter=null;this.declaredFilter=null;this.pendingRestorationToggles=null;this.scrolledCell=null;this.focusHandoff=null;this.cancelResize=null;this.cancelSearch=null;this.disposeSearchFlyout=null;this.canvas.replaceChildren();this.outline.replaceChildren()}});const ROW_HELPERS={};const GRID_REPORTING={};for(const name of["buildHeader","visibleColumns","applyWidths","setColumnWidth","startResize","cell","newCell","paintSlot","paintBadges","cellTip","paintHostSlot","setSlotContent","setTimeZone","rowCells","heldCell","restoreCell","focusCell","revealInRow","revealInCell","settleCell"])
602
636
  ROW_HELPERS[name]=TreeGrid.prototype[name];function gridMomentFromParts(year,month,day,hours,minutes,seconds,local){const parts=[year,month,day,hours,minutes,seconds];if(!parts.every(Number.isInteger))return null;const moment=new Date(0),zone=local?"":"UTC";moment["set"+zone+"FullYear"](year,month-1,day);moment["set"+zone+"Hours"](hours,minutes,seconds,0);const actual=["FullYear","Month","Date","Hours","Minutes","Seconds"].map(name=>moment["get"+zone+name]());actual[1]++;return parts.every((value,index)=>value===actual[index])?moment:null}
603
637
  function gridDateInputMoment(text,local){const match=/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{1,3}))?)?$/.exec(text);
604
638
  if(!match)return null;const moment=gridMomentFromParts(Number(match[1]),Number(match[2]),Number(match[3]),Number(match[4]),Number(match[5]),Number(match[6]||0),local);if(moment)moment.setTime(moment.getTime()+ Number((match[7]||"").padEnd(3,"0")));return moment}
@@ -607,8 +641,29 @@ return value}
607
641
  DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{gridSelectionCount:"{count} selected",gridClearSelection:"Clear selection",gridSelectionQueryUnknown:"All matching records selected; {excluded} excluded",gridFitContent:"Fit to content",gridUnpin:"Unpin",gridWhere:"Where",gridComplexFilter:"This column belongs to a mixed condition group. Edit it in Filters.",gridPinLeft:"Pin left",gridPinRight:"Pin right",gridResponsiveHidden:"Hidden at this width",gridFilterMatch:"Match",gridFilterAll:"All",gridFilterAny:"Any",gridDeleteFilterGroup:"Remove condition group",gridFacetSearch:"Search values",gridFacetChoose:"Choose a value",gridFacetCounts:"{count} matching rows; {shown} of {total} values.",gridTrue:"True",gridFalse:"False",gridHeaderFilter:"Filter {column}",gridClearColumnFilter:"Clear filter",gridSelectionAggregate:"Count: {count} · Sum: {sum} · Average: {average} · Minimum: {minimum} · Maximum: {maximum}",gridConditionValue:"Value",gridConditionUpperValue:"Upper value",gridDeleteCondition:"Remove condition",gridShowRowsWhere:"Show rows where",gridOfTheseAreTrue:"of these are true",gridOfThese:"of these",gridGroupCount:"{count} groups",gridMore:"More",gridDone:"Done",gridClearAll:"Clear all",gridRows:"rows",gridResultNoun:"{count} of {total} {noun}",gridSearchNoun:"Search {noun}",gridChart:"Chart",gridPrint:"Print",gridRowPicked:"Picked up {title}. Move to a calendar and press Enter to drop it.",gridColumnMenu:"Menu for {column}",gridSortAscending:"Sort ascending",gridSortDescending:"Sort descending",gridClearSort:"Clear sort",gridFilterColumn:"Filter…",gridHideColumn:"Hide column",gridGroupedBy:"Grouped by",gridRemoveGrouping:"Remove grouping",gridSelectAllValues:"Select all values",gridFilterValues:"Search values",gridAddCondition:"+ Condition",gridAddGroup:"+ Group",gridAnd:"and",gridOr:"or",gridEditAsText:"Edit as text",gridFilterText:"Filter expression",gridDeepFilters:"This saved filter has more than two nesting levels.",gridToday:"Today",gridYesterday:"Yesterday",gridLastSevenDays:"Last 7 days",gridLastThirtyDays:"Last 30 days",gridThisMonth:"This month",gridDateRange:"Range",gridEmpty:"No {noun}",gridEmptyReason:"There are no records to display.",gridNoMatches:"No matching {noun}",gridNoMatchesReason:"Search: {search}. Active filters: {count}.",gridRetry:"Retry",gridLoadFailed:"Could not load records",gridAll:"All",gridPageOf:"{page} of {pages}",gridStatusCount:"{count} {noun} · {selected} selected",gridDetailsSection:"Details",gridPreviousRecord:"Previous record",gridNextRecord:"Next record",gridCloseRecord:"Close",gridShowMore:"Show more",gridNoData:"No data",gridPeriodRange:"{from}–{to}: {state}",}));const GRID_ICONS={search:'<circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/>',filter:'<path d="M4 5h16l-6 7.5V19l-4-2v-4.5z"/>',columns:'<rect x="3.5" y="4.5" width="17" height="15" rx="2"/><path d="M9.5 4.5v15M14.5 4.5v15"/>',views:'<path d="M6 4h12v16l-6-4-6 4z"/>',export:'<path d="M12 4v11M7.5 10.5 12 15l4.5-4.5M5 19h14"/>',more:'<circle cx="5" cy="12" r="1.2"/><circle cx="12" cy="12" r="1.2"/><circle cx="19" cy="12" r="1.2"/>',close:'<path d="M6 6l12 12M18 6 6 18"/>',check:'<path d="m5 12.5 4.5 4.5L19 7.5"/>',chart:'<path d="M4 19h16M7 16V10M12 16V6M17 16v-4"/>',copy:'<rect x="8" y="8" width="11" height="11" rx="2"/><path d="M16 8V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h2"/>',up:'<path d="M12 19V5M6 11l6-6 6 6"/>',down:'<path d="M12 5v14M6 13l6 6 6-6"/>',retry:'<path d="M4 12a8 8 0 1 0 2.4-5.7M4 4v4.5h4.5"/>',previous:'<path d="m14 7-5 5 5 5"/>',next:'<path d="m10 7 5 5-5 5"/>',first:'<path d="m13 7-5 5 5 5M17 7l-5 5 5 5"/>',last:'<path d="m11 7 5 5-5 5M7 7l5 5-5 5"/>'};function gridIcon(name,shapes){return svgIcon(shapes||GRID_ICONS[name]||GRID_ICONS.more)}
608
642
  function gridDecorateButton(button,icon,ghost){button.classList.add("cx-btn");if(ghost)button.classList.add("ghost");if(icon)button.prepend(gridIcon(icon));return button}
609
643
  function gridFilterCount(query){const count=group=>group?group.filters.length+group.groups.reduce((sum,child)=>sum+count(child),0):0;return(query?.filters?.length||0)+ count(query?.filterGroup)}
644
+ const GRID_OPTIONS={},GRID_OPTION_GRIDS=new WeakMap();const gridClassName=value=>typeof value==="string"&&value.length<=512&&/^(?:[A-Za-z_][\w-]*)(?: +[A-Za-z_][\w-]*)*$/.test(value);
645
+ function gridColumnOptions(column,columns){if(column.className!=null&&!gridClassName(column.className)||
646
+ column.alignment!=null&&!["start","center","end"].includes(column.alignment)||
647
+ column.sortComparator!=null&&(typeof column.sortComparator!=="string"||!/^[a-z][a-zA-Z\d]{0,31}$/.test(column.sortComparator)) ||
648
+ column.orderData!==undefined&&(!Array.isArray(column.orderData)||column.orderData.length>32||
649
+ new Set(column.orderData).size!==column.orderData.length||column.orderData.some(id=>!columns.some(item=>item.id===id)))||
650
+ column.orderSequence!==undefined&&(!Array.isArray(column.orderSequence)||column.orderSequence.length>3||
651
+ new Set(column.orderSequence).size!==column.orderSequence.length||column.orderSequence.some(value=>!["asc","desc","none"].includes(value))))
652
+ throw new Error("CanopyX: invalid column class, alignment or ordering options.")}
653
+ function gridColumnDefaults(view){const rules=view.columnDefaults;if(rules===undefined)return view;if(!Array.isArray(rules)||rules.length>64)throw new Error("CanopyX: at most 64 column default rules.");const keys=["className","alignment","sortable","filterable","hidden","orderData","orderSequence","sortComparator"];for(const rule of rules){if(!rule||!Array.isArray(rule.targets)||!rule.targets.length||rule.targets.length>64||
654
+ Object.keys(rule).some(key=>key!=="targets"&&!keys.includes(key))||
655
+ rule.targets.some(target=>typeof target!=="string"||!(target[0]==="#"&&target.length>1||/^(\*|\.[A-Za-z_][\w-]*|index:\d+)$/.test(target)) ||
656
+ target[0]==="#"&&!view.columns.some(column=>column.id===target.slice(1))||target.startsWith("index:")&&Number(target.slice(6))>=view.columns.length)||
657
+ ["sortable","filterable","hidden"].some(key=>rule[key]!==undefined&&typeof rule[key]!=="boolean"))
658
+ throw new Error("CanopyX: invalid column defaults.");gridColumnOptions(rule,view.columns)}
659
+ const columns=view.columns.map((column,index)=>{const defaults={};for(const rule of rules)if(rule.targets.some(target=>target==="*"||target==="#"+column.id||target==="index:"+index||
660
+ target[0]==="."&&(column.className||"").split(/ +/).includes(target.slice(1))))
661
+ for(const key of keys)if(defaults[key]===undefined&&rule[key]!=null)defaults[key]=rule[key];return{...defaults,...column}});return{...view,columns}}
662
+ function gridOptionsUsed(view,plugins=[]){return!!(view.footers?.length||view.columns.some(column=>column.orderData||column.sortComparator)||
663
+ plugins.some(plugin=>plugin.filterOperators||plugin.sortComparators))}
610
664
  const GRID_FILTER_LABELS={eq:"=",ne:"≠",contains:"gridContains",startsWith:"gridStartsWith",in:"gridIn",gt:">",ge:"≥",lt:"<",le:"≤",isNull:"gridIsNull",isNotNull:"gridIsNotNull"};function gridQueryRecord(input,record,strict,cursor){if(strict&&Object.keys(input).some(key=>!Object.hasOwn(record,key)&&!(cursor&&key==="offset")))throw new Error("CanopyX: invalid state query.");return gridFreeze(record)}
611
- function gridPredicate(filter,columns,budget){if(++budget.predicates>64)throw new Error("CanopyX: at most 64 grid predicates.");const column=filter&&columns.get(filter.column),values=filter&&filter.values;if(!column||budget.filterable&&column.filterable===false||!Object.keys(GRID_FILTER_LABELS).includes(filter.operator)||
665
+ function gridPredicate(filter,columns,budget){if(++budget.predicates>64)throw new Error("CanopyX: at most 64 grid predicates.");const column=filter&&columns.get(filter.column),values=filter&&filter.values;if(!column||budget.filterable&&column.filterable===false||typeof filter.operator!=="string"||
666
+ !(Object.hasOwn(GRID_FILTER_LABELS,filter.operator)||/^[a-z][a-zA-Z\d]{0,31}$/.test(filter.operator)) ||
612
667
  !Array.isArray(values))
613
668
  throw new Error("CanopyX: invalid grid predicate.");const nullTest=filter.operator==="isNull"||filter.operator==="isNotNull";if(nullTest?values.length!==0:filter.operator==="in"?values.length<1||values.length>1000:values.length!==1)
614
669
  throw new Error("CanopyX: invalid grid predicate arity.");if(["contains","startsWith"].includes(filter.operator)&&(column.kind!=="text"||values.some(value=>typeof value!=="string"))||
@@ -617,9 +672,9 @@ throw new Error("CanopyX: predicate does not match the column kind.");values.for
617
672
  function gridFilterGroup(group,columns,budget,depth){if(depth>8||++budget.groups>64)throw new Error("CanopyX: grid filter groups exceed their depth or count limit.");if(!group||!["and","or"].includes(group.operator)||!Array.isArray(group.filters)||!Array.isArray(group.groups)||
618
673
  !group.filters.length&&!group.groups.length)
619
674
  throw new Error("CanopyX: invalid or empty grid filter group.");const filters=group.filters.map(filter=>gridPredicate(filter,columns,budget));const groups=group.groups.map(child=>gridFilterGroup(child,columns,budget,depth+1));return gridQueryRecord(group,{operator:group.operator,filters,groups},budget.strict)}
620
- function gridMatchesGroup(row,group,columns){if(!group)return true;if(group.operator==="and")return group.filters.every(filter=>gridMatches(row,filter,columns.get(filter.column)))&&
621
- group.groups.every(child=>gridMatchesGroup(row,child,columns));return group.filters.some(filter=>gridMatches(row,filter,columns.get(filter.column)))||
622
- group.groups.some(child=>gridMatchesGroup(row,child,columns))}
675
+ function gridMatchesGroup(row,group,columns,matches=gridMatches){if(!group)return true;if(group.operator==="and")return group.filters.every(filter=>matches(row,filter,columns.get(filter.column)))&&
676
+ group.groups.every(child=>gridMatchesGroup(row,child,columns,matches));return group.filters.some(filter=>matches(row,filter,columns.get(filter.column)))||
677
+ group.groups.some(child=>gridMatchesGroup(row,child,columns,matches))}
623
678
  function gridSearchTerms(text,mode){if(mode!=="words")return text?[foldText(text)]:[];return[...text.matchAll(/"([^"]*)(?:"|$)|([^\s"]+)/g)].map(match => foldText(match[1] === undefined ? match[2] : match[1])).filter(Boolean);
624
679
  }
625
680
  function gridMatchesSearch(row,terms,columns){return terms.every(term=>columns.some(column=>{const cell=row.cells[column.id],text=isCellObject(cell)&&cell.searchText!==undefined?cell.searchText:cellValue(cell);return foldText(text).includes(term)}))}
@@ -627,18 +682,19 @@ function gridQueryStart(query,patch){return{...query,...patch,offset:0,cursor:un
627
682
  function gridNumberFormat(format){const minimum=format?.minimumFractionDigits??0,maximum=format?.maximumFractionDigits??3;if(!format||typeof format!=="object"||Array.isArray(format)||![minimum,maximum].every(digits=>Number.isInteger(digits)&&digits>=0&&digits<=10)||minimum>maximum||
628
683
  Object.keys(format).some(key=>!["minimumFractionDigits","maximumFractionDigits","prefix","suffix"].includes(key))||
629
684
  [format.prefix,format.suffix].some(text=>text!==undefined&&(typeof text!=="string"||!text||text.length>16)))throw new Error("CanopyX: invalid number format.")}
630
- function validateGridView(view){checkDocument(view,"grid");requireIdentifier(view.id,"grid ID");if(view.rowIdentity!==undefined&&!["stableKey","ordinal"].includes(view.rowIdentity))
685
+ function validateGridView(view){checkDocument(view,"grid");requireIdentifier(view.id,"grid ID");view=gridColumnDefaults(view);if(view.rowIdentity!==undefined&&!["stableKey","ordinal"].includes(view.rowIdentity))
631
686
  throw new Error("CanopyX: rowIdentity must be stableKey or ordinal.");if(view.rowIdentity==="ordinal"&&view.live)
632
687
  throw new Error("CanopyX: ordinal row identity is snapshot-local; keyed live updates require stable row keys.");if(view.rowIdentity==="ordinal"&&view.record?.deepLink)
633
688
  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)
634
689
  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)}
635
690
  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)||
691
+ column.headerDescription!==undefined&&typeof column.headerDescription!=="string"||
636
692
  column.width!==undefined&&(!Number.isInteger(column.width)||column.width<40)||
637
693
  ["wrap","autoWidth","fixed","rowHeader","alwaysVisible","editable","filterable","exportable"].some(name=>column[name]!==undefined&&typeof column[name]!=="boolean")||
638
694
  column.flex!==undefined&&!(typeof column.flex==="number"&&column.flex>=0&&column.flex<=100)||column.autoSize!==undefined&&!["content","header","none"].includes(column.autoSize)||
639
695
  column.pinned!==undefined&&![null,"left","right"].includes(column.pinned)||column.priority!==undefined&&!gridPriority(column.priority)||
640
696
  column.fixed&&column.width===undefined||column.tooltip!==undefined&&column.tooltip!=="auto"&&!view.columns.some(item=>item.id===column.tooltip))
641
- 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)}
697
+ throw new Error("CanopyX: invalid or duplicate grid column.");gridColumnOptions(column,view.columns);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)}
642
698
  if(column.aggregatable!==undefined&&(typeof column.aggregatable!=="boolean"||column.aggregatable&&column.kind!=="number")||
643
699
  column.section!==undefined&&(typeof column.section!=="string"||!column.section.trim()||column.section.length>256))
644
700
  throw new Error("CanopyX: invalid column aggregate or drawer section.")}
@@ -658,7 +714,7 @@ view.estimatedRowHeight!==undefined&&(!Number.isInteger(view.estimatedRowHeight)
658
714
  throw new Error("CanopyX: invalid grid source navigation.");if(view.source.navigation==="cursor"&&(view.source.kind!=="host"||view.presentation!=="paged"))
659
715
  throw new Error("CanopyX: cursors need a hosted paged grid.");if(view.presentation!==undefined&&!["continuous","paged"].includes(view.presentation)||
660
716
  view.pageLength!==undefined&&(!Number.isInteger(view.pageLength)||view.pageLength<1||view.pageLength>10000))
661
- throw new Error("CanopyX: invalid grid presentation or page length.");if(view.rowData!==undefined){if(view.source.kind!=="inline"||view.rows!==undefined||!validStructuralCount(view.rowData?.count))throw new Error("CanopyX: invalid grid rowData.")}else if(view.source.kind==="inline")validateGridRows(view.rows,view.columns);else if(view.rows!==undefined)throw new Error("CanopyX: host grids cannot discard inline rows.");if(view.query!==undefined)gridQuery(view,view.query);return{...view,rowHeight:view.rowHeight??(view.density==="compact"?28:view.density==="comfortable"?42:34)}}
717
+ throw new Error("CanopyX: invalid grid presentation or page length.");if(view.rowData!==undefined){if(view.source.kind!=="inline"||view.rows!==undefined||!validStructuralCount(view.rowData?.count))throw new Error("CanopyX: invalid grid rowData.")}else if(view.source.kind==="inline")validateGridRows(view.rows,view.columns);else if(view.rows!==undefined)throw new Error("CanopyX: host grids cannot discard inline rows.");if(view.query!==undefined)gridQuery(view,view.query);return{...view,rowHeight:view.rowHeight??(view.density==="compact"?32:40)}}
662
718
  function gridQuery(view,input,strict){input=input||{};const cursor=view.source.navigation==="cursor",type=cursor?"gridCursorQuery":"gridQuery";if(typeof input!=="object"||Array.isArray(input)||
663
719
  input.protocol!==undefined&&input.protocol!==PROTOCOL||input.type!==undefined&&input.type!==type||
664
720
  input.view!==undefined&&input.view!==view.id)throw new Error("CanopyX: invalid grid query identity.");const query={protocol:PROTOCOL,type,view:view.id,limit:input.limit===undefined?cursor?view.pageLength||50:view.pageSize:input.limit,search:input.search===undefined?"":input.search,cursor:input.cursor,revision:input.revision,searchMode:input.searchMode,filterGroup:undefined};if(cursor?input.offset!==undefined&&input.offset!==0:input.cursor!==undefined)
@@ -667,7 +723,9 @@ throw new Error("CanopyX: invalid grid query window or search.");if(input.revisi
667
723
  if(input.searchMode!==undefined&&!["substring","words"].includes(input.searchMode))throw new Error("CanopyX: invalid grid search mode.");const columns=new Map(view.columns.map(column=>[column.id,column])),sorts=new Set();if(input.sort!==undefined&&!Array.isArray(input.sort)||input.filters!==undefined&&!Array.isArray(input.filters))
668
724
  throw new Error("CanopyX: grid sort and filters must be arrays.");query.sort=(input.sort||[]).map(sort=>{if(!sort||!columns.has(sort.column)||!columns.get(sort.column).sortable||sorts.has(sort.column)||
669
725
  !["asc","desc"].includes(sort.direction))
670
- throw new Error("CanopyX: invalid grid sort column or direction.");sorts.add(sort.column);return gridQueryRecord(sort,{column:sort.column,direction:sort.direction},strict)});const budget={predicates:0,groups:0,strict,filterable:true};query.filters=(input.filters||[]).map(filter=>gridPredicate(filter,columns,budget));if(input.filterGroup!==undefined)query.filterGroup=gridFilterGroup(input.filterGroup,columns,budget,1);if(input[LINK_IMPL.queryOwn])query[LINK_IMPL.queryOwn]=true;return gridQueryRecord(input,query,strict,cursor)}
726
+ throw new Error("CanopyX: invalid grid sort column or direction.");sorts.add(sort.column);return gridQueryRecord(sort,{column:sort.column,direction:sort.direction},strict)});if(view.preSort!==undefined){if(!Array.isArray(view.preSort)||view.preSort.length>32)throw new Error("CanopyX: invalid fixed pre-sort.");const fixed=new Set();for(const sort of view.preSort){if(!columns.get(sort?.column)?.sortable||!["asc","desc"].includes(sort.direction)||fixed.has(sort.column))throw new Error("CanopyX: invalid fixed pre-sort.");fixed.add(sort.column)}
727
+ query.sort=[...view.preSort.map(sort=>({column:sort.column,direction:sort.direction})),...query.sort.filter(sort=>!fixed.has(sort.column))]}
728
+ const budget={predicates:0,groups:0,strict,filterable:true};query.filters=(input.filters||[]).map(filter=>gridPredicate(filter,columns,budget));if(input.filterGroup!==undefined)query.filterGroup=gridFilterGroup(input.filterGroup,columns,budget,1);if(input[LINK_IMPL.queryOwn])query[LINK_IMPL.queryOwn]=true;return gridQueryRecord(input,query,strict,cursor)}
671
729
  function validateGridPage(page,view,query,accepted){checkDocument(page,"gridPage");requireIdentifier(page.revision,"grid revision");if(page.view!==view.id||page.offset!==query.offset||!validStructuralCount(page.total)||!validStructuralCount(page.matched)||
672
730
  page.matched>page.total||page.offset>page.matched||!Array.isArray(page.items)||
673
731
  page.items.length!==Math.min(query.limit,page.matched-page.offset))throw new Error("CanopyX: grid page does not cover its requested window.");return checkedGridPage(page,view,query,accepted)}
@@ -678,12 +736,13 @@ function gridOrder(left,right){return left===right?0:left<right?-1:1}
678
736
  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}
679
737
  return id.length>0}
680
738
  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}
681
- function gridSortScalar(cell,column){return isCellObject(cell)&&cell.sort!=null?cell.sort:gridScalar(cell,column)}
739
+ function gridSortScalar(cell,column){return!column.valueOrder?.length&&isCellObject(cell)&&cell.sort!=null?cell.sort:gridScalar(cell,column)}
682
740
  function gridCompare(left,right,column,direction){return gridKeyCompare(gridSortScalar(left.cells[column.id],column),gridSortScalar(right.cells[column.id],column),column,direction)}
683
- 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}
684
- function gridMatches(row,predicate,column){return cellMatches(row.cells[column.id],predicate,column)}
685
- 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)&&
686
- 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}
741
+ 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}
742
+ 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}
743
+ function gridMatches(row,predicate,column){if(!Object.hasOwn(GRID_FILTER_LABELS,predicate.operator))throw new Error("CanopyX: no plugin provides filter operator '"+predicate.operator+"'.");return cellMatches(row.cells[column.id],predicate,column)}
744
+ function gridQueryRows(view,query,columns,compare=gridCompare,matches=gridMatches,extended=false){if(!extended&&GRID_OPTIONS.queryRows&&GRID_OPTION_GRIDS.has(view))return GRID_OPTIONS.queryRows(view,query,columns,compare);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)&&
745
+ query.filters.every(predicate=>matches(row,predicate,columns.get(predicate.column)))&&gridMatchesGroup(row,query.filterGroup,columns,matches));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}
687
746
  return gridIdOrder(a.id,b.id)}):rows;const sorts=query.sort.map(sort=>[columns.get(sort.column),sort.direction]),keys=sorts.map(([column])=>rows.map(row=>gridSortScalar(row.cells[column.id],column)));return rows.map((row,index)=>index).sort((a,b)=>{for(let s=0;s<sorts.length;s++){const compared=gridKeyCompare(keys[s][a],keys[s][b],sorts[s][0],sorts[s][1]);if(compared)return compared}
688
747
  return gridIdOrder(rows[a].id,rows[b].id)}).map(index=>rows[index])}
689
748
  function inlineGridSource(view){const columns=new Map(view.columns.map(column=>[column.id,column]));const compare=GRID_REPORTING.compare?.(view);let lastShape=null,ordered=null;return{query(query,options){if(options.signal.aborted)throw new DOMException("Grid cancelled.","AbortError");const shape=gridResultShape(query);if(shape!==lastShape){ordered=gridQueryRows(view,query,columns,compare);lastShape=shape}
@@ -697,7 +756,7 @@ page.total!==null&&page.matched!==null&&page.matched>page.total||
697
756
  !page.items.length&&(page.offset!==0||next)||!page.offset&&previous||
698
757
  page.matched!==null&&next!==(end<page.matched)||page.total!==null&&next&&end>=page.total||
699
758
  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)}
700
- 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):
759
+ 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)):
701
760
  typeof scalar==="boolean"?"b:"+scalar:"n:"+scalar}
702
761
  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||
703
762
  input.search!==request.search||input.includeCurrentFilter!==request.includeCurrentFilter||
@@ -714,7 +773,8 @@ throw new Error("CanopyX: facet buckets contradict the matching row count.");ret
714
773
  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)
715
774
  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=[]}
716
775
  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"))
717
- 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?
776
+ 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||
777
+ this.view.autoRowHeight!==false&&this.view.columns.some(column=>column.wrap);this.autoRows=this.authoredAutoRows;this.rowH=this.view.rowHeight==="auto"?this.view.estimatedRowHeight||(this.view.density==="compact"?32:40):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?
718
778
  this.view.source.kind==="inline"?0:300:this.view.searchDelayMs:options.searchDelayMs;if(!Number.isInteger(this.searchDelayMs)||this.searchDelayMs<0||this.searchDelayMs>5000)
719
779
  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||
720
780
  !Number.isInteger(this.requestTimeoutMs)||this.requestTimeoutMs<1||this.requestTimeoutMs>2147483647)
@@ -726,7 +786,7 @@ stateChanged(){if(this.destroyed||this.restoringEpoch===this.queryEpoch)return;c
726
786
  getQuery(){return this.acceptedQuery||null}
727
787
  queryForChange(includeQueuedInput){const query=this.pendingQuery||this.acceptedQuery||{};return includeQueuedInput&&this.searchTimer!=null&&!this.searchComposing?
728
788
  gridQueryStart(query,{search:this.searchInput.value}):query}
729
- async setQuery(input,paging){if(this.destroyed)throw new DOMException("Grid was destroyed.","AbortError");const length=paging?paging.pageLength:this.pageLength;const initial=gridQuery(this.view,this.cursor?{...input,limit:length}:input);const desired=this.cursor?0:Math.floor(initial.offset / length) * length;
789
+ async setQuery(input,paging){if(this.destroyed)throw new DOMException("Grid was destroyed.","AbortError");const length=paging?paging.pageLength:this.pageLength;const footerPage=this.paged&&this.view.source.kind==="host"&&this.view.footers?.some(footer=>footer.scope==="page");const initial=gridQuery(this.view,this.cursor||footerPage?{...input,limit:length}:input);const desired=this.cursor?0:Math.floor(initial.offset / length) * length;
730
790
  const same=this.acceptedQuery&&gridResultShape(initial)===gridResultShape(this.acceptedQuery)&&initial.revision===this.acceptedQuery.revision;let query=this.paged&&!this.cursor?gridQuery(this.view,{...initial,offset:same?Math.min(desired,Math.max(0,Math.ceil(this.rowCount()/ length) - 1) * length) : 0 }) : initial;
731
791
  const epoch=++this.queryEpoch;clearTimeout(this.searchTimer);this.searchTimer=null;this.dataLifetime.abort();this.dataLifetime=new AbortController();const lifetime=this.dataLifetime;this.pendingPages.clear();this.pendingQuery=query;this.pendingPaging=paging?{...paging,pageLength:length}:null;this.setNotice(this.labels.loading,false);this.grid.setAttribute("aria-busy","true");this.syncPager();try{let page=(this.cursor?validateGridCursorPage:validateGridPage)(await this.requestPage(query,lifetime.signal),this.view,query,same?this.snapshot:null);if(this.cursor&&paging&&paging.direction)this.validateCursorTransition(page,paging);if(this.paged&&!this.cursor&&!same&&desired){gridOperationActive(this,lifetime.signal);const offset=Math.min(desired,Math.max(0,Math.ceil(page.matched / length) - 1) * length);
732
792
  if(offset){const snapshot={revision:page.revision,total:page.total,matched:page.matched};query=gridQuery(this.view,{...query,offset,revision:page.revision});page=validateGridPage(await this.requestPage(query,lifetime.signal),this.view,query,snapshot)}}
@@ -735,7 +795,7 @@ this.storePage(page);this.pendingQuery=null;this.pendingPaging=null;this.lastFai
735
795
  this.render();if(hadFocus){const element=this.focused&&this.rendered.get(this.focused);(element||this.grid).focus({preventScroll:true})}
736
796
  this.host.setAttribute("data-cx-ready","true");if(this.searchInput&&!this.searchComposing&&this.searchTimer==null)this.searchInput.value=query.search;this.syncQuerySummary();this.syncPager();this.emit("query",{query:this.acceptedQuery,revision:page.revision,total:page.total,matched:page.matched});this.stateChanged();return this.getQuery()}catch(error){if(epoch===this.queryEpoch&&!this.destroyed){this.pendingQuery=null;this.pendingPaging=null;this.lastFailedQuery=initial;this.lastFailedPaging={...paging,pageLength:length};this.dataLifetime.abort();this.dataLifetime=new AbortController();this.grid.setAttribute("aria-busy","false");this.setNotice(fill(this.labels.queryFailed,{error:error.message}),true);this.syncPager();this.emit("error",{error})}
737
797
  throw error}}
738
- querySortHeader(id,event){const previous=gridQuery(this.view,this.queryForChange(true)),sorts=previous.sort.slice();const found=sorts.findIndex(sort=>sort.column===id),old=found>=0?sorts[found].direction:null;const next=old==="asc"?"desc":old==="desc"?null:"asc";const changed=event&&event.shiftKey?sorts.filter(sort=>sort.column!==id):[];if(next)changed.splice(event&&event.shiftKey&&found>=0?Math.min(found,changed.length):changed.length,0,{column:id,direction:next});this.setQuery(gridQueryStart(previous,{sort:changed})).catch(()=>{})}
798
+ querySortHeader(id,event){const previous=gridQuery(this.view,this.queryForChange(true)),sorts=previous.sort.slice();const found=sorts.findIndex(sort=>sort.column===id),old=found>=0?sorts[found].direction:null;const authored=this.columns.find(column=>column.id===id).orderSequence;const sequence=authored?.length?authored:["asc","desc","none"];const direction=sequence[(sequence.indexOf(old||"none")+ 1)%sequence.length];const next=direction==="none"?null:direction;const changed=event&&event.shiftKey?sorts.filter(sort=>sort.column!==id):[];if(next)changed.splice(event&&event.shiftKey&&found>=0?Math.min(found,changed.length):changed.length,0,{column:id,direction:next});this.setQuery(gridQueryStart(previous,{sort:changed})).catch(()=>{})}
739
799
  sort(sorts){return this.setQuery(gridQueryStart(this.queryForChange(true),{sort:sorts}))}
740
800
  rowCount(){return this.cursor?this.cursorWindow?this.cursorWindow.end:0:this.snapshot?this.snapshot.matched:0}
741
801
  rowBounds(){return{first:this.pageOffset,last:this.paged?Math.min(this.rowCount(),this.pageOffset+this.pageLength)- 1:this.rowCount()- 1}}
@@ -792,7 +852,7 @@ if(this.pendingNavigation!==navigation)return;if(this.destroyed||this.pendingQue
792
852
  throw new Error("CanopyX: row position is outside the accepted result page.");const epoch=this.queryEpoch,ownsFocus=focus&&this.canvas.contains(document.activeElement);const initial=this.rowItem(index);this.setFocus(initial,ownsFocus);navigation.epoch=epoch;this.pendingNavigation=navigation;if(focus===false&&column==null&&control==null&&initial&&!initial.status&&
793
853
  !this.destroyed&&!this.dataLifetime.signal.aborted&&epoch===this.queryEpoch&&!this.pendingQuery&&
794
854
  this.pendingNavigation===navigation&&this.rowCache.get(index)===initial&&this.focused===initial&&
795
- this.rendered.get(initial)?.isConnected)return;const navigationTop=this.logicalTop();const row=await this.waitForRow(index,epoch);if(this.destroyed||epoch!==this.queryEpoch||this.pendingQuery)throw new DOMException("Grid navigation was superseded.","AbortError");if(this.pendingNavigation!==navigation)return;if(focus&&(!ownsFocus||!this.canvas.contains(document.activeElement)||!this.focused||this.focused._ri!==index))return;const currentColumn=columnId?this.visibleColumns().findIndex(item=>item.id===columnId):-1;if(!focus||currentColumn<0||!row||row.status){if(this.logicalTop()===navigationTop)this.setFocus(row,focus)}else{const currentTop=this.logicalTop();this.focusCell(row,currentColumn,control);if(currentTop!==navigationTop){this.setLogicalTop(currentTop);this.render()}}}finally{if(this.pendingNavigation===navigation)this.pendingNavigation=null}}});Object.assign(DataGrid.prototype,{build(){const host=this.host,style=host.style,signal=this.lifetime.signal;const minimum=style.getPropertyValue("--cx-min-h"),priority=style.getPropertyPriority("--cx-min-h"),rowHeight=style.getPropertyValue("--cx-row-h"),rowPriority=style.getPropertyPriority("--cx-row-h"),density=host.getAttribute("data-cx-density"),maximum=style.maxHeight;this.restoreHeight=()=>{style.maxHeight=maximum;style.setProperty("--cx-min-h",minimum,priority);style.setProperty("--cx-row-h",rowHeight,rowPriority);if(density===null)host.removeAttribute("data-cx-density");else host.setAttribute("data-cx-density",density)};style.removeProperty("--cx-min-h");host.classList.add("cx-host","cx-data-grid","cx-chrome");host.classList.toggle("cx-row-accents",!!this.view.rowAccents);host.setAttribute("data-cx-density",this.view.density||"default");if(!host.hasAttribute("data-cx-theme"))host.setAttribute("data-cx-theme","auto");style.setProperty("--cx-row-h",this.rowH+"px");this.toolbar=h("div","cx-toolbar");this.toolbar.hidden=this.opts.toolbar===false;if(this.view.search&&this.tools.search!==false)this.buildGridSearch();this.buildGridControls();this.buildGridChrome();this.buildQuerySummary();const grid=this.grid=h("div","cx-grid");grid.id=this.id;grid.tabIndex=-1;grid.setAttribute("role","grid");grid.setAttribute("aria-label",this.view.label);if(this.multi)grid.setAttribute("aria-multiselectable","true");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.notice=h("div","cx-grid-notice");this.notice.hidden=true;this.live=h("div","cx-live cx-sr-only");this.live.setAttribute("aria-live","polite");host.append(this.toolbar,this.querySummary);if(this.groupBar)host.appendChild(this.groupBar);host.append(this.notice,grid,this.live);this.buildPager();this.buildGridStatus();this.buildHeader();grid.addEventListener("scroll",()=>{this.scheduleRender();this.syncPinnedShadows();this.stateChanged()},{passive:true,signal});grid.addEventListener("click",event=>this.onClick(event),{signal});grid.addEventListener("pointerover",event=>this.cellTip(event),{signal});grid.addEventListener("dblclick",event=>{const element=event.target.closest(".cx-row"),row=element&&element._w;if(row&&!row.status&&!event.target.closest("a,button,input,select,textarea,[contenteditable]")&&!this.clickAction(element))
855
+ this.rendered.get(initial)?.isConnected)return;const navigationTop=this.logicalTop();const row=await this.waitForRow(index,epoch);if(this.destroyed||epoch!==this.queryEpoch||this.pendingQuery)throw new DOMException("Grid navigation was superseded.","AbortError");if(this.pendingNavigation!==navigation)return;if(focus&&(!ownsFocus||!this.canvas.contains(document.activeElement)||!this.focused||this.focused._ri!==index))return;const currentColumn=columnId?this.visibleColumns().findIndex(item=>item.id===columnId):-1;if(!focus||currentColumn<0||!row||row.status){if(this.logicalTop()===navigationTop)this.setFocus(row,focus)}else{const currentTop=this.logicalTop();this.focusCell(row,currentColumn,control);if(currentTop!==navigationTop){this.setLogicalTop(currentTop);this.render()}}}finally{if(this.pendingNavigation===navigation)this.pendingNavigation=null}}});Object.assign(DataGrid.prototype,{build(){const host=this.host,style=host.style,signal=this.lifetime.signal;const minimum=style.getPropertyValue("--cx-min-h"),priority=style.getPropertyPriority("--cx-min-h"),rowHeight=style.getPropertyValue("--cx-row-h"),rowPriority=style.getPropertyPriority("--cx-row-h"),density=host.getAttribute("data-cx-density"),maximum=style.maxHeight;this.restoreHeight=()=>{style.maxHeight=maximum;style.setProperty("--cx-min-h",minimum,priority);style.setProperty("--cx-row-h",rowHeight,rowPriority);if(density===null)host.removeAttribute("data-cx-density");else host.setAttribute("data-cx-density",density)};style.removeProperty("--cx-min-h");host.classList.add("cx-host","cx-data-grid","cx-chrome");host.classList.toggle("cx-row-accents",!!this.view.rowAccents);host.setAttribute("data-cx-density",this.view.density||"default");watchTheme(host,signal);style.setProperty("--cx-row-h",this.rowH+"px");this.toolbar=h("div","cx-toolbar");this.toolbar.hidden=this.opts.toolbar===false;if(this.view.search&&this.tools.search!==false)this.buildGridSearch();this.buildGridControls();this.buildGridChrome();this.buildQuerySummary();const grid=this.grid=h("div","cx-grid");grid.id=this.id;grid.tabIndex=-1;grid.setAttribute("role","grid");grid.setAttribute("aria-label",this.view.label);if(this.multi)grid.setAttribute("aria-multiselectable","true");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.notice=h("div","cx-grid-notice");this.notice.hidden=true;this.live=h("div","cx-live cx-sr-only");this.live.setAttribute("aria-live","polite");host.append(this.toolbar,this.querySummary);if(this.groupBar)host.appendChild(this.groupBar);host.append(this.notice,grid,this.live);this.buildPager();this.buildGridStatus();this.buildHeader();grid.addEventListener("scroll",()=>{this.scheduleRender();this.syncPinnedShadows();this.stateChanged()},{passive:true,signal});grid.addEventListener("click",event=>this.onClick(event),{signal});grid.addEventListener("pointerover",event=>this.cellTip(event),{signal});grid.addEventListener("dblclick",event=>{const element=event.target.closest(".cx-row"),row=element&&element._w;if(row&&!row.status&&!event.target.closest("a,button,input,select,textarea,[contenteditable]")&&!this.clickAction(element))
796
856
  this.activateRow(row,false)},{signal});grid.addEventListener("keydown",event=>this.onKey(event),{signal});if(this.view.dragRows){grid.addEventListener("dragstart",event=>this.gridDragStart(event),{signal});grid.addEventListener("dragend",()=>{GRID_DRAG.item=null},{signal})}
797
857
  this.canvas.addEventListener("focusin",event=>{const element=event.target.closest(".cx-row");if(element&&element._w&&this.pendingNavigation&&this.pendingQuery&&element._w._ri!==this.pendingNavigation.index)
798
858
  this.pendingNavigation=null;if(element&&element._w&&this.focused!==element._w){this.pendingNavigation=null;this.focused=element._w;this.scheduleRender()}},{signal});document.addEventListener("focusin",event=>{if(this.pendingNavigation&&this.pendingNavigation.focus&&!this.canvas.contains(event.target))this.pendingNavigation=null;if(this.focusOrigin&&event.target!==this.focusOrigin)this.focusOrigin=null},{signal,capture:true});document.addEventListener("focusout",event=>{if(event.target===this.focusOrigin)this.focusOrigin=null},{signal,capture:true});this.canvas.addEventListener("focusout",event=>this.settleCell(event.relatedTarget),{signal});this.sized=this.hasGridSize();grid.style.opacity="0";let resizeFrame;signal.addEventListener("abort",()=>cancelAnimationFrame(resizeFrame),{once:true});this.resizeObserver=new ResizeObserver(entries=>{const size=entries.find(entry=>entry.target===grid);if(size)this.fitContentWidth=size.contentRect.width;if(size&&!size.contentRect.width)grid.style.opacity="0";const resize=()=>{if(this.destroyed)return;if(!grid.clientWidth||!grid.checkVisibility()){this.sized=false;return}
@@ -800,13 +860,14 @@ style.setProperty("--cx-min-h",(this.toolbar.hidden?0:[...host.children].reduce(
800
860
  height +(child===grid?0:child.offsetHeight),this.rowH*Math.min(4,Math.max(1,this.rowCount()))+ 2))+ "px");this.fitHeight();if(!(this.sized=this.hasGridSize()))return;this.applyWidths();this.updateGridPhone();this.fitHeight();this.viewportHeight=grid.clientHeight-this.head.offsetHeight;if(this.hiddenScrollTop!==undefined){const top=this.hiddenScrollTop;delete this.hiddenScrollTop;this.setLogicalTop(top)}
801
861
  if(grid.style.opacity){this.render();grid.style.opacity=""}
802
862
  else this.scheduleRender()};cancelAnimationFrame(resizeFrame);resizeFrame=requestAnimationFrame(resize)});this.resizeObserver.observe(grid);this.resizeObserver.observe(this.head)},setLogicalTop(top){if(!this.hasGridSize()){this.hiddenScrollTop=top;return}
803
- return ROW_SCROLLING.setLogicalTop.call(this,top)},logicalTop(){return this.hiddenScrollTop??ROW_SCROLLING.logicalTop.call(this)},hasGridSize(){return!!(this.grid.clientWidth&&this.grid.clientHeight&&this.grid.checkVisibility())},buildHeader(){const sorts=this.acceptedQuery?this.acceptedQuery.sort:[];this.sortState=sorts[0]||null;ROW_HELPERS.buildHeader.call(this);for(const cell of this.headCells){const button=cell.querySelector(".cx-sort");if(button){const label=h("span","cx-htext");setText(label,button.textContent);button.replaceChildren(label)}
863
+ const result=ROW_SCROLLING.setLogicalTop.call(this,top);this.visibleScrollTop=ROW_SCROLLING.logicalTop.call(this);return result},logicalTop(){if(this.hiddenScrollTop!==undefined)return this.hiddenScrollTop;if(!this.grid.checkVisibility())return this.visibleScrollTop??0;return this.visibleScrollTop=ROW_SCROLLING.logicalTop.call(this)},hasGridSize(){return!!(this.grid.clientWidth&&this.grid.clientHeight&&this.grid.checkVisibility())},buildHeader(){const fixed=new Set((this.view.preSort||[]).map(sort=>sort.column));const sorts=(this.acceptedQuery?.sort||[]).filter(sort=>!fixed.has(sort.column));const fixedText=(this.view.preSort||[]).map(sort=>(this.columns.find(column=>column.id===sort.column)?.title||sort.column)+ " "+sort.direction).join(", ");this.sortState=sorts[0]||null;ROW_HELPERS.buildHeader.call(this);for(const cell of this.headCells){const column=this.columns.find(column=>column.id===cell.getAttribute("data-cx-column"));if(column?.className)cell.classList.add(...column.className.split(/ +/));
864
+ if(column?.alignment)cell.style.textAlign=column.alignment;const button=cell.querySelector(".cx-sort");if(fixedText)cell.title +="\nAlways sorted by "+fixedText+" first";if(button){const label=h("span","cx-htext");setText(label,button.textContent);button.replaceChildren(label)}
804
865
  const index=sorts.findIndex(sort=>sort.column===cell.getAttribute("data-cx-column"));if(index>=0){cell.setAttribute("aria-sort",sorts.length===1?sorts[index].direction==="asc"?"ascending":"descending":"other");cell.setAttribute("data-cx-sort",sorts[index].direction);cell.setAttribute("data-cx-sort-priority",String(index+1));button.setAttribute("data-cx-sort-priority",String(index+1));if(sorts.length>1){const priority=h("sup","cx-sort-priority");setText(priority,String(index+1));button.appendChild(priority)}
805
- button.setAttribute("aria-label",cell.getAttribute("aria-label")+ ", "+sorts[index].direction+", " +(index+1))}}
806
- 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})}
866
+ button.setAttribute("aria-label",cell.getAttribute("aria-label")+ ", "+sorts[index].direction +(sorts.length>1?", " +(index+1):"")+(fixedText?". "+cell.title:""))}}
867
+ 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;if(column?.alignment)cell.style.textAlign=column.alignment;const slot={cell,content,base:cell.className +(column?.className?" "+column.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})}
807
868
  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 || ""
808
869
  }):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}
809
- 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}
870
+ 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}
810
871
  else if(slot.missing){slot.cell.classList.remove("p-missing");slot.missing=false}
811
872
  if(this.phone||slot.hiddenFields||slot.phonePrimary)this.paintHiddenFields?.(slot,row.h,column,this.columnIndex[i])}
812
873
  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}
@@ -824,7 +885,7 @@ set(index,height){const delta=height -(this.heights.get(index)??this.estimate);t
824
885
  at(y){let index=0,sum=0;for(let step=2**Math.floor(Math.log2(this.count||1));step>=1;step /= 2) {
825
886
  const next=index+step,block=step*this.estimate +(this.deltas.get(next)||0);if(next<=this.count&&sum+block<=y){index=next;sum +=block}}
826
887
  return Math.max(0,Math.min(this.count-1,index))}}
827
- const AUTO_WIDTHS=DataGrid.prototype.applyWidths;DataGrid.prototype.applyWidths=function(widths){AUTO_WIDTHS.call(this,widths);if(!this.autoRows)return;const shape=JSON.stringify(this.cols.map((column,i)=>[column.id,widths?.[i]??column.width]));if(shape!==this.rowWidthShape){this.rowWidthShape=shape;this.measureNeeded=true;this.scheduleRender()}};Object.assign(DataGrid.prototype,{observeDetail(element,auto){if(this.autoRows)TreeGrid.prototype.observeDetail.call(this,element,auto)},gridRowAnchor(){const rows=this.rowProjection||this,top=this.logicalTop(),index=rows.rowAt(top);return{index,offset:top-rows.rowTop(index)}},syncRowOffsets(){const rows=this.rowProjection,bounds=this.rowBounds(),count=rows?rows.rowCount():Math.max(0,bounds.last-bounds.first+1);if(this.rowOffsets&&this.rowOffsetOwner===rows&&this.rowOffsetFirst===bounds.first&&this.rowOffsets.count===count)return;this.rowOffsets=new GridRowOffsets(count,this.rowH);this.rowOffsetOwner=rows;this.rowOffsetFirst=bounds.first;for(const[ordinal,height]of this.rowHeights){const index=rows?rows.recordIndex(ordinal):ordinal-bounds.first;if(index>=0&&index<count)this.rowOffsets.set(index,height)}
888
+ const GRID_ROW_TOP=DataGrid.prototype.rowTop,GRID_ROW_AT=DataGrid.prototype.rowAt;DataGrid.prototype.rowTop=function(index){if(this.autoRows&&!this.rowProjection&&!this.rowOffsets)this.syncRowOffsets();return GRID_ROW_TOP.call(this,index)};DataGrid.prototype.rowAt=function(top){if(this.autoRows&&!this.rowProjection&&!this.rowOffsets)this.syncRowOffsets();return GRID_ROW_AT.call(this,top)};const AUTO_WIDTHS=DataGrid.prototype.applyWidths;DataGrid.prototype.applyWidths=function(widths){AUTO_WIDTHS.call(this,widths);if(!this.autoRows)return;const shape=JSON.stringify(this.cols.map((column,i)=>[column.id,widths?.[i]??column.width]));if(shape!==this.rowWidthShape){this.rowWidthShape=shape;this.measureNeeded=true;this.scheduleRender()}};Object.assign(DataGrid.prototype,{observeDetail(element,auto){if(this.autoRows)TreeGrid.prototype.observeDetail.call(this,element,auto)},gridRowAnchor(){const rows=this.rowProjection||this,top=this.logicalTop(),index=rows.rowAt(top);return{index,offset:top-rows.rowTop(index)}},syncRowOffsets(){const rows=this.rowProjection,bounds=this.rowBounds(),count=rows?rows.rowCount():Math.max(0,bounds.last-bounds.first+1);if(this.rowOffsets&&this.rowOffsetOwner===rows&&this.rowOffsetFirst===bounds.first&&this.rowOffsets.count===count)return;this.rowOffsets=new GridRowOffsets(count,this.rowH);this.rowOffsetOwner=rows;this.rowOffsetFirst=bounds.first;for(const[ordinal,height]of this.rowHeights){const index=rows?rows.recordIndex(ordinal):ordinal-bounds.first;if(index>=0&&index<count)this.rowOffsets.set(index,height)}
828
889
  this.total=this.rowOffsets.top(count);this.syncScrollRange(this.logicalTop());this.measureNeeded=true},measureGridRows(){if(!this.measureNeeded||!this.rowOffsets||!this.hasGridSize())return false;this.measureNeeded=false;const rows=this.rowProjection||this,anchor=this.gridRowAnchor();let changed=false;for(const[row,element]of this.rendered){if(row.status||row.group)continue;const index=rows.indexOf(row)-(this.rowProjection?0:this.pageOffset),measured=element.offsetHeight;if(index<0||!measured)continue;const height=Math.max(this.rowH,measured);row.hpx=height;if(height!==(this.rowOffsets.heights.get(index)??this.rowH)){this.rowOffsets.set(index,height);this.rowHeights.set(row._ri,height);changed=true}}
829
890
  if(changed){this.total=this.rowOffsets.top(this.rowOffsets.count);this.syncScrollRange(rows.rowTop(anchor.index)+ anchor.offset)}
830
891
  return changed},revealGridRow(row,index,rows=this){const top=rows.rowTop(index),viewport=Math.max(0,this.grid.clientHeight-this.head.offsetHeight);if(top<this.logicalTop())this.setLogicalTop(top);else if(top+Math.min(row.hpx,viewport)>this.logicalTop()+ viewport)this.setLogicalTop(top+Math.min(row.hpx,viewport)- viewport)},gridPageStep(row,direction,rows=this){const index=this.rowProjection?rows.indexOf(row):row._ri;if(!this.autoRows)return index+direction*Math.max(1,Math.floor((this.grid.clientHeight-this.head.offsetHeight)/ this.rowH));
@@ -872,15 +933,15 @@ Object.assign(DataGrid.prototype,COLUMN_FIT,{fitAvailableWidth(){const grid=this
872
933
  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)))}
873
934
  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;
874
935
  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}
875
- 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})}
936
+ this.headCells.forEach((cell,index)=>{cell.querySelector(".cx-sort,.cx-htext").title=cell.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})}
876
937
  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}
877
938
  queueMicrotask(()=>this.destroyed||this.applyWidths())}
878
939
  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}
879
940
  for(const column of this.columns){if(!column.fixed&&!column.sized)column.width=this.fitSize(column)}
880
- 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))}
941
+ 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(head?.paddingRight)||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))}
881
942
  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))+
882
943
  (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+/);
883
- 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)+
944
+ 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;const atomicWidth=atomic?text(value,pill?pillFont:undefined)+
884
945
  (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:
885
946
  Math.min(kind==="longText"||kind==="tags"||kind==="list"||column.wrap?320:420,text(value))+
886
947
  (kind==="progress"?80:kind==="tags"||kind==="list"?48:0));sampled++}
@@ -888,10 +949,12 @@ const cap=columnWidth(column,kind==="enum"||kind==="state"?column.maxW:420);cons
888
949
  this.fitKey=null;this.applyWidths();this.stateChanged()},setColumnPriority(id,priority){const column=this.columns.find(item=>item.id===id);if(!column||!gridPriority(priority))throw new Error("CanopyX: invalid column priority.");column.priority=priority;this.applyWidths();this.syncColumnControls();this.stateChanged()}});const FIT_STATE_COLUMN=gridStateColumn,FIT_STATE_COLUMNS=gridStateColumns;gridStateColumn=column=>Object.assign(FIT_STATE_COLUMN(column),{width:column.sized||column.fixed?column.width:column.declared},column.sized&&{sized:true},column.priority!==undefined&&{priority:column.priority});gridStateColumns=(grid,input)=>{const result=FIT_STATE_COLUMNS(grid,input),sources=new Map(input.map(column=>[column?.id,column]));for(const saved of result){const{sized=sources.get(saved.id)?.flex===false||undefined,priority}=sources.get(saved.id)||saved;if(sized!==undefined&&typeof sized!=="boolean"||priority!==undefined&&!gridPriority(priority))throw new Error("CanopyX: invalid saved column.");Object.assign(saved,sized&&{sized},priority!==undefined&&{priority})}
889
950
  return result};function validateGridHighlights(view){if(view.highlightRules===undefined)return;if(!Array.isArray(view.highlightRules)||view.highlightRules.length>64)throw new Error("CanopyX: at most 64 highlight rules.");const columns=new Map(view.columns.map(column=>[column.id,column])),budget={predicates:0};for(const rule of view.highlightRules){if(!rule||
890
951
  rule.target!==undefined&&!["row","cell"].includes(rule.target)||rule.tone===undefined&&rule.className===undefined)
891
- throw new Error("CanopyX: invalid highlight rule.");const{column,operator,values}=rule;gridPredicate({column,operator,values},columns,budget);gridDecoration(rule.tone,rule.className)}}
952
+ throw new Error("CanopyX: invalid highlight rule.");const{column,operator,values}=rule;if(!Object.hasOwn(GRID_FILTER_LABELS,operator))throw new Error("CanopyX: highlight rules use built-in operators.");gridPredicate({column,operator,values},columns,budget);gridDecoration(rule.tone,rule.className)}}
892
953
  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)}
893
- 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;
894
- 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"||
954
+ 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",toneVariable(name,false,"var(--hfx-color-text,light-dark(#16181c,#f2f3f5))"));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;
955
+ 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}
956
+ if(rule){slot.cell.title=rule.label;slot.title=rule.label}
957
+ 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"||
895
958
  ["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()}
896
959
  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||
897
960
  options.limit!==undefined&&(!Number.isInteger(options.limit)||options.limit<1||options.limit>16)))invalid();if((options.minimum===undefined)!==(options.scaleMaximum===undefined)||options.minimum!==undefined&&
@@ -908,14 +971,8 @@ const value=raw.trim();try{const url=new URL(value,document.baseURI);if(["http:"
908
971
  }catch(_){/* Invalid destinations retain plain text. */ }
909
972
  return null}
910
973
  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}}
911
- 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)}
912
- 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));
913
- }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)}
914
- 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));
915
- const preview=add(text.length>budget?text.slice(0,budget).replace(/[\uD800-\uDBFF]$/,"")+" …":text,"cx-wrapped-text"+(options.mono?" p-mono":""));
916
- 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);}
917
- }else add(text);if(object)for(const badge of cell.badges||[])element.appendChild(badgeElement(badge));return true}}
918
- 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})}
974
+ 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)}}
975
+ 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})}
919
976
  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}
920
977
  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}
921
978
  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}
@@ -957,31 +1014,31 @@ throw new Error("CanopyX: invalid paged view state.");if(this.paged){parsed.pagi
957
1014
  return parsed},async setState(input){const state=this.readGridState(input);const rules=state.formatRules!==undefined?JSON.parse(JSON.stringify(state.formatRules)):this.formatEdited?this.view.formatRules||[]:undefined;const before=this.queryEpoch;if(rules!==undefined)await this.validateFormatRules(rules);if(this.destroyed||before!==this.queryEpoch)throw new DOMException("Grid state was superseded.","AbortError");state.formatRules=rules;clearTimeout(this.searchTimer);this.searchTimer=null;const pending=this.setQuery({...state.query,offset:state.paging?state.paging.offset:0},state.paging),epoch=this.queryEpoch;this.restoringEpoch=epoch;try{await pending;if(this.destroyed||epoch!==this.queryEpoch)throw new DOMException("Grid state was superseded.","AbortError");await this.applyStatePresentation(state);return this.getQuery()}finally{if(this.restoringEpoch===epoch){this.restoringEpoch=null;this.stateChanged()}}},applyStatePresentation(state){if(this.cancelResize)this.cancelResize();const current=new Map(this.columns.map(column=>[column.id,column]));this.columns=state.columns.map(saved=>{const column=current.get(saved.id);return Object.assign(column,{sized:false,priority:column.basePriority},saved)});this.setTimeZone(state.timeZone);if(this.view.rowIdentity!=="ordinal")this.setSelection(state.selection);this.buildHeader();this.syncColumnControls();this.setLogicalTop(state.scrollTop);this.render();if(state.formatRules!==undefined||this.formatEdited)return this.setFormatRules(state.formatRules||this.view.formatRules||[])},setColumnOrder(ids){if(!Array.isArray(ids)||ids.length!==this.columns.length||new Set(ids).size!==ids.length||
958
1015
  ids.some(id=>!this.columns.some(column=>column.id===id)))throw new Error("CanopyX: name each column once.");if(this.cancelResize)this.cancelResize();const columns=new Map(this.columns.map(column=>[column.id,column]));this.columns=ids.map(id=>columns.get(id));this.columns.forEach((column,index,all)=>{if(column.pin==="left"&&all.slice(0,index).some(item=>item.pin!=="left")||column.pin==="right"&&all.slice(index+1).some(item=>item.pin!=="right"))column.pin="none"});this.buildHeader();this.syncColumnControls();this.scheduleRender();this.stateChanged()},viewName(name){if(typeof name!=="string"||!name.trim()||name.trim().length>100)throw new Error("CanopyX: view names need 1 to 100 nonblank characters.");return name.trim()},getSavedViews(){return[...this.savedViews.keys()]},saveView(name){name=this.viewName(name);if(!this.getQuery())throw new Error("CanopyX: saving needs an accepted query.");if(!this.savedViews.has(name)&&this.savedViews.size>=20)throw new Error("CanopyX: maximum 20 saved views.");this.savedViews.set(name,this.getState());this.writeStoredState(this.getState());this.syncSavedViews();if(this.savedChoice)this.savedChoice.value=name},applySavedView(name){const state=this.savedViews.get(this.viewName(name));if(!state)throw new Error("CanopyX: the saved view does not exist.");return this.setState(state)},removeSavedView(name){this.savedViews.delete(this.viewName(name));this.writeStoredState(this.getState());this.syncSavedViews()},resetView(){return this.setState(this.defaultState)},readStoredState(){if(!this.storageKey)return null;try{return JSON.parse(global.sessionStorage.getItem(this.storageKey))}catch(_){return null}},writeStoredState(state){if(!this.storageKey||this.destroyed)return;try{global.sessionStorage.setItem(this.storageKey,JSON.stringify({current:state,views:[...this.savedViews].map(([name,value])=>({name,state:value}))}))}
959
1016
  catch(_){/* A disabled or full storage leaves the current session usable. */ }
960
- }});const GRID_HISTORY_IMPL={},GRID_HISTORY=definePart(DataGrid,"history","history presenters",()=>({GRID_HISTORY_IMPL,h,setText,fill,gridSeries,gridPresenterTone,toneColors,toneOf,GRID_TONE_RANK}));const GRID_HISTORY_INIT=DataGrid.prototype.initializeState;DataGrid.prototype.loadHistory=function(){return this.historyLoad||=loadPart(GRID_HISTORY).then(()=>{this.version++;this.scheduleRender()},error=>this.emit("error",{error}))};DataGrid.prototype.initializeState=function(){const ready=GRID_HISTORY_INIT.call(this);return this.columns.some(column=>GRID_HISTORY_KINDS.includes(column.presenter?.kind))?Promise.all([ready,this.loadHistory()]).then(([result])=>result):ready};const GRID_CALENDAR=definePart(DataGrid,"calendar","calendar",()=>({DataGrid,h,setText,fill,plural,gridButton,gridIcon,gridFreeze,cellText,cellValue,isCellObject,gridQuery,gridQueryRows,gridResultShape,gridPresenterTone,validateGridRows,validateGridPage,validateGridCursorPage,validStructuralCount,checkDocument,numberFormat,loadPart,HostCellContext,disposeHostSlot,PROTOCOL}));definePart(DataGrid,"timeline","resource timeline",()=>({DataGrid,TreeGrid,h,setText,fill,numberFormat}));definePart(DataGrid,"calendar-recurrence","calendar recurrence",()=>({DataGrid}));definePart(DataGrid,"calendar-edit","calendar editing",()=>({DataGrid,h,setText,fill,cellValue,GRID_DRAG}));definePart(DataGrid,"calendar-ics","iCalendar",()=>({DataGrid,h,fill,cellText}));const GRID_CALENDAR_API=["getCalendar","setCalendarView","setCalendarDate","setCalendarZoom","calendarStep","calendarToday","getCalendarEvents","exportCalendar","openCalendarEvent","clearCalendarSelection","setCalendarSource"];for(const name of GRID_CALENDAR_API)DataGrid.prototype[name]=function(...args){return this.loadCalendar().then(()=>this[name](...args))};DataGrid.prototype.loadCalendar=function(){return this.calLoad||=loadPart(GRID_CALENDAR).then(()=>this.destroyed||this.calParts()).then(()=>this.destroyed||this.startCalendar()).catch(error=>{this.calLoad=null;this.emit("error",{error});throw error})};const GRID_CALENDAR_INIT=DataGrid.prototype.initializeState;DataGrid.prototype.initializeState=function(){const start=()=>GRID_CALENDAR_INIT.call(this);return this.view.calendar?this.loadCalendar().then(start,start):start()};const CAL_PRESETS={basic:{toolbar:false,details:"popover",views:["month","week","day","agenda"]},standard:{toolbar:["search","filters","export"],details:"popover",print:true,views:["month","week","day","days","agenda","year"]},scheduler:{toolbar:["search","filters","views","export"],details:"drawer",print:true,editable:true,create:true,views:["month","week","day","agenda"]}};const CAL_FIELDS=["allDay","description","tone","resource","recurrence","exceptions","source"];const CAL_TITLES={allDay:"All day",description:"Description",tone:"Tone",resource:"Resource",recurrence:"Repeats",exceptions:"Exceptions",source:"Source"};const CAL_OWN=new Set(["events","preset","id","label","views","view","date","timeZone","firstDay","toolbar","details","editable","create","drop","resources","timeline","live","facets","drawer","export","print","sources","calendar","links"]);const calPad=(value,size=2)=>String(value).padStart(size,"0");function calInstantText(value,field,allDay){if(value instanceof Date&&Number.isFinite(value.getTime()))
1017
+ }});const GRID_HISTORY_IMPL={},GRID_HISTORY=definePart(DataGrid,"history","history presenters",()=>({GRID_HISTORY_IMPL,h,setText,fill,gridSeries,gridPresenterTone,toneColors,toneOf,GRID_TONE_RANK}));const GRID_HISTORY_INIT=DataGrid.prototype.initializeState;DataGrid.prototype.loadHistory=function(){return this.historyLoad||=loadPart(GRID_HISTORY).then(()=>{this.version++;this.scheduleRender()},error=>this.emit("error",{error}))};DataGrid.prototype.initializeState=function(){const ready=GRID_HISTORY_INIT.call(this);return this.columns.some(column=>GRID_HISTORY_KINDS.includes(column.presenter?.kind))?Promise.all([ready,this.loadHistory()]).then(([result])=>result):ready};const GRID_CALENDAR=definePart(DataGrid,"calendar","calendar",()=>({DataGrid,h,setText,fill,plural,gridButton,gridIcon,gridFreeze,cellText,cellValue,isCellObject,gridQuery,gridQueryRows,gridResultShape,gridPresenterTone,validateGridRows,validateGridPage,validateGridCursorPage,validStructuralCount,checkDocument,numberFormat,loadPart,HostCellContext,disposeHostSlot,PROTOCOL,toneVariable}));definePart(DataGrid,"timeline","resource timeline",()=>({DataGrid,TreeGrid,h,setText,fill,numberFormat,toneVariable}));definePart(DataGrid,"calendar-recurrence","calendar recurrence",()=>({DataGrid}));definePart(DataGrid,"calendar-edit","calendar editing",()=>({DataGrid,h,setText,fill,cellValue,GRID_DRAG}));definePart(DataGrid,"calendar-ics","iCalendar",()=>({DataGrid,h,fill,cellText}));const GRID_CALENDAR_API=["getCalendar","setCalendarView","setCalendarDate","setCalendarZoom","calendarStep","calendarToday","getCalendarEvents","exportCalendar","openCalendarEvent","editCalendarOccurrence","clearCalendarSelection","setCalendarSource"];for(const name of GRID_CALENDAR_API)DataGrid.prototype[name]=function(...args){return this.loadCalendar().then(()=>this[name](...args))};DataGrid.prototype.loadCalendar=function(){return this.calLoad||=loadPart(GRID_CALENDAR).then(()=>this.destroyed||this.calParts()).then(()=>this.destroyed||this.startCalendar()).catch(error=>{this.calLoad=null;this.emit("error",{error});throw error})};const GRID_CALENDAR_INIT=DataGrid.prototype.initializeState;DataGrid.prototype.initializeState=function(){const start=()=>GRID_CALENDAR_INIT.call(this);return this.view.calendar?this.loadCalendar().then(start,start):start()};const CAL_PRESETS={basic:{toolbar:false,details:"popover",views:["month","week","day","agenda"]},standard:{toolbar:["search","filters","export"],details:"popover",print:true,views:["month","week","day","days","agenda","year"]},scheduler:{toolbar:["search","filters","views","export"],details:"drawer",print:true,editable:true,create:true,views:["month","week","day","agenda"]}};const CAL_FIELDS=["allDay","description","tone","resource","resourceIds","recurrence","exceptions","series","recurrenceId","source"];const CAL_TITLES={allDay:"All day",description:"Description",tone:"Tone",resource:"Resource",resourceIds:"Resources",series:"Series",recurrenceId:"Original start",recurrence:"Repeats",exceptions:"Exceptions",source:"Source"};const CAL_OWN=new Set(["events","preset","id","label","views","view","date","timeZone","firstDay","toolbar","details","editable","create","drop","resources","timeline","live","facets","drawer","export","print","sources","calendar","links"]);const calPad=(value,size=2)=>String(value).padStart(size,"0");function calInstantText(value,field,allDay){if(value instanceof Date&&Number.isFinite(value.getTime()))
961
1018
  return allDay?calPad(value.getFullYear(),4)+ "-"+calPad(value.getMonth()+ 1)+ "-"+calPad(value.getDate())+ "T00:00:00Z":value.toISOString().replace(".000Z","Z");if(typeof value==="string"&&/^\d{4}-\d\d-\d\d$/.test(value)) return value + "T00:00:00Z";
962
1019
  if(typeof value==="string"&&/^\d{4}-\d\d-\d\dT\d\d:\d\d(:\d\d(\.\d+)?)?(Z|[+-]\d\d:\d\d)$/.test(value)) return allDay ? value.slice(0, 10) + "T00:00:00Z" : value;
963
1020
  const parsed=typeof value==="string"&&/^\d{4}-\d\d-\d\dT\d\d:\d\d/.test(value) ? new Date(value) : null;
964
1021
  if(parsed&&Number.isFinite(parsed.getTime()))return calInstantText(parsed,field,allDay);throw new Error("CanopyX: a calendar event's "+field+" is a Date or an ISO date or date and time.")}
965
1022
  function createCalendar(host,options={}){const preset=CAL_PRESETS[options.preset??"basic"];if(!preset)throw new Error("CanopyX: calendar presets are basic, standard and scheduler.");const events=options.events??[];if(!Array.isArray(events)||events.length>100000)throw new Error("CanopyX: calendar events are an array of at most 100,000 events.");const hooks={},own={};for(const[name,value]of Object.entries(options.calendar||{}))(typeof value==="function"?hooks:own)[name]=value;const pick=name=>own[name]!==undefined?own[name]:options[name]!==undefined?options[name]:preset[name];const editable=!!pick("editable"),create=pick("create"),drop=!!pick("drop"),used=new Set(),ids=new Set();const rows=events.map((event,index)=>{if(!event||typeof event!=="object"||typeof event.title!=="string")throw new Error("CanopyX: calendar event " +(index+1)+ " needs a title.");const id=event.id===undefined?"e" +(index+1):String(event.id);if(ids.has(id))throw new Error("CanopyX: calendar event ids are unique; '"+id+"' repeats.");ids.add(id);const allDay=event.allDay??(typeof event.start==="string"&&event.start.length===10);const cells={title:event.title,start:calInstantText(event.start,"start",allDay)};if(event.end!=null)cells.end=calInstantText(event.end,"end",allDay);if(allDay){cells.allDay=true;used.add("allDay")}
966
- for(const field of CAL_FIELDS)if(field!=="allDay"&&event[field]!=null){cells[field]=String(event[field]);used.add(field)}
967
- 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})}
1023
+ for(const field of CAL_FIELDS)if(field!=="allDay"&&event[field]!=null){cells[field]=field==="resourceIds"?JSON.stringify(event[field]):field==="recurrenceId"?calInstantText(event[field],field,false):String(event[field]);used.add(field)}
1024
+ return{id,cells}});if(options.resources)used.add("resource");if(used.has("recurrence"))for(const field of["series","recurrenceId","exceptions"])used.add(field);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:field==="recurrenceId"?"datetime":"text",hidden:field!=="description",editable:writable&&(field==="resource"||field==="resourceIds"||field==="series"||field==="recurrenceId"||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})}
968
1025
  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)}
969
1026
  return roots}
970
- 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")
1027
+ 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,overlayTheme,watchOverlayTheme}));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")
971
1028
  throw new Error("CanopyX: invalid saved facet panel state.");if(this.view.facets||this.opts.facets)state.facets={open:facets.open}}
972
1029
  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}
973
- 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())
974
- .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")||
1030
+ 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,toneVariable,numberFormat,gridButton,gridOption,gridInputLabel,gridIcon,gridDecorateButton,GRID_REPORTING,loadPart,definePart,announceMenu,boundedPattern,wildcardMatch,svgIcon,overlayTheme}));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_OPTIONS_PART=definePart(DataGrid,"grid-options","grid footer and query extensions",()=>({DataGrid,GRID_OPTIONS,GRID_OPTION_GRIDS,h,setText,fill,gridQuery,gridQueryRows,gridCompare,gridKeyCompare,gridSortScalar,gridMatches,gridMatchesGroup,gridResultShape,GRID_REPORTING,gridScalar,gridFreeze,gridOperationActive,numberText,isCellObject,cellValue,requireIdentifier,validStructuralCount,PROTOCOL}));const OPTIONS_REQUEST=DataGrid.prototype.requestPage;DataGrid.prototype.requestPage=async function(query,signal){if(!gridOptionsUsed(this.view,this.plugins))return OPTIONS_REQUEST.call(this,query,signal);await loadPart(GRID_OPTIONS_PART);gridOperationActive(this,signal);GRID_OPTIONS.attach(this);const page=await OPTIONS_REQUEST.call(this,query,signal);return GRID_OPTIONS.page(this,query,signal,page)};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())
1031
+ .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")||
975
1032
  !!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)=>
976
1033
  (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}
977
1034
  class MatrixHost{}
978
- const MATRIX_IMPL={},activeMatrices=new WeakMap();const MATRIX_PART=definePart(MatrixHost,"matrix","matrix view",()=>({MATRIX_IMPL,h,setText,fill,plural,foldText,numberFormat,gridFreeze,toneOf,applyTone,toneColors,AxisWindow,PROTOCOL}));const MATRIX_METHODS=["sort","group","filter","setSearch","setAttentionOnly","getState","setState","getVisible","focusCell","update"];function createMatrix(host,options){if(!host||!options||!options.view||typeof options.view!=="object")throw new Error("CanopyX: createMatrix needs a host element and a matrix document.");const existing=activeMatrices.get(host);if(existing)return existing;const addedClasses=["cx-host","cx-matrix-host"].filter(name=>!host.classList.contains(name)),hadClass=host.hasAttribute("class");const previousError=host.getAttribute("data-cx-error");let impl=null,destroyed=false,notice=null,errorText=null;const cancelled=()=>new DOMException("Matrix was destroyed.","AbortError");const ready=loadPart(MATRIX_PART).then(()=>{if(destroyed)throw cancelled();impl=MATRIX_IMPL.create(host,options);return impl.ready});const api={element:host};Object.defineProperty(api,"view",{enumerable:true,get:()=>impl?impl.document():options.view});for(const name of MATRIX_METHODS)api[name]=(...args)=>{const invoke=()=>{if(destroyed)throw cancelled();return impl[name](...args)};if(destroyed)throw cancelled();return impl?invoke():ready.then(invoke)};api.ready=ready.then(()=>{if(destroyed)throw cancelled();return api});api.ready.catch(()=>{});api.destroy=()=>{if(destroyed)return;destroyed=true;impl?.destroy();if(activeMatrices.get(host)===api)activeMatrices.delete(host);if(host.canopyx===api)delete host.canopyx;host.removeAttribute("data-canopyx-mounted");notice?.remove();if(errorText!==null&&host.getAttribute("data-cx-error")===errorText){if(previousError===null)host.removeAttribute("data-cx-error");else host.setAttribute("data-cx-error",previousError)}
979
- for(const name of addedClasses)host.classList.remove(name);if(!hadClass&&!host.classList.length)host.removeAttribute("class")};ready.catch(error=>{if(destroyed)return;notice=h("div","cx-mount-error");notice.setAttribute("role","alert");setText(notice,error&&error.message?error.message:String(error));host.appendChild(notice);errorText=notice.textContent;host.setAttribute("data-cx-error",errorText);host.dispatchEvent(new CustomEvent("canopyx:error",{detail:{error},bubbles:true}))});Object.freeze(api);activeMatrices.set(host,api);host.classList.add("cx-host","cx-matrix-host");host.setAttribute("data-canopyx-mounted","true");host.canopyx=api;return api}
1035
+ const MATRIX_IMPL={},activeMatrices=new WeakMap();const MATRIX_PART=definePart(MatrixHost,"matrix","matrix view",()=>({MATRIX_IMPL,h,setText,fill,plural,foldText,numberFormat,gridFreeze,toneOf,applyTone,toneColors,AxisWindow,PROTOCOL}));const MATRIX_METHODS=["sort","group","filter","setSearch","setAttentionOnly","getState","setState","getVisible","focusCell","update"];function createMatrix(host,options){if(!host||!options||!options.view||typeof options.view!=="object")throw new Error("CanopyX: createMatrix needs a host element and a matrix document.");const existing=activeMatrices.get(host);if(existing)return existing;const addedClasses=["cx-host","cx-matrix-host"].filter(name=>!host.classList.contains(name)),hadClass=host.hasAttribute("class");const previousError=host.getAttribute("data-cx-error");let stopTheme;let impl=null,destroyed=false,notice=null,errorText=null;const cancelled=()=>new DOMException("Matrix was destroyed.","AbortError");const ready=loadPart(MATRIX_PART).then(()=>{if(destroyed)throw cancelled();impl=MATRIX_IMPL.create(host,options);return impl.ready});const api={element:host};Object.defineProperty(api,"view",{enumerable:true,get:()=>impl?impl.document():options.view});for(const name of MATRIX_METHODS)api[name]=(...args)=>{const invoke=()=>{if(destroyed)throw cancelled();return impl[name](...args)};if(destroyed)throw cancelled();return impl?invoke():ready.then(invoke)};api.ready=ready.then(()=>{if(destroyed)throw cancelled();return api});api.ready.catch(()=>{});api.destroy=()=>{if(destroyed)return;destroyed=true;impl?.destroy();stopTheme?.();if(activeMatrices.get(host)===api)activeMatrices.delete(host);if(host.canopyx===api)delete host.canopyx;host.removeAttribute("data-canopyx-mounted");notice?.remove();if(errorText!==null&&host.getAttribute("data-cx-error")===errorText){if(previousError===null)host.removeAttribute("data-cx-error");else host.setAttribute("data-cx-error",previousError)}
1036
+ for(const name of addedClasses)host.classList.remove(name);if(!hadClass&&!host.classList.length)host.removeAttribute("class")};ready.catch(error=>{if(destroyed)return;notice=h("div","cx-mount-error");notice.setAttribute("role","alert");setText(notice,error&&error.message?error.message:String(error));host.appendChild(notice);errorText=notice.textContent;host.setAttribute("data-cx-error",errorText);host.dispatchEvent(new CustomEvent("canopyx:error",{detail:{error},bubbles:true}))});Object.freeze(api);activeMatrices.set(host,api);host.classList.add("cx-host","cx-matrix-host");stopTheme=watchTheme(host);host.setAttribute("data-canopyx-mounted","true");host.canopyx=api;return api}
980
1037
  const MATRIX_API={createMatrix};class ChangesHost{}
981
- const CHANGES_IMPL={},activeChangeViews=new WeakMap();const CHANGES_PART=definePart(ChangesHost,"changes","change views",()=>({CHANGES_IMPL,h,setText,fill,plural,numberFormat,gridFreeze,toneOf,applyTone,svgIcon,PROTOCOL}));const CHANGE_VIEW_METHODS={diff:["getLayout","setLayout","next","previous","expandAll","copy","getHunks","update"],changes:["getState","setState","toggle","focusItem","update"],propagation:["update"]};function changeViewFactory(kind,name){return function(host,options){if(!host||!options||!options.view||typeof options.view!=="object")throw new Error("CanopyX: "+name+" needs a host element and a "+kind+" document.");const existing=activeChangeViews.get(host);if(existing)return existing;const addedClasses=["cx-host","cx-change-host"].filter(className=>!host.classList.contains(className)),hadClass=host.hasAttribute("class"),previousError=host.getAttribute("data-cx-error");let impl=null,destroyed=false,notice=null,errorText=null,failure=null,loaded=false,currentView=options.view;const cancelled=()=>new DOMException("Change view was destroyed.","AbortError");const clearError=()=>{notice?.remove();notice=null;if(errorText!==null&&host.getAttribute("data-cx-error")===errorText){if(previousError===null)host.removeAttribute("data-cx-error");else host.setAttribute("data-cx-error",previousError)}
1038
+ const CHANGES_IMPL={},activeChangeViews=new WeakMap();const CHANGES_PART=definePart(ChangesHost,"changes","change views",()=>({CHANGES_IMPL,h,setText,fill,plural,numberFormat,gridFreeze,toneOf,applyTone,svgIcon,PROTOCOL}));const CHANGE_VIEW_METHODS={diff:["getLayout","setLayout","next","previous","expandAll","copy","getHunks","update"],changes:["getState","setState","toggle","focusItem","update"],propagation:["update"]};function changeViewFactory(kind,name){return function(host,options){if(!host||!options||!options.view||typeof options.view!=="object")throw new Error("CanopyX: "+name+" needs a host element and a "+kind+" document.");const existing=activeChangeViews.get(host);if(existing)return existing;const addedClasses=["cx-host","cx-change-host"].filter(className=>!host.classList.contains(className)),hadClass=host.hasAttribute("class"),previousError=host.getAttribute("data-cx-error");let stopTheme;let impl=null,destroyed=false,notice=null,errorText=null,failure=null,loaded=false,currentView=options.view;const cancelled=()=>new DOMException("Change view was destroyed.","AbortError");const clearError=()=>{notice?.remove();notice=null;if(errorText!==null&&host.getAttribute("data-cx-error")===errorText){if(previousError===null)host.removeAttribute("data-cx-error");else host.setAttribute("data-cx-error",previousError)}
982
1039
  errorText=null};const showError=error=>{if(destroyed)return;impl?.destroy();impl=null;failure=error;clearError();notice=h("div","cx-mount-error");notice.setAttribute("role","alert");setText(notice,error&&error.message?error.message:String(error));host.appendChild(notice);errorText=notice.textContent;host.setAttribute("data-cx-error",errorText);host.dispatchEvent(new CustomEvent("canopyx:error",{detail:{error},bubbles:true}))};const mount=view=>{clearError();impl=CHANGES_IMPL[kind](host,{...options,view});failure=null;return impl.ready};const ready=loadPart(CHANGES_PART).then(()=>{if(destroyed)throw cancelled();loaded=true;return mount(currentView)});const api={element:host};Object.defineProperty(api,"view",{enumerable:true,get:()=>impl?impl.document():currentView});for(const method of CHANGE_VIEW_METHODS[kind])api[method]=(...args)=>{const invoke=()=>{if(destroyed)throw cancelled();if(method==="update"){currentView=args[0];try{return impl?impl.update(...args):mount(currentView)}
983
1040
  catch(error){showError(error);throw error}}
984
- if(failure)throw failure;return impl[method](...args)};if(destroyed)throw cancelled();return loaded?invoke():ready.then(invoke)};api.ready=ready.then(()=>{if(destroyed)throw cancelled();return api});api.ready.catch(()=>{});api.destroy=()=>{if(destroyed)return;destroyed=true;impl?.destroy();if(activeChangeViews.get(host)===api)activeChangeViews.delete(host);if(host.canopyx===api)delete host.canopyx;host.removeAttribute("data-canopyx-mounted");clearError();for(const className of addedClasses)host.classList.remove(className);if(!hadClass&&!host.classList.length)host.removeAttribute("class")};ready.catch(showError);Object.freeze(api);activeChangeViews.set(host,api);host.classList.add("cx-host","cx-change-host");host.setAttribute("data-canopyx-mounted","true");host.canopyx=api;return api}}
1041
+ if(failure)throw failure;return impl[method](...args)};if(destroyed)throw cancelled();return loaded?invoke():ready.then(invoke)};api.ready=ready.then(()=>{if(destroyed)throw cancelled();return api});api.ready.catch(()=>{});api.destroy=()=>{if(destroyed)return;destroyed=true;impl?.destroy();stopTheme?.();if(activeChangeViews.get(host)===api)activeChangeViews.delete(host);if(host.canopyx===api)delete host.canopyx;host.removeAttribute("data-canopyx-mounted");clearError();for(const className of addedClasses)host.classList.remove(className);if(!hadClass&&!host.classList.length)host.removeAttribute("class")};ready.catch(showError);Object.freeze(api);activeChangeViews.set(host,api);host.classList.add("cx-host","cx-change-host");host.setAttribute("data-canopyx-mounted","true");host.canopyx=api;stopTheme=watchTheme(host);return api}}
985
1042
  const CHANGES_API={createDiff:changeViewFactory("diff","createDiff"),createChangeList:changeViewFactory("changes","createChangeList"),createPropagation:changeViewFactory("propagation","createPropagation")};const CHANGE_VIEW_TYPES={diff:CHANGES_API.createDiff,changes:CHANGES_API.createChangeList,propagation:CHANGES_API.createPropagation};DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{gridCellRangeSelected:"{rows} rows × {columns} columns selected",gridCellRangesSelected:"{ranges} ranges selected, {cells} cells",gridCellRangeCleared:"Cell selection cleared",gridCopyCells:"Copy cells",gridCopyCellsWithHeaders:"Copy cells with headers",gridPasteCells:"Paste",gridSelectAllCells:"Select all cells",gridCellsCopied:"Copied {rows} rows × {columns} columns",gridCellsPasted:"Pasted {count} cells",gridPasteRefused:"{count} cells were not pasted",gridPasteReadOnly:"This cell cannot be changed.",gridPasteType:"“{value}” is not a valid value for {column}.",gridPasteReport:"Paste report",gridPasteCell:"Row {row}, {column}: {reason}",gridFillHandle:"Drag to fill the cells below",gridCellsFilled:"Filled {count} cells",gridCellMenu:"Cell actions",gridClearCellRanges:"Clear cell selection"}));const GRID_PART_CONTEXT=()=>({DataGrid,h,setText,fill,columnWidth,foldText,gridButton,gridIcon,gridDecorateButton,cellText,cellValue,isCellObject,numberFormat,gridFreeze,gridMomentFromParts,requireIdentifier,loadGridFilterEditor,CELL_CONTROLS,reachable,gridExportField});const GRID_COLUMN_GROUPS=definePart(DataGrid,"column-groups","column groups",GRID_PART_CONTEXT);const GRID_CELL_RANGE=definePart(DataGrid,"cell-range","cell ranges",GRID_PART_CONTEXT);const GRID_PART_API=[["column-groups","getColumnGroups","setColumnGroupVisible"],["cell-range","getCellRanges","setCellRanges","clearCellRanges","selectAllCells","copyCellRanges","getCellRangeText","pasteCells"]];const gridPartLoader=(part,start)=>function(){return(this.partLoads||={})[start]||=loadPart(part).then(()=>this.destroyed||this["start"+start]()).catch(error=>{this.partLoads[start]=null;throw error})};DataGrid.prototype.loadColumnGroups=gridPartLoader(GRID_COLUMN_GROUPS,"ColumnGroups");DataGrid.prototype.loadCellRanges=gridPartLoader(GRID_CELL_RANGE,"CellRanges");for(const[part,read,...actions]of GRID_PART_API){const load=part==="cell-range"?"loadCellRanges":"loadColumnGroups";DataGrid.prototype[read]=()=>[];for(const name of actions){const stub=DataGrid.prototype[name]=function(...args){return this[load]().then(()=>{if(DataGrid.prototype[name]===stub)throw new Error("CanopyX: the "+part+" part did not install "+name+".");return this[name](...args)})}}}
986
1043
  const GRID_PARTS_INIT=DataGrid.prototype.initializeState;DataGrid.prototype.initializeState=function(){const ready=GRID_PARTS_INIT.call(this),range=this.opts.rangeSelection??this.view.rangeSelection;const parts=[this.view.columnGroups?.length&&this.loadColumnGroups(),range&&range.enabled!==false&&this.loadCellRanges()].filter(Boolean);return parts.length?Promise.all([ready,...parts.map(part=>part.catch(error=>this.emit("error",{error})))]).then(([result])=>result):ready};function gridButton(text,run){const button=h("button","cx-button");button.type="button";setText(button,text);button.onclick=event=>{button.focus({preventScroll:true});run(event)};return button}
987
1044
  let keyboardInput=false;if(typeof document!=="undefined"){document.addEventListener("keydown",()=>{keyboardInput=true},true);document.addEventListener("pointerdown",()=>{keyboardInput=false},true)}
@@ -991,7 +1048,7 @@ const MENU_EVENT="canopyx:closemenus",announceMenu=source=>document.dispatchEven
991
1048
  catch(failure){setText(error,failure.message)}};panel.appendChild(gridButton(this.labels.gridApply,()=>run(()=>this.applySavedView(choice.value))));panel.appendChild(gridButton(this.labels.gridSaveView,()=>run(()=>this.saveView(name.value))));panel.appendChild(gridButton(this.labels.gridRemoveView,()=>run(()=>this.removeSavedView(choice.value))));panel.appendChild(error);this.syncSavedViews()},syncSavedViews(){if(!this.savedChoice)return;const selected=this.savedChoice.value;this.savedChoice.textContent="";this.savedChoice.appendChild(gridOption("",this.labels.gridChooseView));this.getSavedViews().forEach(name=>this.savedChoice.appendChild(gridOption(name,name)));if(this.savedViews.has(selected))this.savedChoice.value=selected},placeMenus(phone){if(this.overflow)for(const selector of[".cx-grid-views",".cx-grid-export"]){const item=this.toolbar.querySelector(selector);if(!item)continue;item.open=false;if(phone)this.overflow.panel.appendChild(item);else this.toolbar.insertBefore(item,selector===".cx-grid-views"?this.slots?.afterViews||this.spacer:this.overflow.details)}}};function gridCountLabel(element,label,values,marks=/(\{count\}|\{selected\})/){
992
1049
  element.replaceChildren(...label.split(marks).map((part,index)=>{if(index%2===0)return document.createTextNode(fill(part,values));const bold=h("b");setText(bold,fill(part,values));return bold}))}
993
1050
  DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{gridResultCount:"{count} of {total} rows",gridClearQuery:"Clear search and filters",gridRemoveSearch:"Clear search: {search}",gridGroupedFilters:"Grouped filters ({count} conditions)",gridRemoveGroup:"Clear grouped filters",gridRemoveCondition:"Remove condition: {condition}"}));Object.assign(DataGrid.prototype,{buildGridSearch(){const search=h("div","cx-search"),input=this.searchInput=h("input","cx-search-input"),signal=this.lifetime.signal;input.type="search";input.placeholder=this.labels.searchPlaceholder;input.setAttribute("aria-label",this.labels.searchPlaceholder);const update=()=>{clearTimeout(this.searchTimer);this.searchTimer=null;if(this.destroyed||this.searchComposing)return;if(this.queryForChange().search===input.value)return;this.setQuery(gridQueryStart(this.queryForChange(),{search:input.value})).catch(()=>{})};GRID_REPORTING.search?.(this,update);const schedule=()=>{clearTimeout(this.searchTimer);this.searchTimer=null;if(this.searchComposing)return;if(this.searchDelayMs===0)update();else this.searchTimer=setTimeout(update,this.searchDelayMs)};input.addEventListener("compositionstart",()=>{this.searchComposing=true;clearTimeout(this.searchTimer);this.searchTimer=null},{signal});input.addEventListener("compositionend",()=>{this.searchComposing=false;schedule()},{signal});input.addEventListener("input",event=>{if(!event.isComposing)schedule()},{signal});input.addEventListener("keydown",event=>{if(event.key==="Enter"&&!this.searchComposing&&!event.isComposing&&event.keyCode!==229){event.preventDefault();update()}},{signal});const shortcut=h("kbd");setText(shortcut,"/");search.append(gridIcon("search"),input,shortcut);this.toolbar.appendChild(search);this.host.addEventListener("keydown",event=>{if(event.key==="/"&&!event.ctrlKey&&!event.metaKey&&!event.altKey&&!event.target.closest("input,textarea,select,[contenteditable]")){event.preventDefault();input.focus()}},{signal})},buildQuerySummary(){this.querySummary=h("div","cx-grid-query-summary");this.resultCount=h("span","cx-grid-result-count");this.resultCount.setAttribute("role","status");this.queryChips=h("div","cx-grid-query-chips");this.querySummary.append(this.resultCount,this.queryChips);this.querySummary.hidden=true;if(this.tools.count===false)this.resultCount.remove()},syncQuerySummary(){if(!this.acceptedQuery||!this.querySummary)return;const query=this.acceptedQuery,active=document.activeElement,focused=this.queryChips.contains(active);const key=focused&&active.getAttribute("data-cx-condition");const numbers=numberFormat(this.lang);this.querySummary.hidden=!query.search&&!gridFilterCount(query);this.syncGridChrome();gridCountLabel(this.resultCount,this.snapshot.matched===null?this.labels.gridUnknownCount:this.snapshot.total===null?
994
- this.labels.gridMatchedCount:this.view.noun?this.labels.gridResultNoun:this.labels.gridResultCount,{count:numbers.format(this.snapshot.matched),total:numbers.format(this.snapshot.total),noun:this.view.noun||this.labels.gridRows});this.queryChips.textContent="";const apply=patch=>{this.setQuery(gridQueryStart(this.queryForChange(true),patch)).catch(()=>{})};const chip=(text,label,id,run)=>{const button=gridButton("",()=>{button.focus({preventScroll:true});run()});button.classList.add("cx-grid-chip");filterChipContent(button,text);button.title=text;button.setAttribute("aria-label",label);button.setAttribute("data-cx-condition",id);this.queryChips.appendChild(button)};if(query.search)chip(query.search,fill(this.labels.gridRemoveSearch,{search:query.search}),"search",()=>{if(this.searchInput)this.searchInput.value="";apply({search:""})});query.filters.forEach((filter,index)=>{const column=this.columns.find(item=>item.id===filter.column),name=GRID_FILTER_LABELS[filter.operator];const condition=column.title+" " +(this.labels[name]||name)+(filter.values.length?" "+filter.values.join(", "):"");chip(condition,fill(this.labels.gridRemoveCondition,{condition}),"filter-"+index,()=>{const filters=this.queryForChange().filters.slice(),at=filters.findIndex(item=>JSON.stringify(item)===JSON.stringify(filter));if(at>=0){filters.splice(at,1);apply({filters})}})});if(query.filterGroup){const count=group=>group.filters.length+group.groups.reduce((total,child)=>total+count(child),0);chip(fill(this.labels.gridGroupedFilters,{count:numbers.format(count(query.filterGroup))}),this.labels.gridRemoveGroup,"group",()=>{if(JSON.stringify(this.queryForChange().filterGroup)===JSON.stringify(query.filterGroup))apply({filterGroup:undefined})})}
1051
+ this.labels.gridMatchedCount:this.view.noun?this.labels.gridResultNoun:this.labels.gridResultCount,{count:numbers.format(this.snapshot.matched),total:numbers.format(this.snapshot.total),noun:this.view.noun||this.labels.gridRows});this.queryChips.textContent="";const apply=patch=>{this.setQuery(gridQueryStart(this.queryForChange(true),patch)).catch(()=>{})};const chip=(text,label,id,run)=>{const button=gridButton("",()=>{button.focus({preventScroll:true});run()});button.classList.add("cx-grid-chip");filterChipContent(button,text);button.title=text;button.setAttribute("aria-label",label);button.setAttribute("data-cx-condition",id);this.queryChips.appendChild(button)};if(query.search)chip(query.search,fill(this.labels.gridRemoveSearch,{search:query.search}),"search",()=>{if(this.searchInput)this.searchInput.value="";apply({search:""})});query.filters.forEach((filter,index)=>{const column=this.columns.find(item=>item.id===filter.column),name=GRID_FILTER_LABELS[filter.operator]||filter.operator;const condition=column.title+" " +(this.labels[name]||name)+(filter.values.length?" "+filter.values.join(", "):"");chip(condition,fill(this.labels.gridRemoveCondition,{condition}),"filter-"+index,()=>{const filters=this.queryForChange().filters.slice(),at=filters.findIndex(item=>JSON.stringify(item)===JSON.stringify(filter));if(at>=0){filters.splice(at,1);apply({filters})}})});if(query.filterGroup){const count=group=>group.filters.length+group.groups.reduce((total,child)=>total+count(child),0);chip(fill(this.labels.gridGroupedFilters,{count:numbers.format(count(query.filterGroup))}),this.labels.gridRemoveGroup,"group",()=>{if(JSON.stringify(this.queryForChange().filterGroup)===JSON.stringify(query.filterGroup))apply({filterGroup:undefined})})}
995
1052
  if(query.search||query.filters.length||query.filterGroup){const clear=gridButton(this.labels.gridClearAll,()=>{clear.focus({preventScroll:true});if(this.searchInput)this.searchInput.value="";apply({search:"",filters:[],filterGroup:undefined})});clear.classList.add("cx-link");clear.setAttribute("aria-label",this.labels.gridClearQuery);clear.setAttribute("data-cx-condition","clear");this.queryChips.appendChild(clear)}
996
1053
  if(focused){const target=[...this.queryChips.children].find(button=>button.getAttribute("data-cx-condition")===key);(target||this.queryChips.lastElementChild||this.searchInput||this.grid).focus({preventScroll:true})}
997
1054
  this.gridPopover?.position()}});DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{gridFilters:"Filters",gridColumn:"Column",gridOperator:"Condition",gridValueType:"Raw value type",gridText:"Text",gridBoolean:"Boolean",gridRemoveFilter:"Remove {column} filter",gridApply:"Apply",gridClearFilters:"Clear all filters",gridFitAllColumns:"Fit all columns",gridViews:"Views",gridViewName:"View name",gridSaveView:"Save view",gridRemoveView:"Remove view",gridResetView:"Reset view",gridChooseView:"Choose a saved view",gridInvalidFilter:"Enter a valid filter value.",gridContains:"contains",gridStartsWith:"starts with",gridIn:"is any of",gridIsNull:"is missing",gridIsNotNull:"is present",gridFindColumn:"Find a column…",gridShowAllColumns:"Show all",gridResetColumns:"Reset columns",gridReorderColumn:"{column}: drag, or press Alt+Up or Alt+Down to move",gridPinnedLeft:"Pinned left",gridPinnedRight:"Pinned right"}));Object.assign(DataGrid.prototype,TOOLBAR_PANELS,{buildGridControls(){this.startMenus();this.buildGridFilters();if(this.tools.columns!==false)this.buildGridColumns();if(this.tools.views!==false){this.buildSavedViews();this.toolbar.querySelector(".cx-grid-views .cx-grid-panel").appendChild(gridButton(this.labels.gridResetView,()=>this.resetView().catch(()=>{})))}
@@ -1002,7 +1059,7 @@ this.runGridHook(signal=>this.opts.onChart({query:this.getQuery(),selection:this
1002
1059
  {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")||
1003
1060
  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}
1004
1061
  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)}}
1005
- 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()}
1062
+ 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()}
1006
1063
  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))}
1007
1064
  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))}
1008
1065
  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)}}
@@ -1011,7 +1068,7 @@ if(this.gridPopover)this.gridPopover.position()}});const GRID_PIN_PREPARE=DataGr
1011
1068
  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)}
1012
1069
  for(const column of[...grid.cols].reverse())if(column.effectivePin==="right"){column.pinOffset=end;end+=width(column)}
1013
1070
  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)})}
1014
- 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)}
1071
+ 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,overlayTheme,reportingRangeRows:typeof reportingRangeRows==="function"?reportingRangeRows:null}));function loadGridFilterEditor(){return loadPart(FILTER_EDITOR)}
1015
1072
  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())}}
1016
1073
  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)+'"]'))}
1017
1074
  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")}
@@ -1021,7 +1078,7 @@ const prepared=grid.calIcsFormatWriter&&provider?.write===grid.calIcsFormatWrite
1021
1078
  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))
1022
1079
  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||
1023
1080
  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:
1024
- 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)||
1081
+ 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)||
1025
1082
  index<(this.cursor?this.pageOffset:0)||index>=this.rowCount())
1026
1083
  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)
1027
1084
  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)})}
@@ -1174,8 +1231,8 @@ destroy(){this.clearDropRow();this.dragLease=null;super.destroy()}};class FlowHo
1174
1231
  const FORMS_IMPL={},FLOW_IMPL={},activeFlows=new WeakMap();const FORMS_PART=definePart(FlowHost,"forms","forms",()=>({FORMS_IMPL,h,setText,fill,gridFreeze,gridMomentFromParts,boundedPattern,foldText}));const FLOW_VIEWS=typeof FLOW_GRID_VIEWS==="object"?FLOW_GRID_VIEWS:Object.freeze({grid:null,tree:null,reporting:false});const FLOW_PART=definePart(FlowHost,"flow","flow view",()=>({FLOW_IMPL,FORMS_IMPL,h,setText,fill,plural,foldText,boundedPattern,numberFormat,gridFreeze}));const FLOW_FEATURES={};for(const name of["host","checks","options","pick","records","drafts","preview","command","tasks","dialog","links","endpoint","consent"])
1175
1232
  FLOW_FEATURES[name]=definePart(FlowHost,"flow-"+name,"flow "+name,()=>({FLOW_IMPL,FORMS_IMPL,h,setText,fill,plural,numberFormat,FLOW_VIEWS}));if(typeof DataGrid==="function")DataGrid.prototype.parts.forms=FORMS_PART;const FLOW_DOC_PARTS={command:"command",presets:"drafts",draft:"drafts",deepLinks:"links",endpoint:"endpoint"},FLOW_DOC_PLAIN={draft:"none",deepLinks:false};function flowFeatures(doc,hooks){const names=new Set(),add=(name,on)=>on&&names.add(name),list=value=>Array.isArray(value)?value:[];const object=value=>value!==null&&typeof value==="object"&&!Array.isArray(value),has=(value,...keys)=>object(value)&&keys.some(key=>value[key]!==undefined);for(const[key,name]of Object.entries(FLOW_DOC_PARTS))add(name,doc[key]!==undefined&&doc[key]!==FLOW_DOC_PLAIN[key]);add("tasks",doc.mode==="tasks");add("dialog",has(doc.layout,"launch")||has(doc.layout,"container")&&doc.layout.container!=="inline");add("preview",list(doc.endpoint?.routes).includes("preview"));for(const step of list(doc.steps).filter(object)){add("checks",step.checks!==undefined);add("pick",step.type==="pick");add("preview",step.preview===true);add("consent",has(step,"confirm","acknowledge"));for(const block of[step,...list(step.sections)]){if(block!==step)add("options",has(block,"source","dependsOn"));for(const field of object(block)?list(block.fields):[]){add("options",has(field,"dependsOn")||has(field,"source")&&field.source!=="document");add("records",object(field)&&field.type==="records")}}}
1176
1233
  hooks=object(hooks)?hooks:{};return{required:[...names],optional:[typeof hooks.preview==="function"&&"preview",object(hooks.presetStore)&&"drafts"].filter(name=>name&&!names.has(name))}}
1177
- const FLOW_ASYNC_METHODS=["next","back","goTo","setState","validate","submit","runCheck","refreshOptions","saveDraft","setPreset"];const FLOW_SYNC_METHODS=["getStep","getValues","setValues","getState","isDirty","reset","setFieldError","setProgress","complete","setStepState","open","close"];function createFlow(host,options){if(!host||!options||!options.flow||typeof options.flow!=="object")throw new Error("CanopyX: createFlow needs a host element and a flow document.");const existing=activeFlows.get(host);if(existing)return existing;let impl=null,destroyed=false,mountError=null;const destroyedError=()=>new Error("CanopyX: this flow has been destroyed.");const requireImpl=name=>{if(destroyed)throw destroyedError();if(!impl)throw new Error("CanopyX: flow is not ready; await api.ready before calling "+name+"().");return impl};const editors=Object.assign({},...[...PLUGINS.values()].map(item=>item.editors||{}));const{required,optional}=flowFeatures(options.flow,options.hooks);const ready=Promise.all([loadPart(FLOW_PART),...required.map(name=>loadPart(FLOW_FEATURES[name])),...optional.map(name=>loadPart(FLOW_FEATURES[name])
1178
- .catch(error=>host.dispatchEvent(new CustomEvent("canopyx:error",{detail:{error,hook:"part"},bubbles:true}))))]).then(async()=>{if(destroyed)throw destroyedError();impl=FLOW_IMPL.create(host,options,editors);return impl.ready});const api={element:host,flow:options.flow,view:options.flow};for(const name of FLOW_SYNC_METHODS)api[name]=(...args)=>requireImpl(name)[name](...args);for(const name of FLOW_ASYNC_METHODS)api[name]=(...args)=>{if(destroyed)return Promise.reject(destroyedError());return ready.then(()=>requireImpl(name)[name](...args))};api.ready=ready.then(()=>{if(destroyed)throw destroyedError();return api});api.ready.catch(()=>{});api.destroy=()=>{if(destroyed)return;destroyed=true;try{impl?.destroy()}
1234
+ const FLOW_ASYNC_METHODS=["next","back","goTo","setState","validate","submit","runCheck","refreshOptions","saveDraft","setPreset"];const FLOW_SYNC_METHODS=["getStep","getValues","setValues","getState","isDirty","reset","setFieldError","setProgress","complete","setStepState","open","close"];function createFlow(host,options){if(!host||!options||!options.flow||typeof options.flow!=="object")throw new Error("CanopyX: createFlow needs a host element and a flow document.");const existing=activeFlows.get(host);if(existing)return existing;const disposeTheme=watchTheme(host);let impl=null,destroyed=false,mountError=null;const destroyedError=()=>new Error("CanopyX: this flow has been destroyed.");const requireImpl=name=>{if(destroyed)throw destroyedError();if(!impl)throw new Error("CanopyX: flow is not ready; await api.ready before calling "+name+"().");return impl};const editors=Object.assign({},...[...PLUGINS.values()].map(item=>item.editors||{}));const{required,optional}=flowFeatures(options.flow,options.hooks);const ready=Promise.all([loadPart(FLOW_PART),...required.map(name=>loadPart(FLOW_FEATURES[name])),...optional.map(name=>loadPart(FLOW_FEATURES[name])
1235
+ .catch(error=>host.dispatchEvent(new CustomEvent("canopyx:error",{detail:{error,hook:"part"},bubbles:true}))))]).then(async()=>{if(destroyed)throw destroyedError();impl=FLOW_IMPL.create(host,options,editors);return impl.ready});const api={element:host,flow:options.flow,view:options.flow};for(const name of FLOW_SYNC_METHODS)api[name]=(...args)=>requireImpl(name)[name](...args);for(const name of FLOW_ASYNC_METHODS)api[name]=(...args)=>{if(destroyed)return Promise.reject(destroyedError());return ready.then(()=>requireImpl(name)[name](...args))};api.ready=ready.then(()=>{if(destroyed)throw destroyedError();return api});api.ready.catch(()=>{});api.destroy=()=>{if(destroyed)return;destroyed=true;disposeTheme();try{impl?.destroy()}
1179
1236
  finally{impl=null;mountError?.remove();if(activeFlows.get(host)===api){activeFlows.delete(host);if(host.canopyx===api)delete host.canopyx;host.removeAttribute("data-canopyx-mounted");host.removeAttribute("data-cx-ready");host.removeAttribute("data-cx-error");host.classList.remove("cx-flow-host")}}};ready.catch(error=>{if(destroyed)return;const notice=mountError=h("div","cx-mount-error");notice.setAttribute("role","alert");setText(notice,error&&error.message?error.message:String(error));host.appendChild(notice);host.setAttribute("data-cx-error",notice.textContent);host.dispatchEvent(new CustomEvent("canopyx:error",{detail:{error},bubbles:true}))});Object.freeze(api);activeFlows.set(host,api);host.classList.add("cx-host","cx-flow-host");host.setAttribute("data-canopyx-mounted","true");host.canopyx=api;return api}
1180
1237
  const FLOW_API={createFlow};function createTreeGrid(host,options){if(!host||!options||!options.view){throw new Error("CanopyX: createTreeGrid needs a host element and a view document.")}
1181
1238
  const existing=activeGrids.get(host);if(existing)return existing;const grid=new TreeGrid(host,options);const api=Object.assign({element:host,view:grid.view,ready:startPlugins(grid,()=>api),expandPath:(ids,o)=>grid.expandPath(ids,o),setFilter:(filter,o)=>{if(!grid.queryAware)grid.clearDeclaredFilters();grid.setFilter(filter,o)},setFilterActive:(id,active)=>grid.setFilterActive(id,active),setActiveFilters:(ids)=>grid.setActiveFilters(ids),updateActiveFilters:(change)=>grid.updateActiveFilters(change),getActiveFilters:()=>Array.from(grid.activeFilters),sort:(columnId,direction)=>grid.sort(columnId,direction),getQuery:()=>grid.getQuery(),setQuery:(query,options)=>grid.setQuery(query,options),setColumnVisible:(columnId,visible)=>grid.setColumnVisible(columnId,visible),setColumnWidth:(columnId,width)=>grid.setColumnWidth(columnId,width),setTreeColumnPinned:(pinned)=>grid.setTreeColumnPinned(pinned),setTimeZone:(zone)=>grid.setTimeZone(zone),getTimeZone:()=>(grid.local?"local":"utc"),refresh:()=>{grid.version++;grid.scheduleRender()},reload:(id,options)=>grid.reload(id,options),readLocation:()=>grid.readLocation(),getSelected:()=>Array.from(grid.selected).map((w)=>w.h),setSelection:(ids)=>grid.setSelection(ids),clearSelection:()=>grid.setSelection([]),selectAll:(options)=>grid.selectAll(options),focus:()=>{if(grid.destroyed)return;const target=grid.indexOf(grid.focused)>=0?grid.focused:grid.rows[0];if(target)grid.setFocus(target,true);else grid.grid.focus({preventScroll:true})},visibleRows:()=>grid.visibleRows(),toOutline:()=>grid.toOutline(),getState:()=>grid.getState(),setState:(state)=>grid.setState(state),getLayout:()=>grid.getLayout(),setLayout:(change)=>grid.setLayout(change),getMatches:()=>grid.getMatches(),setSearchHighlight:(enabled)=>grid.setSearchHighlight(enabled),nextMatch:(options)=>grid.nextMatch(options),previousMatch:(options)=>grid.previousMatch(options),search:(query,limit)=>grid.search(query,limit||(grid.view.search&&grid.view.search.maxResults)||20),loadMore:(id)=>{const w=id==null?grid.root:grid.keyMap.get(id);return w?grid.loadMore(w):Promise.resolve()},applyCounts:(doc)=>grid.applyCounts(doc),refreshCounts:(ids)=>grid.refreshCounts(ids),closeMenus:()=>grid.closeMenus?.(),destroy:()=>{grid.destroy();if(activeGrids.get(host)===api)activeGrids.delete(host);if(host.canopyx===api)delete host.canopyx}},grid.interactionApi&&grid.interactionApi(),linkApi(grid));for(const name of["prepareExport","exportAs","getSavedViews","saveView","applySavedView","removeSavedView","resetView","setColumnOrder","resetColumns","setColumnPinned","openDetails","openRecord"])