@evotecit/canopyx 0.3.18 → 0.3.21

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 (133) hide show
  1. package/CanopyX.Html/Assets/canopyx-board.css +12 -12
  2. package/CanopyX.Html/Assets/canopyx-board.js +1 -1
  3. package/CanopyX.Html/Assets/canopyx-calendar.css +70 -57
  4. package/CanopyX.Html/Assets/canopyx-calendar.js +14 -14
  5. package/CanopyX.Html/Assets/canopyx-cell-range.css +4 -4
  6. package/CanopyX.Html/Assets/canopyx-cell-range.js +1 -1
  7. package/CanopyX.Html/Assets/canopyx-changes.css +55 -55
  8. package/CanopyX.Html/Assets/canopyx-changes.js +1 -1
  9. package/CanopyX.Html/Assets/canopyx-column-groups.css +5 -1
  10. package/CanopyX.Html/Assets/canopyx-column-groups.js +15 -9
  11. package/CanopyX.Html/Assets/canopyx-compare.css +4 -4
  12. package/CanopyX.Html/Assets/canopyx-compare.js +1 -1
  13. package/CanopyX.Html/Assets/canopyx-detail-rows.css +4 -4
  14. package/CanopyX.Html/Assets/canopyx-detail-rows.js +1 -1
  15. package/CanopyX.Html/Assets/canopyx-editing.css +3 -3
  16. package/CanopyX.Html/Assets/canopyx-editing.js +1 -1
  17. package/CanopyX.Html/Assets/canopyx-enhance.js +2 -2
  18. package/CanopyX.Html/Assets/canopyx-export.js +8 -8
  19. package/CanopyX.Html/Assets/canopyx-facets.css +19 -18
  20. package/CanopyX.Html/Assets/canopyx-facets.js +1 -1
  21. package/CanopyX.Html/Assets/canopyx-filter-editor.css +24 -24
  22. package/CanopyX.Html/Assets/canopyx-filter-editor.js +3 -3
  23. package/CanopyX.Html/Assets/canopyx-flow-checks.css +2 -2
  24. package/CanopyX.Html/Assets/canopyx-flow-checks.js +1 -1
  25. package/CanopyX.Html/Assets/canopyx-flow-command.css +3 -3
  26. package/CanopyX.Html/Assets/canopyx-flow-command.js +1 -1
  27. package/CanopyX.Html/Assets/canopyx-flow-dialog.css +2 -2
  28. package/CanopyX.Html/Assets/canopyx-flow-dialog.js +1 -1
  29. package/CanopyX.Html/Assets/canopyx-flow-drafts.css +2 -2
  30. package/CanopyX.Html/Assets/canopyx-flow-drafts.js +1 -1
  31. package/CanopyX.Html/Assets/canopyx-flow-entry.css +24 -23
  32. package/CanopyX.Html/Assets/canopyx-flow-entry.js +4 -4
  33. package/CanopyX.Html/Assets/canopyx-flow-host.css +2 -2
  34. package/CanopyX.Html/Assets/canopyx-flow-host.js +1 -1
  35. package/CanopyX.Html/Assets/canopyx-flow-module.mjs +4 -4
  36. package/CanopyX.Html/Assets/canopyx-flow-pick.css +4 -4
  37. package/CanopyX.Html/Assets/canopyx-flow-pick.js +1 -1
  38. package/CanopyX.Html/Assets/canopyx-flow-preview.css +1 -1
  39. package/CanopyX.Html/Assets/canopyx-flow-preview.js +1 -1
  40. package/CanopyX.Html/Assets/canopyx-flow-records.css +2 -2
  41. package/CanopyX.Html/Assets/canopyx-flow-records.js +1 -1
  42. package/CanopyX.Html/Assets/canopyx-flow-tasks.css +4 -4
  43. package/CanopyX.Html/Assets/canopyx-flow-tasks.js +1 -1
  44. package/CanopyX.Html/Assets/canopyx-flow.css +41 -41
  45. package/CanopyX.Html/Assets/canopyx-flow.js +1 -1
  46. package/CanopyX.Html/Assets/canopyx-format-editor.css +9 -9
  47. package/CanopyX.Html/Assets/canopyx-format-editor.js +1 -1
  48. package/CanopyX.Html/Assets/canopyx-formatting.css +13 -13
  49. package/CanopyX.Html/Assets/canopyx-formatting.js +3 -3
  50. package/CanopyX.Html/Assets/canopyx-forms.css +3 -3
  51. package/CanopyX.Html/Assets/canopyx-forms.js +1 -1
  52. package/CanopyX.Html/Assets/canopyx-grid-module.mjs +56 -46
  53. package/CanopyX.Html/Assets/canopyx-grid-options.css +8 -8
  54. package/CanopyX.Html/Assets/canopyx-grid-options.js +9 -2
  55. package/CanopyX.Html/Assets/canopyx-grid.css +99 -96
  56. package/CanopyX.Html/Assets/canopyx-grid.js +55 -45
  57. package/CanopyX.Html/Assets/canopyx-grouping.css +7 -7
  58. package/CanopyX.Html/Assets/canopyx-grouping.js +1 -1
  59. package/CanopyX.Html/Assets/canopyx-highlight.css +10 -10
  60. package/CanopyX.Html/Assets/canopyx-highlight.js +1 -1
  61. package/CanopyX.Html/Assets/canopyx-interactive.css +50 -49
  62. package/CanopyX.Html/Assets/canopyx-interactive.js +12 -11
  63. package/CanopyX.Html/Assets/canopyx-labels-de.js +4 -0
  64. package/CanopyX.Html/Assets/canopyx-labels-es.js +4 -0
  65. package/CanopyX.Html/Assets/canopyx-labels-fr.js +4 -0
  66. package/CanopyX.Html/Assets/canopyx-labels-it.js +4 -0
  67. package/CanopyX.Html/Assets/canopyx-labels-pl.js +4 -0
  68. package/CanopyX.Html/Assets/canopyx-layouts.css +9 -9
  69. package/CanopyX.Html/Assets/canopyx-layouts.js +2 -2
  70. package/CanopyX.Html/Assets/canopyx-link.css +3 -3
  71. package/CanopyX.Html/Assets/canopyx-link.js +3 -3
  72. package/CanopyX.Html/Assets/canopyx-links.js +2 -2
  73. package/CanopyX.Html/Assets/canopyx-live.css +2 -2
  74. package/CanopyX.Html/Assets/canopyx-live.js +1 -1
  75. package/CanopyX.Html/Assets/canopyx-matrix.css +31 -31
  76. package/CanopyX.Html/Assets/canopyx-matrix.js +1 -1
  77. package/CanopyX.Html/Assets/canopyx-module.mjs +13 -12
  78. package/CanopyX.Html/Assets/canopyx-pager.css +1 -1
  79. package/CanopyX.Html/Assets/canopyx-pager.js +1 -1
  80. package/CanopyX.Html/Assets/canopyx-path.css +8 -8
  81. package/CanopyX.Html/Assets/canopyx-path.js +1 -1
  82. package/CanopyX.Html/Assets/canopyx-pivot.css +10 -10
  83. package/CanopyX.Html/Assets/canopyx-pivot.js +3 -3
  84. package/CanopyX.Html/Assets/canopyx-plan.css +24 -17
  85. package/CanopyX.Html/Assets/canopyx-plan.js +13 -9
  86. package/CanopyX.Html/Assets/canopyx-record-panel.css +47 -42
  87. package/CanopyX.Html/Assets/canopyx-record-panel.js +16 -9
  88. package/CanopyX.Html/Assets/canopyx-reporting-module.mjs +59 -56
  89. package/CanopyX.Html/Assets/canopyx-reporting.css +104 -101
  90. package/CanopyX.Html/Assets/canopyx-reporting.js +58 -55
  91. package/CanopyX.Html/Assets/canopyx-stack.css +6 -6
  92. package/CanopyX.Html/Assets/canopyx-stack.js +1 -1
  93. package/CanopyX.Html/Assets/canopyx-time-slider.css +5 -5
  94. package/CanopyX.Html/Assets/canopyx-time-slider.js +1 -1
  95. package/CanopyX.Html/Assets/canopyx-timeline.css +19 -19
  96. package/CanopyX.Html/Assets/canopyx-timeline.js +2 -2
  97. package/CanopyX.Html/Assets/canopyx-tree-tools.css +21 -21
  98. package/CanopyX.Html/Assets/canopyx-tree-tools.js +3 -3
  99. package/CanopyX.Html/Assets/canopyx-ui-accordion.css +119 -0
  100. package/CanopyX.Html/Assets/canopyx-ui-accordion.js +33 -0
  101. package/CanopyX.Html/Assets/canopyx-ui-menu.css +7 -7
  102. package/CanopyX.Html/Assets/canopyx-ui-menu.js +1 -1
  103. package/CanopyX.Html/Assets/canopyx-ui-module.mjs +39 -0
  104. package/CanopyX.Html/Assets/canopyx-ui-navigation.css +9 -9
  105. package/CanopyX.Html/Assets/canopyx-ui-navigation.js +5 -5
  106. package/CanopyX.Html/Assets/canopyx-ui-overlays.css +5 -5
  107. package/CanopyX.Html/Assets/canopyx-ui-overlays.js +5 -2
  108. package/CanopyX.Html/Assets/canopyx-ui-picker.css +2 -2
  109. package/CanopyX.Html/Assets/canopyx-ui-picker.js +1 -1
  110. package/CanopyX.Html/Assets/canopyx-ui-stepper.css +12 -12
  111. package/CanopyX.Html/Assets/canopyx-ui-stepper.js +1 -1
  112. package/CanopyX.Html/Assets/canopyx-ui-tabs.css +9 -8
  113. package/CanopyX.Html/Assets/canopyx-ui-tabs.js +7 -4
  114. package/CanopyX.Html/Assets/canopyx-ui.css +119 -0
  115. package/CanopyX.Html/Assets/canopyx-ui.js +37 -0
  116. package/CanopyX.Html/Assets/canopyx-view-intents.css +1 -1
  117. package/CanopyX.Html/Assets/canopyx-view-intents.js +1 -1
  118. package/CanopyX.Html/Assets/canopyx.css +47 -46
  119. package/CanopyX.Html/Assets/canopyx.js +12 -11
  120. package/JavaScript/column-groups.d.ts +24 -4
  121. package/JavaScript/grid.d.ts +11 -1
  122. package/JavaScript/hosts.d.ts +2 -0
  123. package/JavaScript/locales/de.mjs +4 -0
  124. package/JavaScript/locales/es.mjs +4 -0
  125. package/JavaScript/locales/fr.mjs +4 -0
  126. package/JavaScript/locales/it.mjs +4 -0
  127. package/JavaScript/locales/pl.mjs +4 -0
  128. package/JavaScript/protocol.d.ts +3 -0
  129. package/JavaScript/records.d.ts +2 -0
  130. package/JavaScript/ui.d.ts +70 -2
  131. package/README.md +76 -206
  132. package/README.nuget.md +63 -87
  133. package/package.json +14 -1
@@ -75,8 +75,7 @@ function fill(template,values){return template.replace(/\{(\w+)\}/g, (match, nam
75
75
  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
76
  let rules=pluralRules.get(lang);if(!rules){try{rules=new Intl.PluralRules(lang||"en")}catch(_){rules=new Intl.PluralRules("en")}pluralRules.set(lang,rules)}
77
77
  return forms[rules.select(Number(count))]??forms.other??template}
78
- let DEFAULT_LABELS=Object.freeze({searchPlaceholder:"Search",searchResults:"Search results",searchResultCount:"{count} results",searchResultCountOfTotal:"{count} of {total} results",searchResultCountOfMany:"{count} of many results",searchNoResults:"No results",searchTooShort:"Type at least {min} characters",searchWordTooShort:"Type a word of at least {min} characters",searchFailed:"Search failed: {error}",columns:"Columns",hiddenColumns:"[one]+{count} column[other]+{count} columns",visibleColumns:"Visible columns",resizeColumn:"Resize {column}",columnWidth:"{width} pixels",loading:"Loading…",loadError:"Could not load: {error} (Enter to retry)",queryFailed:"Could not update the view: {error}",showMore:"Show more ({loaded} of {total} loaded)",showMoreUnknownTotal:"Show more ({loaded} loaded)",pageLoaded:"{loaded} of {total} loaded",itemsLoaded:"{count} items",yes:"Yes",no:"No",utcTime:"{time} UTC",localTime:"{time} local time",mountError:"This view could not be displayed: {error}"});function labelsFor(...sources){const labels=Object.assign({},DEFAULT_LABELS);for(const source of sources){if(source==null)continue;if(typeof source!=="object"||Array.isArray(source))throw new Error("CanopyX: labels must be an object of strings.");Object.keys(source).forEach((name)=>{const uiLabel=/^(?:tabs(?:More(?:Selected)?|ScrollPrevious|ScrollNext|Section|Position|Pause|Play|MotionDisabled)|stepper(?:StepOf|Back|Next|Finish|Skip|SaveDraft|AllSteps|Optional|Completed|Skipped|Issues?)|dialogClose|drawer(?:Close|Previous|Next)|state(?:Loading|Retry|Details))$/.test(name);
79
- if(!Object.hasOwn(DEFAULT_LABELS,name)&&!/^(?:gridEdit|format|calendar|flow|matrix|change|board|plan|path|stack|time|compare|viewIntent)[A-Z]\w{0,63}$/.test(name) && !uiLabel) throw new Error("CanopyX: there is no label '" + name + "'.");
78
+ let DEFAULT_LABELS=Object.freeze({searchPlaceholder:"Search",searchResults:"Search results",searchResultCount:"{count} results",searchResultCountOfTotal:"{count} of {total} results",searchResultCountOfMany:"{count} of many results",searchNoResults:"No results",searchTooShort:"Type at least {min} characters",searchWordTooShort:"Type a word of at least {min} characters",searchFailed:"Search failed: {error}",columns:"Columns",hiddenColumns:"[one]+{count} column[other]+{count} columns",visibleColumns:"Visible columns",resizeColumn:"Resize {column}",columnWidth:"{width} pixels",loading:"Loading…",loadError:"Could not load: {error} (Enter to retry)",queryFailed:"Could not update the view: {error}",showMore:"Show more ({loaded} of {total} loaded)",showMoreUnknownTotal:"Show more ({loaded} loaded)",pageLoaded:"{loaded} of {total} loaded",itemsLoaded:"{count} items",yes:"Yes",no:"No",utcTime:"{time} UTC",localTime:"{time} local time",mountError:"This view could not be displayed: {error}"});function labelsFor(...sources){const labels=Object.assign({},DEFAULT_LABELS);for(const source of sources){if(source==null)continue;if(typeof source!=="object"||Array.isArray(source))throw new Error("CanopyX: labels must be an object of strings.");Object.keys(source).forEach((name)=>{if(!Object.hasOwn(DEFAULT_LABELS,name)&&!/^(?:gridEdit|format|calendar|flow|matrix|change|board|plan|path|stack|time|compare|viewIntent|tabs|stepper|accordion|dialog|drawer|state)[A-Z]\w{0,63}$/.test(name)) throw new Error("CanopyX: there is no label '" + name + "'.");
80
79
  if(typeof source[name]!=="string"||!/\S/.test(source[name])) throw new Error("CanopyX: label '" + name + "' must be a string with visible text.");
81
80
  if((name==="utcTime"||name==="localTime")&&source[name].indexOf("{time}")<0)throw new Error("CanopyX: label '"+name+"' must hold {time}.");labels[name]=source[name]})}
82
81
  return Object.freeze(labels)}
@@ -90,8 +89,8 @@ function trusted(kind,value){if(trustPolicy===undefined){try{trustPolicy=global.
90
89
  catch(_){trustPolicy=null}}
91
90
  return trustPolicy?trustPolicy["create"+kind](value):value}
92
91
  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.")}
93
- 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}}}
94
- 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}
92
+ 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;const surface=parent&&["--hfx-color-surface-card","--hfx-color-surface"].some(name=>parent.getPropertyValue(name).trim());let mode=null;if(!surface){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}}}
93
+ if(surface||!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}
95
94
  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)}
96
95
  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)}
97
96
  return copied}
@@ -214,8 +213,9 @@ if(kind==="inline"){if(!Array.isArray(view.roots))throw new Error("CanopyX: inli
214
213
  throw new Error("CanopyX: unknown source kind '"+kind+"'.")}
215
214
  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)}
216
215
  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))}}
217
- 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.")}
218
- 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"))
216
+ class TreeGrid{constructor(host,options){const view=checkDocument(options.view,"view");if(view.recordDrawerModal!==undefined&&typeof view.recordDrawerModal!=="boolean")
217
+ throw new Error("CanopyX: recordDrawerModal must be a Boolean.");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.")}
218
+ do{this.id="cx" + ++instanceSeq}while(document.getElementById(this.id));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"))
219
219
  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.")}
220
220
  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||[]}
221
221
  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()}
@@ -410,7 +410,7 @@ if(accepted&&deferred&&revision===this.selectionRevision)
410
410
  this.notifySelection(w,Array.from(this.selected).map((selected)=>selected.h),revision)}},async retryPage(status){const parent=status.parent;await this.loadStatusPage(parent,status,parent.next||null)},typeAhead(e,i){if(e.key.length!==1||e.ctrlKey||e.metaKey||e.altKey){return false}
411
411
  const now=performance.now();const letter=e.key.toLowerCase();this.typeBuf=now-this.typeAt>TYPEAHEAD_MS?letter:this.typeBuf+letter;this.typeAt=now;const n=this.rows.length;const start=this.typeBuf.length===1?i+1:i;for(let k=0;k<n;k++){const w=this.rows[(start+k)%n];if(!w.status&&String(w.h.label).toLowerCase().startsWith(this.typeBuf)){this.setFocus(w);break}}
412
412
  return true},announce(message){setText(this.live,message)}});const CELL_CONTROLS="a[href],button,input,select,textarea,summary,[tabindex],[contenteditable]:not([contenteditable=false])," +
413
- "[role=button],[role=checkbox],[role=radio],[role=link],[role=switch],[role=tab],[role=menuitem],[role=textbox],[role=combobox]";const OWN_ARROWS=".cx-detail-body,textarea,select,[contenteditable]:not([contenteditable=false]),[aria-activedescendant]," +
413
+ "[role=button],[role=checkbox],[role=radio],[role=link],[role=switch],[role=tab],[role=menuitem],[role=textbox],[role=combobox]";const OWN_ARROWS=".cx-detail-body,.cx-phone-value,textarea,select,[contenteditable]:not([contenteditable=false]),[aria-activedescendant]," +
414
414
  "[role=textbox],[role=combobox],[role=spinbutton],[role=slider],[role=radio],[role=tab],[role=menuitem],[role=listbox],[role=tree],[role=grid]," +
415
415
  "input:not([type=button]):not([type=checkbox]):not([type=submit]):not([type=reset]):not([type=image]):not([type=file]):not([type=color])";function reachable(control){return!control.matches(":disabled")&&!control.closest("[inert],[aria-hidden=true]")&&
416
416
  (control.checkVisibility?control.checkVisibility({visibilityProperty:true}):control.getClientRects().length>0)}
@@ -530,11 +530,11 @@ close()}else{return}
530
530
  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 lifetime=new AbortController();let flyout=null,pending=null;const ready=()=>flyout?Promise.resolve(flyout):pending||=loadPart(SHARED_PARTS["ui-overlays"]).then(()=>{if(!lifetime.signal.aborted)flyout=UI_TOOLS.toolbarFlyout(anchorElement,panel,isOpen,lifetime.signal);return flyout}).catch(error=>{pending=null;throw error});const invoke=method=>{if(lifetime.signal.aborted||!isOpen())return;if(flyout){flyout[method]();return}
531
531
  ready().then(value=>{if(!lifetime.signal.aborted&&isOpen())value?.[method]()}).catch(error=>{if(!lifetime.signal.aborted)(anchorElement.closest(".cx-host")||anchorElement)
532
532
  .dispatchEvent(new CustomEvent("canopyx:error",{detail:{error},bubbles:true}))})};return{position:()=>invoke("position"),open:()=>invoke("open"),close:()=>flyout?.close(),dispose:()=>lifetime.abort()}}
533
- const PART_URL=typeof document!=="undefined"&&document.currentScript?.src;const PARTS={"ui-overlays":["68a7687b9c3c8a28","canopyx-ui-overlays.83acc4346a232940.js","canopyx-ui-overlays.bc49b6f13527aecd.css"],"ui-menu":["c86ee2a16b5a5a46","canopyx-ui-menu.1414af91bc295de8.js","canopyx-ui-menu.29b983c01571b5c3.css"],"ui-picker":["02ff3779dd1c1ef4","canopyx-ui-picker.7fc22075e98b3e14.js","canopyx-ui-picker.a10010ec2d8143ae.css"],"ui-navigation":["e7815ee277df3a57","canopyx-ui-navigation.86b48ef9eaffe773.js","canopyx-ui-navigation.4dd22a646eb71b44.css"],"ui-tabs":["96f562187c7e0732","canopyx-ui-tabs.4ea5e653f6919c8e.js","canopyx-ui-tabs.68bc5521fcc174fe.css"],"ui-stepper":["89aeb7d73c4b8160","canopyx-ui-stepper.0198464c5b259da1.js","canopyx-ui-stepper.fe35ecb9b43b2b2e.css"],"tree-tools":["ab6490d0ae0e0aff","canopyx-tree-tools.23262806ed53e5de.js","canopyx-tree-tools.9c5a978314bf0a86.css"],"presenters":["d5f9d61bb730974b","canopyx-presenters.d71f9e12d83969d9.js"],"filter-editor":["3baf5349dd74fe9f","canopyx-filter-editor.a25a9997f0aef871.js","canopyx-filter-editor.6faf0c36e139d75f.css"],"export":["fa85a4b0e8aead4a","canopyx-export.f18d1ef109ccf0c6.js"],"office-export":["4fb7a4d570390ee9","canopyx-office-export.7e62c385b884e75b.js"],"history":["7d9901d2fe04df72","canopyx-history.9432e724bf14c9ed.js"],"pager":["3dcab112113081dd","canopyx-pager.15bb475e4365fe79.js","canopyx-pager.e39f321db5bdfde4.css"],"enhance":["c0f4773cf3b59919","canopyx-enhance.7b4dab125769b947.js"],"data":["bab770170bd2cfdd","canopyx-data.34325d1fd693886e.js"],"forms":["0d77c25f4fa14425","canopyx-forms.3b18e30a2aeb56dd.js","canopyx-forms.e3a0e1f016287057.css"],"flow":["93f8d2eb57cc1770","canopyx-flow.c3f65a21ced2d654.js","canopyx-flow.68af38159226dd08.css"],"flow-host":["6f335df747cc5f05","canopyx-flow-host.ea0be90307b19d0f.js","canopyx-flow-host.87b00b9ed5899f1f.css"],"flow-checks":["1710216916cb32a5","canopyx-flow-checks.5a3e04709a556310.js","canopyx-flow-checks.e97a4514fd32bde5.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":["c3b57a7478b94a93","canopyx-flow-dialog.a98f91c1fe0ade3b.js","canopyx-flow-dialog.98c7ea17adc9a223.css"],"flow-links":["2c14b19c9236e90d","canopyx-flow-links.7b6cfe42d28b6067.js"],"flow-endpoint":["f5cddfc9545e0920","canopyx-flow-endpoint.b31146202bd76aac.js"],"flow-facts":["385b5e61ed487e16","canopyx-flow-facts.8dad3bc07a71fdb0.js"],"flow-consent":["22121778bc0d07c5","canopyx-flow-consent.749b97f13039bc71.js","canopyx-flow-consent.9f6580d3673ae8bf.css"],"matrix":["e5fa5cb0660b953a","canopyx-matrix.84cbd5879b0e07fa.js","canopyx-matrix.b01ffc8cdafd463d.css"],"changes":["419bb03b4580fd5c","canopyx-changes.86727fd2ca1714dd.js","canopyx-changes.5403d88f9169c173.css"],"editing":["25fd83789bef4fcb","canopyx-editing.53aebff05d75884c.js","canopyx-editing.4b3c01342a64d4e3.css"],"column-groups":["cd6d93e033719439","canopyx-column-groups.922e21b9bdf57efa.js","canopyx-column-groups.6a6c9704c4ee7884.css"],"cell-range":["53c37a658f4f7afb","canopyx-cell-range.e8215f22827b9003.js","canopyx-cell-range.ce87ff1c2023feae.css"],"links":["f1ab7e32b501ce37","canopyx-links.d96addeefb3eccf5.js"],"search":["521eebd6e1bbbd35","canopyx-search.14c69f4551c69f23.js"],"formatting":["7d7402e30ec311ca","canopyx-formatting.6bfafbee3f9579d6.js","canopyx-formatting.922dc9fc7e6d35a7.css"],"format-editor":["5398e457a885ef0d","canopyx-format-editor.f65fa4b3402ae488.js","canopyx-format-editor.dbdf4a154e7e5f48.css"],"link":["fd21dd4495607a16","canopyx-link.5874879aadd6cefb.js","canopyx-link.b872151e9cbbd0ce.css"],"detail-rows":["e4150bb67f40d597","canopyx-detail-rows.e7f93158e19cbb28.js","canopyx-detail-rows.cabc50f51ed091ad.css"],"calculations":["f902dc5856fc7bdd","canopyx-calculations.97e438237ba43f99.js","canopyx-calculations.50432e524dd7d8d9.css"],"pivot":["230b05b7fcab6cf1","canopyx-pivot.de89c7750bbaf133.js","canopyx-pivot.3a7e122e33aaeab4.css"],"values":["0d7006b0f7bfca10","canopyx-values.ad4c56fcbcd89cbb.js","canopyx-values.446654b98c62ef1d.css"],"buckets":["cc69c8336c15df83","canopyx-buckets.1f59613f13ee292c.js"],"grouping":["c7eead770d16a84b","canopyx-grouping.dcab87ec8593eb59.js","canopyx-grouping.c4dace7c55dbb84b.css"],"highlight":["459b28e174406d32","canopyx-highlight.10ef4bb28c5a8f5b.js","canopyx-highlight.ab1040f93cbb5dbb.css"],"layouts":["077268d4fb78c464","canopyx-layouts.9a318c748cde4c84.js","canopyx-layouts.18dbf5842f1c5efd.css"],"facets":["f1ed74d2447e4f11","canopyx-facets.9a51d843e93278f4.js","canopyx-facets.6da87c205c61cbe2.css"],"live":["4ef2fb01714f877e","canopyx-live.c6d5b70f326f3bf9.js","canopyx-live.b60435092089b07f.css"],"record-panel":["2a4059ade4ca1439","canopyx-record-panel.4f525c01ecbd0e07.js","canopyx-record-panel.f1d740569605e625.css"],"calendar":["4762fd2f9e9d1617","canopyx-calendar.df3bcff81a62548a.js","canopyx-calendar.88ef06b86bccd0df.css"],"calendar-recurrence":["64bcc24d785bd1af","canopyx-calendar-recurrence.4b7f430c2a64de23.js"],"calendar-edit":["09747e191820d94c","canopyx-calendar-edit.174f5125d3e75bd9.js"],"calendar-ics":["ac8b2950fccbfb0f","canopyx-calendar-ics.4a18c1c4a1520418.js"],"timeline":["ece982b3b7277183","canopyx-timeline.66fe4cefa5f41ff7.js","canopyx-timeline.e3c962ae517931d2.css"],"grid-options":["e74170bbb841519c","canopyx-grid-options.c5fa91fc19205d5a.js","canopyx-grid-options.9c393c5122332461.css"],"board":["31d8984cbdc39866","canopyx-board.5dcac9033d72968c.js","canopyx-board.2351154bbc60bf43.css"],"plan":["640ca4be173c3310","canopyx-plan.58418c1ff7605fa3.js","canopyx-plan.be9f8826b6ab669f.css"],"path":["28b4b60b1851bf2e","canopyx-path.e32fe5c520a77be5.js","canopyx-path.61905ad5e56e2fd0.css"],"stack":["9ebd0cfb3f4f074b","canopyx-stack.041611f7810280dd.js","canopyx-stack.c875bfcb7eeaea25.css"],"time-slider":["a4888d801922c858","canopyx-time-slider.687623fbee479b03.js","canopyx-time-slider.2a79dfc4921df0bb.css"],"view-intents":["26b4233395638945","canopyx-view-intents.9579957e593d30d4.js","canopyx-view-intents.5b6d00ea612494a7.css"],"compare":["2df5f137f630380f","canopyx-compare.1863f941f9f5207d.js","canopyx-compare.acd8641545cac008.css"]},PART_CODE=new Map(),SHARED_PARTS={},partName=name=>typeof name==="string"&&/^[a-z][a-z\d-]{0,31}$/.test(name);
533
+ const PART_URL=typeof document!=="undefined"&&document.currentScript?.src;const PARTS={"ui-overlays":["24afaa117ebf3fb5","canopyx-ui-overlays.dedc42d3a501a387.js","canopyx-ui-overlays.3668a9a74004ea8e.css"],"ui-menu":["352b1ee391133ff0","canopyx-ui-menu.f9abee36db8f6ad2.js","canopyx-ui-menu.2f3478cc5f5c272f.css"],"ui-picker":["d415103478faf52a","canopyx-ui-picker.13e544bd68aca998.js","canopyx-ui-picker.59c85a1988a287a9.css"],"ui-navigation":["2553d01c5276d56a","canopyx-ui-navigation.c4ebc214197f140d.js","canopyx-ui-navigation.0afd07bbdc5aecb5.css"],"ui-tabs":["19ece8184f3daf4a","canopyx-ui-tabs.6cd35b2afd89f530.js","canopyx-ui-tabs.7bb6c6f1341e87e9.css"],"ui-stepper":["5682c49db1b85314","canopyx-ui-stepper.96973189b0f6e0c4.js","canopyx-ui-stepper.1d4a9db373b8d2f2.css"],"ui-accordion":["1424f075b78d0ccd","canopyx-ui-accordion.d0d5daa7f73d0859.js","canopyx-ui-accordion.a3ef9c27cea5b7a4.css"],"tree-tools":["ef0d06c82135ae2e","canopyx-tree-tools.1c4b9e286dde6065.js","canopyx-tree-tools.350dd0ee46757029.css"],"presenters":["d5f9d61bb730974b","canopyx-presenters.d71f9e12d83969d9.js"],"filter-editor":["b760f978327dbab0","canopyx-filter-editor.4851bd579e7d146c.js","canopyx-filter-editor.2e0cf6850cbd3235.css"],"export":["15abf3205094bda6","canopyx-export.68b90138463329fe.js"],"office-export":["4fb7a4d570390ee9","canopyx-office-export.7e62c385b884e75b.js"],"history":["7d9901d2fe04df72","canopyx-history.9432e724bf14c9ed.js"],"pager":["cc30dd4f6d3feeb0","canopyx-pager.2a6f5da8c93de083.js","canopyx-pager.c1e16027780b7fdd.css"],"enhance":["a3b4be5ec19a43a6","canopyx-enhance.4a189cba27c290de.js"],"data":["bab770170bd2cfdd","canopyx-data.34325d1fd693886e.js"],"forms":["381a3edba481660b","canopyx-forms.fa85aa9e8b62876a.js","canopyx-forms.50a5ddb0fcc98bdf.css"],"flow":["02a915fe174e4710","canopyx-flow.2ec165998fe2950d.js","canopyx-flow.347ecd64183ea3a1.css"],"flow-host":["7169c4283cec8b25","canopyx-flow-host.52ccd1a2b6cd53f7.js","canopyx-flow-host.a7c8d3fc930ad3a9.css"],"flow-checks":["53394e75b7d1b0e2","canopyx-flow-checks.76e58f9d05eaa78f.js","canopyx-flow-checks.88dd9f389b249147.css"],"flow-options":["60450342239ded26","canopyx-flow-options.d31458a54aa4b1e7.js"],"flow-pick":["7e0924c72fdd2f74","canopyx-flow-pick.c2e34da944b0edab.js","canopyx-flow-pick.ce7687598d4703f1.css"],"flow-records":["0b652a9789ce4128","canopyx-flow-records.df8aba0a303019e0.js","canopyx-flow-records.393243243aae9a56.css"],"flow-drafts":["fac75bf905a77d0b","canopyx-flow-drafts.c7db634ab651e9fc.js","canopyx-flow-drafts.2c43cff1ce9be700.css"],"flow-preview":["5e8207eed3801f91","canopyx-flow-preview.3924dc8410f9775d.js","canopyx-flow-preview.069c52c33e87ffb4.css"],"flow-command":["a30245a47f6d4530","canopyx-flow-command.b145a234a6ecc8a2.js","canopyx-flow-command.f98b5333af3a0e17.css"],"flow-tasks":["8a4437f5216ac3ee","canopyx-flow-tasks.569d4c40d317472b.js","canopyx-flow-tasks.54857a9f2732048a.css"],"flow-dialog":["8c45e0a8bb6a8ab9","canopyx-flow-dialog.cb4e85bcb7383fe2.js","canopyx-flow-dialog.58bd5d446415e01a.css"],"flow-links":["2c14b19c9236e90d","canopyx-flow-links.7b6cfe42d28b6067.js"],"flow-endpoint":["f5cddfc9545e0920","canopyx-flow-endpoint.b31146202bd76aac.js"],"flow-facts":["385b5e61ed487e16","canopyx-flow-facts.8dad3bc07a71fdb0.js"],"flow-consent":["22121778bc0d07c5","canopyx-flow-consent.749b97f13039bc71.js","canopyx-flow-consent.9f6580d3673ae8bf.css"],"matrix":["002a6d917bb4d638","canopyx-matrix.17ae2d0e03ad1364.js","canopyx-matrix.59fc6920ae000d49.css"],"changes":["7d9a526aa07a8838","canopyx-changes.75f1a61cbba98a4f.js","canopyx-changes.5f0ae1710b8b081c.css"],"editing":["88e4ca705a7eb0c3","canopyx-editing.6a6df811fb4dde54.js","canopyx-editing.4816f6be6f89d794.css"],"column-groups":["91abd99e8ff95b58","canopyx-column-groups.4c71d23375de727c.js","canopyx-column-groups.4e4131c1e2df40b1.css"],"cell-range":["cb29468954702795","canopyx-cell-range.d4f99a024db5d0f8.js","canopyx-cell-range.c790b8f140b1243b.css"],"links":["c6579c9401f0971d","canopyx-links.b25760079f57e6e1.js"],"search":["521eebd6e1bbbd35","canopyx-search.14c69f4551c69f23.js"],"formatting":["0feff4e3424599e9","canopyx-formatting.94536547a1d35e9b.js","canopyx-formatting.22b2400c566e25d6.css"],"format-editor":["97085e181fbc1cf7","canopyx-format-editor.a6bc57c48173bfc0.js","canopyx-format-editor.d5aaa8e873d92695.css"],"link":["7485f5c9875e9f9b","canopyx-link.9066770aa822fe0f.js","canopyx-link.997fefec6b85f0c5.css"],"detail-rows":["1892f1fd9d035c0f","canopyx-detail-rows.8be98dbc5721170a.js","canopyx-detail-rows.275076ec8bd9144a.css"],"calculations":["f902dc5856fc7bdd","canopyx-calculations.97e438237ba43f99.js","canopyx-calculations.50432e524dd7d8d9.css"],"pivot":["577443c67c7ed719","canopyx-pivot.3abc630122030933.js","canopyx-pivot.5670e62c0bbf114f.css"],"values":["0d7006b0f7bfca10","canopyx-values.ad4c56fcbcd89cbb.js","canopyx-values.446654b98c62ef1d.css"],"buckets":["cc69c8336c15df83","canopyx-buckets.1f59613f13ee292c.js"],"grouping":["c82705991ff01a4c","canopyx-grouping.239f13b0785a2e30.js","canopyx-grouping.a91801c602d752b3.css"],"highlight":["5ebf0042011ba4fd","canopyx-highlight.ff11a0ca8e30102b.js","canopyx-highlight.9c26291cbcd0962b.css"],"layouts":["90267e35e7edf3a4","canopyx-layouts.058b8a396f909a79.js","canopyx-layouts.ca17f42babc4192a.css"],"facets":["e78c2340a96fa802","canopyx-facets.74b2e520a3c04580.js","canopyx-facets.e2970dd7cf0c3da6.css"],"live":["78791b002a111843","canopyx-live.878dc16d683abb72.js","canopyx-live.9881627f352f59da.css"],"record-panel":["cb6bcd1baf644a51","canopyx-record-panel.557c676822e8624f.js","canopyx-record-panel.174846a640de979f.css"],"calendar":["e11aad6b723ddf23","canopyx-calendar.79518c25ddf28dd7.js","canopyx-calendar.47490d57a6e6c1dc.css"],"calendar-recurrence":["64bcc24d785bd1af","canopyx-calendar-recurrence.4b7f430c2a64de23.js"],"calendar-edit":["09747e191820d94c","canopyx-calendar-edit.174f5125d3e75bd9.js"],"calendar-ics":["ac8b2950fccbfb0f","canopyx-calendar-ics.4a18c1c4a1520418.js"],"timeline":["cb9b9dd33154172c","canopyx-timeline.a3dea165914fa7fd.js","canopyx-timeline.44c3156c218531e2.css"],"grid-options":["ee53e6f124b99d5a","canopyx-grid-options.9f8604806c93bf19.js","canopyx-grid-options.e85648a66d70d5b5.css"],"board":["dd02be00df77f53a","canopyx-board.81de43b6e0f4aec3.js","canopyx-board.b62cc3a0348e758a.css"],"plan":["db07c2eb53541d49","canopyx-plan.f3bf394516b627b7.js","canopyx-plan.743201d95414f399.css"],"path":["c6fa2dbab6a0dbaa","canopyx-path.97c3ee2b076b2db6.js","canopyx-path.efba21adc0bfc372.css"],"stack":["e29298edc07edb6d","canopyx-stack.82a5a0c6383519dc.js","canopyx-stack.b867aa57edf9002c.css"],"time-slider":["5516099a165cc345","canopyx-time-slider.ed59a275671c729f.js","canopyx-time-slider.dfc55326f03e1d4a.css"],"view-intents":["dbd26360f2b90a49","canopyx-view-intents.3adcb56dffca0650.js","canopyx-view-intents.29a5c2de68ce3ba0.css"],"compare":["46245b96483e9c30","canopyx-compare.2a8ddc0ce67e903f.js","canopyx-compare.da0a2dff321e782d.css"]},PART_CODE=new Map(),SHARED_PARTS={},partName=name=>typeof name==="string"&&/^[a-z][a-z\d-]{0,31}$/.test(name);
534
534
  function registerPart(name,part){if(!partName(name)||!part||typeof part.version!=="string"||typeof part.install!=="function"||
535
535
  part.requires!==undefined&&!(Array.isArray(part.requires)&&part.requires.every(partName)))throw new Error("CanopyX: invalid part.");PART_CODE.set(name,part)}
536
536
  function definePart(View,name,label,context){const parts=View.prototype.parts||={};return parts[name]={name,label,context,parts}}
537
- function loadPart(part){return part.ready||=Promise.resolve().then(async()=>{const[version,scriptFile,styleFile]=Object.hasOwn(PARTS,part.name)?PARTS[part.name]:[];part.version=version;if(!version)throw new Error("CanopyX: this runtime has no "+part.label+".");if(PART_CODE.get(part.name)?.version!==part.version||part.styleReady===null){const find=type=>[...document.querySelectorAll('script[type="application/x-canopyx-'+type+'"][data-cx-version="'+part.version+'"]')].find(item=>!pageNonce||item.nonce===pageNonce);const payload=find(part.name),script=h("script"),embeddedStyle=styleFile&&find(part.name+"-style");if(payload){if(embeddedStyle){const style=h("style");style.nonce=payload.nonce;setText(style,embeddedStyle.textContent);document.head.appendChild(style)}
537
+ function loadPart(part){return part.ready||=Promise.resolve().then(async()=>{const[version,scriptFile,styleFile]=Object.hasOwn(PARTS,part.name)?PARTS[part.name]:[];part.version=version;if(!version)throw new Error("CanopyX: no "+part.label+".");if(PART_CODE.get(part.name)?.version!==part.version||part.styleReady===null){const find=type=>[...document.querySelectorAll('script[type="application/x-canopyx-'+type+'"][data-cx-version="'+part.version+'"]')].find(item=>!pageNonce||item.nonce===pageNonce);const payload=find(part.name),script=h("script"),embeddedStyle=styleFile&&find(part.name+"-style");if(payload){if(embeddedStyle){const style=h("style");style.nonce=payload.nonce;setText(style,embeddedStyle.textContent);document.head.appendChild(style)}
538
538
  script.textContent=trusted("Script",payload.textContent);script.nonce=payload.nonce;document.head.appendChild(script);script.remove()}else{const base=global.CanopyXFilterEditorBase,runtime=PART_URL||typeof base==="string"&&base||document.baseURI,hashed=PART_URL&&/\.[a-f\d]{16}\.js(?:[?#]|$)/.test(PART_URL);
539
539
  const load=(element,attribute,file,kind)=>new Promise((resolve,reject)=>{const url=new URL(file,runtime).href;element[attribute]=attribute==="src"?trusted("ScriptURL",url):url;element.onload=resolve;element.onerror=()=>{element.remove();reject(new Error("CanopyX: "+part.label+" "+kind+" unavailable."))};document.head.appendChild(withNonce(element))});const link=h("link");link.rel="stylesheet";const style=styleFile&&(part.styleReady||=load(link,"href",hashed?styleFile:"canopyx-"+part.name+".css","stylesheet")
540
540
  .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")
@@ -592,7 +592,7 @@ const wanted=Array.from(new Set(ids||this.rows.filter((w)=>!w.status).map((w)=>w
592
592
  const navigation=navigationScope(this,this.dataLifetime.signal);let doc;try{doc=await navigation.wait(this.source.counts(wanted,this.sourceRequest(this.dataLifetime.signal)))}
593
593
  finally{navigation.dispose()}
594
594
  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}});function UiHost(){}
595
- const UI_IMPL={},UI_TOOLS={},uiInstances=new WeakMap();const UI_KINDS={tabs:"ui-tabs",stepper:"ui-stepper",menu:"ui-menu",dialog:"ui-overlays",drawer:"ui-overlays",popover:"ui-overlays",tooltip:"ui-overlays"};const uiContext=()=>({UI_IMPL,UI_TOOLS,h,setText,fill,watchTheme,overlayTheme,hostHtml});for(const name of["ui-overlays","ui-menu","ui-picker","ui-navigation","ui-tabs","ui-stepper"])SHARED_PARTS[name]=definePart(UiHost,name,name.replace("ui-","UI "),uiContext);function createUi(kind,target,options={}){const root=typeof target==="string"?document.querySelector(target):target;if(root?.nodeType!==1)throw new Error("CanopyX: "+kind+" needs an element.");let registrations=uiInstances.get(root);if(!registrations)uiInstances.set(root,registrations=new Map());if(registrations.has(kind))return registrations.get(kind);const lifetime=new AbortController();watchTheme(root,lifetime.signal);let instance=null;const ready=loadPart(SHARED_PARTS[UI_KINDS[kind]]).then(()=>{if(lifetime.signal.aborted)throw new DOMException("UI component destroyed.","AbortError");instance=UI_IMPL[kind](root,options,lifetime.signal);return instance.ready||instance});const api={element:root,ready:ready.then(()=>api),destroy(){if(lifetime.signal.aborted)return;lifetime.abort();instance?.destroy?.();registrations.delete(kind)}};for(const name of["select","getSelected","refresh","preparePrint","open","close","next","back","skip","finish","setStepState","getState"])api[name]=(...args)=>{if(lifetime.signal.aborted)throw new Error("CanopyX: UI component destroyed.");return instance?instance[name]?.(...args):ready.then(()=>instance[name]?.(...args))};api.ready.catch(error=>{if(error.name!=="AbortError")root.dispatchEvent(new CustomEvent("canopyx:error",{detail:{error},bubbles:true}))});registrations.set(kind,Object.freeze(api));return api}
595
+ const UI_IMPL={},UI_TOOLS={},uiInstances=new WeakMap();const UI_KINDS={tabs:"ui-tabs",stepper:"ui-stepper",accordion:"ui-accordion",menu:"ui-menu",dialog:"ui-overlays",drawer:"ui-overlays",popover:"ui-overlays",tooltip:"ui-overlays"};const uiContext=()=>({UI_IMPL,UI_TOOLS,h,setText,fill,watchTheme,overlayTheme,hostHtml});for(const name of Object.keys(PARTS).filter(part=>part.startsWith("ui-")))SHARED_PARTS[name]=definePart(UiHost,name,name.replace("ui-","UI "),uiContext);function createUi(kind,target,options={}){const root=typeof target==="string"?document.querySelector(target):target;if(root?.nodeType!==1)throw new Error("CanopyX: "+kind+" needs an element.");let registrations=uiInstances.get(root);if(!registrations)uiInstances.set(root,registrations=new Map());if(registrations.has(kind))return registrations.get(kind);const lifetime=new AbortController();watchTheme(root,lifetime.signal);let instance=null;const ready=loadPart(SHARED_PARTS[UI_KINDS[kind]]).then(()=>{if(lifetime.signal.aborted)throw new DOMException("UI component destroyed.","AbortError");instance=UI_IMPL[kind](root,options,lifetime.signal);return instance.ready||instance});const api={element:root,ready:ready.then(()=>api),destroy(){if(lifetime.signal.aborted)return;lifetime.abort();instance?.destroy?.();registrations.delete(kind)}};for(const name of["select","getSelected","refresh","preparePrint","open","close","next","back","skip","finish","setStepState","getState","toggle","getOpen","filter"])api[name]=(...args)=>{if(lifetime.signal.aborted)throw new Error("CanopyX: UI component destroyed.");return instance?instance[name]?.(...args):ready.then(()=>instance[name]?.(...args))};api.ready.catch(error=>{if(error.name!=="AbortError")root.dispatchEvent(new CustomEvent("canopyx:error",{detail:{error},bubbles:true}))});registrations.set(kind,Object.freeze(api));return api}
596
596
  function bindContextMenu(target,items,options={}){if(typeof target!=="string"&&target?.nodeType!==1)throw new Error("CanopyX: contextMenu needs an element or selector.");if(typeof target==="string")document.documentElement.matches(target);let disposed=false,cleanup=null;const dispose=()=>{disposed=true;cleanup?.()};dispose.ready=loadPart(SHARED_PARTS["ui-menu"]).then(()=>{if(!disposed)cleanup=UI_IMPL.contextMenu(target,items,options)});dispose.open=(...args)=>disposed?false:cleanup?cleanup.open(...args):dispose.ready.then(()=>!disposed&&cleanup.open(...args));dispose.close=(...args)=>cleanup?.close(...args);return dispose}
597
597
  function mountUi(root=document){const mounted=[];for(const kind of Object.keys(UI_KINDS)){const selector="[data-cx-"+kind+"]",nodes=[...root.querySelectorAll(selector)];if(root.matches?.(selector))nodes.unshift(root);for(const element of nodes){if(kind==="menu"&&element.parentElement?.closest(selector))continue;if(kind==="stepper"&&["report","static"].includes(element.dataset.mode))continue;mounted.push(createUi(kind,element))}}
598
598
  return mounted}
@@ -704,11 +704,12 @@ function gridNumberFormat(format){const minimum=format?.minimumFractionDigits??0
704
704
  Object.keys(format).some(key=>!["minimumFractionDigits","maximumFractionDigits","prefix","suffix"].includes(key))||
705
705
  [format.prefix,format.suffix].some(text=>text!==undefined&&(typeof text!=="string"||!text||text.length>16)))throw new Error("CanopyX: invalid number format.")}
706
706
  function validateGridView(view){checkDocument(view,"grid");requireIdentifier(view.id,"grid ID");if([view.board,view.path,view.stack,view.calendar].filter(value=>value!=null).length>1)
707
- throw new Error("CanopyX: choose one grid presentation: board, path, stack or calendar (with optional plan).");view=gridColumnDefaults(view);if(view.allowRegexSearch!==undefined&&typeof view.allowRegexSearch!=="boolean")throw new Error("CanopyX: allowRegexSearch is a boolean.");if(view.rowIdentity!==undefined&&!["stableKey","ordinal"].includes(view.rowIdentity))
708
- throw new Error("CanopyX: rowIdentity must be stableKey or ordinal.");if(view.rowIdentity==="ordinal"&&view.live)
709
- throw new Error("CanopyX: ordinal row identity is snapshot-local; keyed live updates require stable row keys.");if(view.rowIdentity==="ordinal"&&view.record?.deepLink)
710
- 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)
711
- 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)}
707
+ throw new Error("CanopyX: choose one grid presentation: board, path, stack or calendar (with optional plan).");view=gridColumnDefaults(view);if(view.selectOnClick!==undefined&&typeof view.selectOnClick!=="boolean")throw new Error("CanopyX: selectOnClick is a boolean.");if(view.allowRegexSearch!==undefined&&typeof view.allowRegexSearch!=="boolean")throw new Error("CanopyX: allowRegexSearch is a boolean.");const groups=[view.columnBands,view.columnGroups].filter(value=>value!==undefined);if(groups.length>1||groups.some(value=>!Array.isArray(value)))
708
+ throw new Error("CanopyX: choose columnBands or columnGroups as an array.");if(view.rowIdentity!==undefined&&!["stableKey","ordinal"].includes(view.rowIdentity))
709
+ throw new Error("CanopyX: rowIdentity must be stableKey or ordinal.");if(view.rowIdentity==="ordinal"&&(view.live||view.record?.deepLink))
710
+ throw new Error("CanopyX: rowIdentity must be stableKey for live updates or deep links.");if(typeof view.label!=="string"||!view.label.trim()||!Array.isArray(view.columns)||!view.columns.length)
711
+ throw new Error("CanopyX: a grid needs a label and columns.");if(!view.source||typeof view.source!=="object"||!["inline","host"].includes(view.source.kind))
712
+ throw new Error("CanopyX: a grid needs source.kind inline or host.");if(view.reporting!==undefined){if(!GRID_REPORTING.validate)throw new Error("CanopyX: this view needs the reporting runtime.");GRID_REPORTING.validate(view)}
712
713
  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)||
713
714
  column.headerDescription!==undefined&&typeof column.headerDescription!=="string"||
714
715
  column.width!==undefined&&(!Number.isInteger(column.width)||column.width<40)||
@@ -723,17 +724,18 @@ column.section!==undefined&&(typeof column.section!=="string"||!column.section.t
723
724
  throw new Error("CanopyX: invalid column aggregate or drawer section.")}
724
725
  if(view.columns.every(column=>column.hidden)||view.columns.filter(column=>column.rowHeader).length>1)
725
726
  throw new Error("CanopyX: a grid needs a visible column and one row header at most.");if(view.density!==undefined&&!["compact","default","comfortable"].includes(view.density)||
726
- ["zebra","statusBar","autoHeight","rowAccents"].some(name=>view[name]!==undefined&&typeof view[name]!=="boolean")||
727
+ ["zebra","statusBar","autoHeight","rowAccents","recordDrawerModal"].some(name=>view[name]!==undefined&&typeof view[name]!=="boolean")||
727
728
  view.rowAction!==undefined&&!["none","details","link"].includes(view.rowAction)||
728
729
  view.noun!==undefined&&(typeof view.noun!=="string"||!view.noun.trim()||view.noun.length>256)||
729
730
  view.emptyReason!==undefined&&(typeof view.emptyReason!=="string"||view.emptyReason.length>4096))throw new Error("CanopyX: invalid grid appearance or state text.");validateGridHighlights(view);if(view.searchDelayMs!==undefined&&(!Number.isInteger(view.searchDelayMs)||view.searchDelayMs<0||view.searchDelayMs>5000))
730
731
  throw new Error("CanopyX: search delay must be an integer from 0 to 5000 milliseconds.");if(view.searchColumns!==undefined&&(!Array.isArray(view.searchColumns)||!view.searchColumns.length||
731
732
  new Set(view.searchColumns).size!==view.searchColumns.length||view.searchColumns.some(id=>!ids.has(id))))
732
- throw new Error("CanopyX: search columns must identify unique declared columns.");if(view.exportFormats!==undefined&&!exportFormatIds(view.exportFormats))throw new Error("CanopyX: exportFormats lists unique format IDs.");if(view.autoRowHeight!==undefined&&typeof view.autoRowHeight!=="boolean"||
733
- view.rowHeight!==undefined&&view.rowHeight!=="auto"&&(!Number.isInteger(view.rowHeight)||view.rowHeight<20||view.rowHeight>64)||
734
- view.estimatedRowHeight!==undefined&&(!Number.isInteger(view.estimatedRowHeight)||view.estimatedRowHeight<20||view.estimatedRowHeight>64)||
735
- !Number.isInteger(view.pageSize)||view.pageSize<1||view.pageSize>10000||
736
- !["none","single","multiple"].includes(view.selection))throw new Error("CanopyX: invalid grid sizing or selection.");if(!view.source||!["inline","host"].includes(view.source.kind))throw new Error("CanopyX: grid source must be inline or host.");if(view.calculatedColumnsEditable!==undefined&&(typeof view.calculatedColumnsEditable!=="boolean"||view.calculatedColumnsEditable&&view.source.kind!=="inline"))
733
+ throw new Error("CanopyX: search columns must identify unique declared columns.");if(view.exportFormats!==undefined&&!exportFormatIds(view.exportFormats))throw new Error("CanopyX: exportFormats lists unique format IDs.");if(!Number.isInteger(view.pageSize)||view.pageSize<1||view.pageSize>10000)
734
+ throw new Error("CanopyX: pageSize must be 1 to 10000.");if(!["none","single","multiple"].includes(view.selection))
735
+ throw new Error("CanopyX: selection must be none, single or multiple.");if(view.autoRowHeight!==undefined&&typeof view.autoRowHeight!=="boolean")
736
+ throw new Error("CanopyX: autoRowHeight is a boolean.");if(view.rowHeight!==undefined&&view.rowHeight!=="auto"&&(!Number.isInteger(view.rowHeight)||view.rowHeight<20||view.rowHeight>64))
737
+ throw new Error("CanopyX: rowHeight must be auto or 20 to 64.");if(view.estimatedRowHeight!==undefined&&(!Number.isInteger(view.estimatedRowHeight)||view.estimatedRowHeight<20||view.estimatedRowHeight>64))
738
+ throw new Error("CanopyX: estimatedRowHeight must be 20 to 64.");if(view.calculatedColumnsEditable!==undefined&&(typeof view.calculatedColumnsEditable!=="boolean"||view.calculatedColumnsEditable&&view.source.kind!=="inline"))
737
739
  throw new Error("CanopyX: the calculated-column editor requires an inline grid.");if(view.source.navigation!==undefined&&!["offset","cursor"].includes(view.source.navigation))
738
740
  throw new Error("CanopyX: invalid grid source navigation.");if(view.source.navigation==="cursor"&&(view.source.kind!=="host"||view.presentation!=="paged"))
739
741
  throw new Error("CanopyX: cursors need a hosted paged grid.");if(view.presentation!==undefined&&!["continuous","paged"].includes(view.presentation)||
@@ -807,8 +809,8 @@ throw new Error("CanopyX: facet counts contradict the known accepted dataset cou
807
809
  throw new Error("CanopyX: invalid facet value/count bucket.");const key=gridFacetKey(item.value,column);if(keys.has(key))throw new Error("CanopyX: duplicate typed facet bucket.");keys.add(key);occurrences +=item.count;return{value:item.value,count:item.count}});if(occurrences>input.matched||!request.search&&!input.truncated&&occurrences!==input.matched)
808
810
  throw new Error("CanopyX: facet buckets contradict the matching row count.");return gridFreeze({protocol:PROTOCOL,type:"gridFacetPage",view:input.view,revision:input.revision,column:input.column,search:input.search,includeCurrentFilter:input.includeCurrentFilter,matched:input.matched,totalValues:input.totalValues,truncated:input.truncated,items,...(request.bucket?{bucket:request.bucket}:{})})}
809
811
  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)
810
- 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=[]}
811
- 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"))
812
+ throw new Error("CanopyX: rowIdentity must be stableKey for live updates or deep links.");if(rows)this.view.rows=owned?rows:JSON.parse(JSON.stringify(rows));if(rowData){this.view.rowData=owned?rowData:structuredClone(rowData);this.view.rows=[]}
813
+ this.selectOnClick=this.view.selectOnClick===true;this.host=host;this.opts=options;do{this.id="cx" + ++instanceSeq}while(document.getElementById(this.id));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"))
812
814
  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||
813
815
  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?
814
816
  this.view.source.kind==="inline"?0:300:this.view.searchDelayMs:options.searchDelayMs;if(!Number.isInteger(this.searchDelayMs)||this.searchDelayMs<0||this.searchDelayMs>5000)
@@ -826,12 +828,12 @@ async setQuery(input,paging){if(this.destroyed)throw new DOMException("Grid was
826
828
  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;
827
829
  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);
828
830
  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)}}
829
- gridOperationActive(this,lifetime.signal);const hadFocus=this.canvas.contains(document.activeElement),previousId=this.focused&&this.focused.key;const retireSelection=this.view.rowIdentity==="ordinal"&&this.snapshot&&this.snapshot.revision!==page.revision;this.pages.clear();this.rowCache.clear();this.placeholders.clear();this.focused=null;this.acceptedQuery=gridQuery(this.view,{...query,revision:page.revision});this.snapshot={revision:page.revision,total:page.total,matched:page.matched};if(retireSelection)this.clearSnapshotSelection();this.pageLength=length;if(paging)this.pageAll=!!paging.allRows;this.pageOffset=this.cursor?page.offset:this.paged?query.offset:0;if(this.cursor)this.cursorWindow={end:page.offset+page.items.length,next:page.nextCursor,previous:page.previousCursor};if(this.autoRows){if(!same)this.rowHeights.clear();this.rowOffsets=null}
831
+ gridOperationActive(this,lifetime.signal);const hadFocus=this.canvas.contains(document.activeElement),previousId=this.focused&&this.focused.key;const retireSelection=this.view.rowIdentity==="ordinal"&&this.snapshot&&this.snapshot.revision!==page.revision;if(!same||this.snapshot?.revision!==page.revision)this.selectionAnchor=null;this.pages.clear();this.rowCache.clear();this.placeholders.clear();this.focused=null;this.acceptedQuery=gridQuery(this.view,{...query,revision:page.revision});this.snapshot={revision:page.revision,total:page.total,matched:page.matched};if(retireSelection)this.clearSnapshotSelection();this.pageLength=length;if(paging)this.pageAll=!!paging.allRows;this.pageOffset=this.cursor?page.offset:this.paged?query.offset:0;if(this.cursor)this.cursorWindow={end:page.offset+page.items.length,next:page.nextCursor,previous:page.previousCursor};if(this.autoRows){if(!same)this.rowHeights.clear();this.rowOffsets=null}
830
832
  this.storePage(page);this.pendingQuery=null;this.pendingPaging=null;this.lastFailedQuery=null;this.lastFailedPaging=null;this.version++;const hasRows=this.cursor?page.items.length:page.matched;this.total=(this.cursor?page.items.length:this.paged?Math.min(length,page.matched-this.pageOffset):page.matched)*this.rowH;this.grid.setAttribute("aria-rowcount",page.matched===null?"-1":String(page.matched+1 +(this.headDepth||0)));this.grid.tabIndex=hasRows?-1:0;this.syncScrollRange(this.paged?0:query.offset*this.rowH);this.buildHeader();this.syncColumnControls();this.setNotice(hasRows?"":this.labels.searchNoResults,false);this.grid.setAttribute("aria-busy","false");if(hadFocus||this.focusOrigin){this.focused=[...this.rowCache.values()].find(row=>row.key===previousId)||this.rowCache.get(this.cursor?page.offset:query.offset)||null}
831
833
  this.render();if(hadFocus){const element=this.focused&&this.rendered.get(this.focused);(element||this.grid).focus({preventScroll:true})}
832
834
  this.host.setAttribute("data-cx-ready","true");if(this.searchInput&&!this.searchComposing&&this.searchTimer==null)this.searchInput.value=query.search;if(this.searchInput){const label=query.searchMode==="regex"?this.labels.gridRegexSearch:this.view.noun?
833
835
  fill(this.labels.gridSearchNoun,{noun:this.noun}):this.labels.searchPlaceholder;this.searchInput.placeholder=label;this.searchInput.setAttribute("aria-label",label);this.searchInput.maxLength=query.searchMode==="regex"?256:524288;this.searchInput.setCustomValidity("")}
834
- 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){const cancelled=lifetime.signal.aborted&&error?.name==="AbortError";this.pendingQuery=null;this.pendingPaging=null;this.lastFailedQuery=cancelled?null:initial;this.lastFailedPaging=cancelled?null:{...paging,pageLength:length};this.dataLifetime.abort();this.dataLifetime=new AbortController();this.grid.setAttribute("aria-busy","false");this.setNotice(cancelled?"":fill(this.labels.queryFailed,{error:error.message}),!cancelled);this.syncPager();if(!cancelled)this.emit("error",{error})}
836
+ this.syncQuerySummary();this.syncPager();this.fitHeight();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){const cancelled=lifetime.signal.aborted&&error?.name==="AbortError";this.pendingQuery=null;this.pendingPaging=null;this.lastFailedQuery=cancelled?null:initial;this.lastFailedPaging=cancelled?null:{...paging,pageLength:length};this.dataLifetime.abort();this.dataLifetime=new AbortController();this.grid.setAttribute("aria-busy","false");this.setNotice(cancelled?"":fill(this.labels.queryFailed,{error:error.message}),!cancelled);this.syncPager();this.fitHeight();if(!cancelled)this.emit("error",{error})}
835
837
  throw error}}
836
838
  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(()=>{})}
837
839
  sort(sorts){return this.setQuery(gridQueryStart(this.queryForChange(true),{sort:sorts}))}
@@ -844,12 +846,12 @@ indexOf(row){if(!row||this.paged&&(row._ri<this.pageOffset||row._ri>=this.pageOf
844
846
  rowItem(index){if(index<0||index>=this.rowCount()||this.paged&&(index<this.pageOffset||index>=this.pageOffset+this.pageLength))return null;if(this.rowCache.has(index))return this.rowCache.get(index);if(!this.placeholders.has(index))this.placeholders.set(index,{_ri:index,hpx:this.rowH,status:"loading",h:{cells:{}}});const row=this.placeholders.get(index),page=this.pages.get(Math.floor(index / this.pageSize) * this.pageSize);
845
847
  row.status=page&&page.error?"error":"loading";return row}
846
848
  render(){if(this.destroyed||!this.sized)return;let measured=false;if(this.autoRows)this.syncRowOffsets();for(let pass=0;;pass++){this.renderPass();if(!this.autoRows||!this.measureGridRows())break;measured=true;if(pass===3){this.scheduleRender();break}}
847
- for(const[index,row]of this.placeholders)if(!this.rendered.has(row)&&this.focused!==row)this.placeholders.delete(index);this.loadWindow();const origin=this.focusOrigin;if(origin&&this.hasGridSize()){this.focusOrigin=null;if(document.activeElement===origin)(this.rendered.get(this.focused)||this.grid).focus({preventScroll:true})}
849
+ this.syncGridPhoneValues?.();for(const[index,row]of this.placeholders)if(!this.rendered.has(row)&&this.focused!==row)this.placeholders.delete(index);this.loadWindow();const origin=this.focusOrigin;if(origin&&this.hasGridSize()){this.focusOrigin=null;if(document.activeElement===origin)(this.rendered.get(this.focused)||this.grid).focus({preventScroll:true})}
848
850
  return measured}
849
851
  observeDetail(){}
850
852
  trimInactiveCache(){this.trimPages()}
851
853
  clearSnapshotSelection(){const changed=this.selected.size||this.querySelection;this.selectionController?.abort();this.selectionAnchor=null;this.querySelection=null;this.selectionExcluded=null;this.selected.clear();if(changed){this.version++;this.scheduleRender();this.emit("select",{ids:[]});this.syncGridChrome()}}
852
- setSelection(ids){if(this.destroyed)return;if(!Array.isArray(ids))throw new Error("CanopyX: selection must be an array of row IDs.");ids.forEach(id=>requireIdentifier(id,"selection ID"));const next=new Set(ids);if(this.view.selection==="none"&&next.size||!this.multi&&next.size>1)throw new Error("CanopyX: selection exceeds the view's mode.");this.selected=next;this.version++;this.scheduleRender();this.emit("select",{ids:[...next]});this.syncGridChrome();this.stateChanged()}
854
+ setSelection(ids){if(this.destroyed)return;if(!Array.isArray(ids))throw new Error("CanopyX: selection must be an array of row IDs.");ids.forEach(id=>requireIdentifier(id,"selection ID"));const next=new Set(ids);if(this.view.selection==="none"&&next.size||!this.multi&&next.size>1)throw new Error("CanopyX: selection exceeds the view's mode.");this.selectionController?.abort();this.selectionAnchor=null;this.selected=next;this.version++;this.scheduleRender();this.emit("select",{ids:[...next]});this.syncGridChrome();this.stateChanged()}
853
855
  setColumnVisible(id,visible){const column=this.columns.find(item=>item.id===id);if(!column||typeof visible!=="boolean")throw new Error("CanopyX: visibility needs a declared column and boolean.");if(!visible&&this.columns.filter(item=>!item.hidden).length===1&&!column.hidden)throw new Error("CanopyX: keep at least one column visible.");column.hidden=!visible;this.buildHeader();this.version++;this.scheduleRender();this.stateChanged();this.syncColumnControls()}
854
856
  destroy(){if(this.destroyed)return;this.writeStoredState(this.getState());this.destroyed=true;this.queryEpoch++;this.lifetime.abort();this.dataLifetime.abort();this.focusOrigin=null;for(const row of[...this.rendered.values(),...this.pool])disposeRowHostCells(row);if(this.rafId)cancelAnimationFrame(this.rafId);clearTimeout(this.searchTimer);this.searchTimer=null;clearTimeout(this.stateTimer);if(this.disposeControls)this.disposeControls();if(this.cancelResize)this.cancelResize();this.resizeObserver.disconnect();this.detailObserver?.disconnect();this.rowHeights?.clear();this.rowOffsets=null;this.restoreHeight();this.host.classList.remove("cx-data-grid","cx-chrome","cx-phone","cx-has-selection","cx-scroll-left","cx-scroll-right","cx-grid-awaiting","cx-pins");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);this.pages.clear();this.rowCache.clear();this.placeholders.clear();this.pendingPages.clear();this.rendered.clear();this.pool.length=0;this.toolbar.remove();this.grid.remove();this.notice.remove();this.live.remove();this.querySummary?.remove();if(this.pager)this.pager.remove();this.statusBar?.remove();this.groupBar?.remove();this.statusAggregateController?.abort();this.host.removeAttribute("data-cx-ready");this.host.removeAttribute("data-canopyx-mounted")}}
855
857
  Object.assign(DataGrid.prototype,ROW_SCROLLING,ROW_DOM_ORDER,ROW_VIEWPORT,ROW_HELPERS);Object.assign(DataGrid.prototype,{requestPage(query,signal){return this.runGridHook(signal=>this.source.query(query,{signal}),signal)},storePage(page){const rows=page.items.map((item,i)=>({key:item.id,h:item,_ri:page.offset+i,hpx:this.rowH}));const incoming=new Map(rows.map(row=>[row.key,row._ri]));for(const cached of this.rowCache.values())if(incoming.has(cached.key)&&incoming.get(cached.key)!==cached._ri)
@@ -896,9 +898,10 @@ this.canvas.addEventListener("focusin",event=>{const element=event.target.closes
896
898
  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()){if(host.clientWidth&&host.checkVisibility())this.updateGridPhone();this.sized=false;return}
897
899
  if(this.fitContentWidth===0)return;if(host.classList.contains("cx-grid-awaiting"))grid.style.setProperty("--cx-empty-head-height",Math.max(this.phone?44:0,this.head.offsetHeight+grid.offsetHeight-grid.clientHeight)+ "px");style.setProperty("--cx-min-h",this.minimumGridHeight()+ "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)}
898
900
  if(grid.style.opacity){this.render();grid.style.opacity=""}
899
- else this.scheduleRender()};cancelAnimationFrame(resizeFrame);resizeFrame=requestAnimationFrame(resize)});this.resizeObserver.observe(grid);this.resizeObserver.observe(this.head);this.resizeObserver.observe(host)},minimumGridHeight(){if(this.toolbar.hidden)return 0;return[...this.host.children].reduce((height,child)=>{if(child===this.grid)return height;const css=getComputedStyle(child);if(css.position==="absolute"||css.position==="fixed")return height;let block=child.offsetHeight;if(child===this.notice&&child.classList.contains("cx-state")){const items=[...child.children];block=(items.length?items.at(-1).getBoundingClientRect().bottom-items[0].getBoundingClientRect().top:0)+
900
- parseFloat(css.paddingTop)+ parseFloat(css.paddingBottom)}
901
- return height+block},Math.max(this.head.offsetHeight,this.rowH*Math.min(4,Math.max(1,this.rowCount())))+ 2)},setLogicalTop(top){if(!this.hasGridSize()){this.hiddenScrollTop=top;return}
901
+ else this.scheduleRender()};cancelAnimationFrame(resizeFrame);resizeFrame=requestAnimationFrame(resize)});this.resizeObserver.observe(grid);this.resizeObserver.observe(this.head);this.resizeObserver.observe(host)},minimumGridHeight(rows=true){if(rows&&this.toolbar.hidden)return 0;const host=getComputedStyle(this.host);let count=0;const height=[...this.host.children].reduce((sum,child)=>{const css=getComputedStyle(child);if(css.display==="none"||css.position==="absolute"||css.position==="fixed")return sum;count++;let block=child===this.grid?0:child.offsetHeight;if(child===this.notice&&child.classList.contains("cx-state")){block=(child.lastElementChild?child.lastElementChild.getBoundingClientRect().bottom-child.firstElementChild.getBoundingClientRect().top:0)+
902
+ parseFloat(css.paddingTop)+ parseFloat(css.paddingBottom)+ child.offsetHeight-child.clientHeight;block=Math.max(block,parseFloat(css.minHeight)||0)}
903
+ return sum+block+parseFloat(css.marginTop)+ parseFloat(css.marginBottom)},rows?Math.max(this.head.offsetHeight,this.rowH*Math.min(4,Math.max(1,this.rowCount())))+ 2:0);return height+this.host.offsetHeight-this.host.clientHeight+parseFloat(host.paddingTop)+ parseFloat(host.paddingBottom)
904
+ + Math.max(0,count-1)*(parseFloat(host.rowGap)||0)},setLogicalTop(top){if(!this.hasGridSize()){this.hiddenScrollTop=top;return}
902
905
  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(/ +/));
903
906
  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)}
904
907
  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)}
@@ -929,9 +932,13 @@ this.total=this.rowOffsets.top(count);this.syncScrollRange(this.logicalTop());th
929
932
  if(changed){this.total=this.rowOffsets.top(this.rowOffsets.count);this.syncScrollRange(rows.rowTop(anchor.index)+ anchor.offset)}
930
933
  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));
931
934
  const proposed=rows.rowAt(Math.max(0,rows.rowTop(index)+ direction*(this.grid.clientHeight-this.head.offsetHeight)));return direction>0?Math.max(index+1,proposed):Math.min(index-1,proposed)}});const HEIGHT_RENDER=DataGrid.prototype.render;DataGrid.prototype.render=function(){const measured=HEIGHT_RENDER.call(this);if(this.sized&&this.total!==this.fitTotal){this.fitTotal=this.total;this.fitHeight()}
932
- return measured};DataGrid.prototype.fitHeight=function(){if(this.view.autoHeight===false||this.pendingQuery||!this.grid.clientWidth||!this.host.checkVisibility())return;const grid=this.grid,style=this.host.style,box=grid.getBoundingClientRect(),computed=getComputedStyle(grid);const borders=parseFloat(computed.borderTopWidth)+ parseFloat(computed.borderBottomWidth);const scrollbar=Math.max(0,grid.offsetHeight-grid.clientHeight-borders);const content=[...grid.children].reduce((sum,child)=>{const position=getComputedStyle(child).position;return position==="absolute"||position==="fixed"?sum:sum+child.getBoundingClientRect().height},borders+scrollbar);if(this.fitInline===undefined){const own=getComputedStyle(this.host).maxHeight;this.fitInline=style.maxHeight;this.fitMax=own==="none"||!own?Infinity:/^-?[\d.]+px$/.test(own) ? parseFloat(own) : own;
933
- }
934
- const hostStyle=getComputedStyle(this.host);const chrome=[...this.host.children].filter(child=>child!==grid).reduce((sum,child)=>{const css=getComputedStyle(child);return css.position==="absolute"||css.position==="fixed"?sum:sum+child.getBoundingClientRect().height},parseFloat(hostStyle.borderTopWidth)+ parseFloat(hostStyle.borderBottomWidth)+ parseFloat(hostStyle.paddingTop)+ parseFloat(hostStyle.paddingBottom));const height=Math.ceil(Math.max(this.host.getBoundingClientRect().height-box.height,chrome)+ content),bound=this.fitMax;const value=!this.rowCount()?this.fitInline:typeof bound==="number"?Math.min(bound,height)+ "px":"min("+height+"px, "+bound+")";if(this.host.style.maxHeight!==value)this.host.style.maxHeight=value};function gridPriority(value){return["essential","normal","optional"].includes(value)||Number.isInteger(value)&&value>=0&&value<=MAX_PROTOCOL_INTEGER}
935
+ return measured};DataGrid.prototype.fitHeight=function(){if(this.view.autoHeight===false||this.pendingQuery||!this.grid.clientWidth||!this.host.checkVisibility())return;const grid=this.grid,style=this.host.style;const content=[...grid.children].reduce((sum,child)=>{const position=getComputedStyle(child).position;return position==="absolute"||position==="fixed"?sum:sum+child.getBoundingClientRect().height},grid.offsetHeight-grid.clientHeight);if(this.fitInline===undefined){this.fitInline=style.maxHeight;global.addEventListener("resize",()=>this.fitHeight(),{signal:this.lifetime.signal})}
936
+ if(/var\(/i.test(this.fitInline) && !this.fitBoundObserver) {
937
+ const observer=this.fitBoundObserver=new MutationObserver(records=>{if(records.some(record=>record.target!==this.host||record.attributeName==="class")||this.fitStyle!==style.cssText)this.fitHeight()});this.lifetime.signal.addEventListener("abort",()=>observer.disconnect(),{once:true})}
938
+ if(this.fitBoundObserver&&this.fitBoundParent!==this.host.parentElement){this.fitBoundObserver.disconnect();for(let parent=this.host;parent;parent=parent.parentElement)
939
+ this.fitBoundObserver.observe(parent,{attributes:true,attributeFilter:["style","class"]});this.fitBoundParent=this.host.parentElement}
940
+ const fitted=style.maxHeight;style.maxHeight=this.fitInline;const resolved=getComputedStyle(this.host).maxHeight;this.fitMax=resolved==="none"||/^(initial|inherit|unset|revert(-layer)?)$/.test(this.fitInline) ? resolved : this.fitInline || resolved;
941
+ style.maxHeight=fitted;const empty=!this.toolbar.hidden&&this.host.classList.contains("cx-grid-awaiting");const height=Math.ceil(Math.max(empty?0:this.host.getBoundingClientRect().height-grid.getBoundingClientRect().height,this.minimumGridHeight(false))+ content),bound=this.fitMax;const value=this.rowCount()||empty?bound==="none"?height+"px":"min("+height+"px, "+bound+")":this.fitInline;if(empty||this.fitEmpty)style.setProperty("--cx-min-h",empty?value:this.minimumGridHeight()+ "px");this.fitEmpty=empty;if(style.maxHeight!==value)style.maxHeight=value;this.fitStyle=style.cssText};function gridPriority(value){return["essential","normal","optional"].includes(value)||Number.isInteger(value)&&value>=0&&value<=MAX_PROTOCOL_INTEGER}
935
942
  function gridRank(column){const value=column.priority;return typeof value==="number"?value:value==="optional"?10000:value==="essential"||value===undefined&&column.identity?0:5000}
936
943
  function gridLevel(column){const rank=gridRank(column);return rank<2?0:rank<10000?1:2}
937
944
  function gridOptions(column){return column.presenter||{}}
@@ -992,7 +999,7 @@ return result};function validateGridHighlights(view){if(view.highlightRules===un
992
999
  rule.target!==undefined&&!["row","cell"].includes(rule.target)||rule.tone===undefined&&rule.className===undefined)
993
1000
  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)}}
994
1001
  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)}
995
- 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;
1002
+ 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-primary,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;
996
1003
  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}
997
1004
  if(rule){slot.cell.title=rule.label;slot.title=rule.label}
998
1005
  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((options.kind==="progress"||options.kind==="change"&&!options.beforeAfter)&&column.kind!=="number"||
@@ -1021,7 +1028,8 @@ row.loadingAt??=performance.now();const wait=150-(performance.now()-row.loadingA
1021
1028
  const cell=element._cells[0].cell;element._cells[0].text.data="";if(element._skeleton?.isConnected)return;const skeleton=element._skeleton=h("span","cx-skel");skeleton.setAttribute("aria-hidden","true");for(const column of this.cols){const span=h("span"),bar=h("i");span.style.width=column.renderWidth+"px";span.appendChild(bar);skeleton.appendChild(span)}cell.appendChild(skeleton)},buildGridStatus(){if(!this.view.statusBar)return;this.statusBar=h("div","cx-grid-status");this.statusCount=h("span");this.statusAggregates=h("span","agg");this.statusBar.setAttribute("role","status");this.statusBar.append(this.statusCount,this.statusAggregates);this.host.appendChild(this.statusBar)},async syncGridStatus(){if(!this.statusBar)return;const count=this.querySelection?this.querySelection.matched==null?null:Math.max(0,this.querySelection.matched-this.selectionExcluded.size):this.selected.size;const number=numberFormat(this.lang);gridCountLabel(this.statusCount,this.labels.gridStatusCount,{count:this.snapshot?.matched==null?"—":number.format(this.snapshot.matched),noun:this.noun,selected:count==null?"—":number.format(count)});const columns=this.columns.filter(column=>column.aggregatable&&column.exportable!==false),key=JSON.stringify([this.queryEpoch,this.snapshot?.revision,count,[...this.selected],this.querySelection?.query,[...(this.selectionExcluded||[])],columns.map(column=>column.id)]);if(key===this.statusAggregateKey)return;this.statusAggregateKey=key;this.statusAggregateController?.abort();this.statusAggregates.replaceChildren();if(!columns.length||count===0||!this.acceptedQuery)return;try{await loadGridFilterEditor();if(!this.destroyed&&this.statusAggregateKey===key)await this.calculateGridAggregates(columns)}
1022
1029
  catch(error){if(!this.destroyed&&this.statusAggregateKey===key)setText(this.statusAggregates,this.labels.gridNoData)}}});Object.assign(DataGrid.prototype,{setFocus(row,focus){this.pendingNavigation=null;if(!row||this.indexOf(row)<0||this.destroyed)return;if(focus)this.focusOrigin=null;this.focused=row;this.revealGridRow(row,row._ri);if(this.render()){this.revealGridRow(row,row._ri);this.render()}
1023
1030
  if(focus){const element=this.rendered.get(row);if(this.hasGridSize()&&element)element.focus({preventScroll:true});else{this.focusOrigin=document.activeElement;this.scheduleRender()}}},onClick(event){const element=event.target.closest(".cx-row"),row=element&&element._w,link=event.target.closest("a.p-link");if(row&&link&&!this.emit("link",{id:row.key,row:gridFreeze(JSON.parse(JSON.stringify(row.h))),href:link.href,column:this.visibleColumns()[this.rowCells(element).findIndex(cell=>cell.contains(link))]?.id}))event.preventDefault();if(!row||event.defaultPrevented||event.target.closest("a,button,input,select,textarea,[contenteditable]"))return;this.setFocus(row,true);if(row.status){if(row.status==="error")this.retry().catch(()=>{});return}
1024
- const action=event.detail<2&&this.clickAction(element);if(action)this.activateRow(row,false,action!==true&&action,event)},clickAction(element){return this.view.rowAction==="link"&&element.querySelector("a[href]")||this.phone||this.view.rowAction==="details"},activateRow(row,keyboard,link,event={}){if(this.emit("rowActivate",{id:row.key,row:gridFreeze(JSON.parse(JSON.stringify(row.h))),keyboard}))link?
1031
+ if(this.selectOnClick&&this.view.selection!=="none"){if(event.detail<2)this.selectClickedRow(row,event);return}
1032
+ const action=event.detail<2&&this.clickAction(element);if(action)this.activateRow(row,false,action!==true&&action,event)},selectClickedRow(row,event){if(this.pendingQuery)return;const additive=this.multi&&(event.ctrlKey||event.metaKey);if(this.multi&&event.shiftKey&&this.selectionAnchor!=null){this.selectRowRange(this.selectionAnchor,row._ri,{additive}).catch(error=>{if(error.name!=="AbortError")this.emit("error",{error})})}else{this.selectionController?.abort();const next=additive?new Set(this.selected):new Set();if(next.has(row.key))next.delete(row.key);else next.add(row.key);this.setSelection([...next]);this.selectionAnchor=row._ri}},clickAction(element){return this.view.rowAction==="link"&&element.querySelector("a[href]")||this.phone||this.view.rowAction==="details"},activateRow(row,keyboard,link,event={}){if(this.emit("rowActivate",{id:row.key,row:gridFreeze(JSON.parse(JSON.stringify(row.h))),keyboard}))link?
1025
1033
  link.dispatchEvent(new MouseEvent("click",{bubbles:true,cancelable:true,ctrlKey:event.ctrlKey,metaKey:event.metaKey,shiftKey:event.shiftKey})):
1026
1034
  Promise.resolve().then(()=>this.openDetails(row.key)).catch(error=>this.emit("error",{error}))},onKey(event){const element=event.target.closest(".cx-row"),row=element&&element._w;if(!row||event.defaultPrevented||event.isComposing||event.altKey)return;const cells=this.rowCells(element),navigation=this.pendingNavigation;const pendingPage=navigation&&navigation.focus&&navigation.epoch===this.queryEpoch&&this.pendingQuery&&
1027
1035
  this.pendingPageNavigation&&this.pendingPageNavigation.epoch===this.queryEpoch&&this.focused===row;let column=cells.findIndex(cell=>cell.contains(event.target));if(pendingPage||row.status&&navigation&&navigation.epoch===this.queryEpoch&&navigation.index===row._ri&&navigation.focus)
@@ -1064,13 +1072,13 @@ const parsed=typeof value==="string"&&/^\d{4}-\d\d-\d\dT\d\d:\d\d/.test(value) ?
1064
1072
  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.")}
1065
1073
  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")}
1066
1074
  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)}
1067
- 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})}
1075
+ 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"]};const opensOnTimeline=pick("view")==="timeline";if(opensOnTimeline&&options.timeline===false)throw new Error("CanopyX: a calendar that opens on the timeline cannot set timeline: false.");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||opensOnTimeline||options.preset==="scheduler"))addTimeline();if(options.preset==="scheduler")calendar.capacity={thresholds:[{at:3,tone:"warning"},{at:5,tone:"danger"}]}}else if(options.timeline||opensOnTimeline)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})}
1068
1076
  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)}
1069
1077
  return roots}
1070
1078
  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:"Refine",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,GRID_BUCKETS,gridBucketDefinition}));Object.assign(DataGrid.prototype,{loadFacets(){return this.facetLoad||=Promise.resolve().then(async()=>{if((this.opts.facets?.columns||this.view.facets?.columns)?.some(facet=>facet?.bucket))await loadPart(BUCKETS_PART);await loadPart(GRID_FACETS);if(!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")
1071
1079
  throw new Error("CanopyX: invalid saved facet panel state.");if(this.view.facets||this.opts.facets)state.facets={open:facets.open}}
1072
1080
  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}
1073
- 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,gridVariant,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,GRID_CALCULATIONS,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())
1081
+ 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,gridVariant,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,GRID_CALCULATIONS,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,validateGridPage,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)};DataGrid.prototype.selectRowRange=async function(start,end,options={}){this.selectionController?.abort();const controller=this.selectionController=new AbortController(),epoch=this.queryEpoch;try{await loadPart(GRID_OPTIONS_PART);if(controller.signal.aborted||epoch!==this.queryEpoch)throw new DOMException("Selection was superseded.","AbortError");return await this.readSelectionRange(start,end,options,controller)}finally{controller.abort();if(this.selectionController===controller)this.selectionController=null}};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())
1074
1082
  .catch(error=>{this.pager.hidden=this.opts.toolbar===false;this.emit("error",{error})})]).then(([result])=>result)};const GRID_PATH=definePart(DataGrid,"path","path view",()=>({DataGrid,h,setText,fill,cellValue,cellText,badgeElement,applyTone,toneOf,PROTOCOL}));const GRID_PATH_INIT=DataGrid.prototype.initializeState;DataGrid.prototype.initializeState=function(){const start=()=>this.destroyed?undefined:GRID_PATH_INIT.call(this);return this.view.path?loadPart(GRID_PATH).then(()=>{if(!this.destroyed)this.validatePathSource()}).then(start).then(async result=>{if(!this.destroyed)await this.startPath();return result}):start()};const GRID_PLAN=definePart(DataGrid,"plan","plan view",()=>({DataGrid,h,setText,fill,cellValue,cellText,gridFreeze}));const GRID_PLAN_INIT=DataGrid.prototype.initializeState;DataGrid.prototype.initializeState=function(){const start=()=>GRID_PLAN_INIT.call(this);return this.view.plan?loadPart(GRID_PLAN).then(async()=>{this.validatePlanDefinition();const result=await start();if(this.view.rowData&&!this.opts.source){await this.source.decoded;this.validatePlanDefinition(true)}
1075
1083
  return result}):start()};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")||
1076
1084
  !!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,repairGridCell,inlineGridSource,loadSidecar,gridIdOrder,gridInlineRevision}));function rowDataSource(grid){let inner=null;const source={reset:()=>{inner=null},query:(query,options)=>
@@ -1087,14 +1095,14 @@ const CHANGES_IMPL={},activeChangeViews=new WeakMap();const CHANGES_PART=defineP
1087
1095
  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)}
1088
1096
  catch(error){showError(error);throw error}}
1089
1097
  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);if(kind==="propagation")bindTimeSlider(api,options,kind,value=>CHANGES_IMPL.validatePropagation(value),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}}
1090
- 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,bindContextMenu});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)})}}}
1091
- 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};const GRID_COMPARE=definePart(DataGrid,"compare","dataset comparison",()=>({DataGrid,h,setText,fill,plural,cellValue,numberFormat,gridQueryStart,gridQuery}));const GRID_VIEW_INTENTS=definePart(DataGrid,"view-intents","view intents",()=>({DataGrid,h,setText,fill,gridButton,gridVariant,gridQuery,gridQueryStart,gridFreeze,GRID_FILTER_LABELS,GRID_REPORTING,watchOverlayTheme}));for(const name of["getViewIntent","validateViewIntent","previewViewIntent","applyViewIntent"]){const stub=DataGrid.prototype[name]=function(...args){return loadPart(GRID_VIEW_INTENTS).then(()=>{if(this.destroyed)throw new DOMException("Grid was destroyed.","AbortError");if(DataGrid.prototype[name]===stub)throw new Error("CanopyX: view intents did not install "+name+".");return this[name](...args)})}}
1098
+ 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,bindContextMenu});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"],["column-groups","getColumnBands"],["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)})}}}
1099
+ 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.columnBands??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};const GRID_COMPARE=definePart(DataGrid,"compare","dataset comparison",()=>({DataGrid,h,setText,fill,plural,cellValue,numberFormat,gridQueryStart,gridQuery}));const GRID_VIEW_INTENTS=definePart(DataGrid,"view-intents","view intents",()=>({DataGrid,h,setText,fill,gridButton,gridVariant,gridQuery,gridQueryStart,gridFreeze,GRID_FILTER_LABELS,GRID_REPORTING,watchOverlayTheme}));for(const name of["getViewIntent","validateViewIntent","previewViewIntent","applyViewIntent"]){const stub=DataGrid.prototype[name]=function(...args){return loadPart(GRID_VIEW_INTENTS).then(()=>{if(this.destroyed)throw new DOMException("Grid was destroyed.","AbortError");if(DataGrid.prototype[name]===stub)throw new Error("CanopyX: view intents did not install "+name+".");return this[name](...args)})}}
1092
1100
  DataGrid.prototype.getOnlyChanges=function(){return false};DataGrid.prototype.setOnlyChanges=function(...args){return loadPart(GRID_COMPARE).then(()=>{if(this.destroyed)throw new DOMException("Grid was destroyed.","AbortError");this.startDatasetCompare();return this.setOnlyChanges(...args)})};const DATA_VIEWS_INIT=DataGrid.prototype.initializeState;DataGrid.prototype.initializeState=function(){const parts=[this.view.compare&&loadPart(GRID_COMPARE),this.view.viewIntents&&loadPart(GRID_VIEW_INTENTS)].filter(Boolean);if(!parts.length)return DATA_VIEWS_INIT.call(this);return Promise.all(parts).then(()=>{if(this.destroyed)throw new DOMException("Grid was destroyed.","AbortError");if(this.view.compare)this.startDatasetCompare();return DATA_VIEWS_INIT.call(this)})};function gridVariant(button,variant){button.dataset.variant=variant;return button}
1093
1101
  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}
1094
1102
  let keyboardInput=false;if(typeof document!=="undefined"){document.addEventListener("keydown",()=>{keyboardInput=true},true);document.addEventListener("pointerdown",()=>{keyboardInput=false},true)}
1095
1103
  const focusDrawerTitle=title=>{if(keyboardInput&&title===document.activeElement&&!title.matches(":focus-visible"))title.blur();title.toggleAttribute("data-cx-pointer-focus",!keyboardInput);if(!keyboardInput)title.addEventListener("blur",()=>title.removeAttribute("data-cx-pointer-focus"),{once:true});title.focus({preventScroll:true,focusVisible:keyboardInput})};function gridInputLabel(text,input){const label=h("label","cx-grid-field");label.appendChild(document.createTextNode(text));label.appendChild(input);return label}
1096
1104
  function gridOption(value,text){const option=h("option");option.value=value;setText(option,text);return option}
1097
- const MENU_EVENT="canopyx:closemenus",announceMenu=source=>document.dispatchEvent(new CustomEvent(MENU_EVENT,{detail:{source}}));const TOOLBAR_PANELS={startMenus(){this.controlFlyouts=[];this.disposeControls=()=>this.controlFlyouts.forEach(flyout=>flyout.dispose());let pressed=null;for(const type of["mouseup","click","keydown","pointercancel"])document.addEventListener(type,()=>{pressed=null},{capture:true,signal:this.lifetime.signal});for(const type of["pointerdown","focusin",MENU_EVENT])document.addEventListener(type,event=>{if(type==="pointerdown")pressed=event.target;const node=type==="focusin"&&pressed?.isConnected&&event.target.contains(pressed)?pressed:event.detail?.source||event.target;if(type!==MENU_EVENT||event.target.contains(this.host))this.closeMenusOutside(node)},{signal:this.lifetime.signal})},closeMenusOutside(node){const holds=element=>element&&(UI_TOOLS.owns?.(element,node)??element.contains(node));if(this.pendingColumnMenu&&!holds(this.pendingColumnMenu.anchor))this.pendingColumnMenu=null;for(const details of this.toolbar.querySelectorAll(".cx-columns[open]"))if(!holds(details))details.open=false;const popover=this.gridPopover;if(popover&&!holds(popover.panel)&&!holds(popover.anchor))this.closeGridPopover(false);const cellMenu=this.cellMenuPanel;if(cellMenu&&!holds(cellMenu)&&!holds(this.cellMenuHit?.cell))this.cellMenuBinding?.close("menus",false,true)},closeMenus(){this.closeMenusOutside(document)},controlPanel(title,className,onOpen){const details=h("details","cx-columns "+className),summary=h("summary","cx-btn"),panel=h("div","cx-columns-list cx-grid-panel cx-pop");summary.setAttribute("role","button");panel.setAttribute("aria-label",title);if(className!=="cx-grid-filters")summary.classList.add("ghost");setText(summary,title);details.append(summary,panel);this.toolbar.appendChild(details);summary.prepend(gridIcon(className.slice(8).replace("rs","r")));panel.popover="manual";const flyout=watchFlyout(details,panel,()=>details.open);this.controlFlyouts.push(flyout);details.addEventListener("toggle",()=>{if(details.open){announceMenu(details);if(onOpen)onOpen(panel);flyout.open()}else{flyout.close();for(const inner of panel.querySelectorAll("details[open]"))inner.open=false}});details.addEventListener("keydown",event=>{if(event.key==="Escape"&&details.open){details.open=false;flyout.close();summary.focus();event.preventDefault();event.stopPropagation()}});return{details,panel}},buildSavedViews(){const panel=this.controlPanel(this.labels.gridViews,"cx-grid-views").panel;const choice=this.savedChoice=h("select"),name=h("input");name.type="text";name.maxLength=100;choice.setAttribute("aria-label",this.labels.gridChooseView);panel.appendChild(choice);panel.appendChild(gridInputLabel(this.labels.gridViewName,name));const error=h("p","cx-grid-control-error");error.setAttribute("role","status");const run=action=>{try{Promise.resolve(action()).then(()=>setText(error,""),failure=>setText(error,failure.message))}
1105
+ const MENU_EVENT="canopyx:closemenus",announceMenu=source=>document.dispatchEvent(new CustomEvent(MENU_EVENT,{detail:{source}}));const TOOLBAR_PANELS={startMenus(){this.controlFlyouts=[];this.disposeControls=()=>this.controlFlyouts.forEach(flyout=>flyout.dispose());let pressed=null;for(const type of["mouseup","click","keydown","pointercancel"])document.addEventListener(type,()=>{pressed=null},{capture:true,signal:this.lifetime.signal});for(const type of["pointerdown","focusin",MENU_EVENT])document.addEventListener(type,event=>{if(type==="pointerdown")pressed=event.target;const node=type==="focusin"&&pressed?.isConnected&&event.target.contains(pressed)?pressed:event.detail?.source||event.target;if(type!==MENU_EVENT||event.target.contains(this.host))this.closeMenusOutside(node)},{signal:this.lifetime.signal})},closeMenusOutside(node){const holds=element=>element&&(UI_TOOLS.owns?.(element,node)??element.contains(node));if(this.pendingColumnMenu&&!holds(this.pendingColumnMenu.anchor))this.pendingColumnMenu=null;for(const details of this.toolbar.querySelectorAll(".cx-columns[open]"))if(!holds(details))details.open=false;const popover=this.gridPopover;if(popover&&!holds(popover.panel)&&!holds(popover.anchor))this.closeGridPopover(false);const cellMenu=this.cellMenuPanel;if(cellMenu&&!holds(cellMenu)&&!holds(this.cellMenuHit?.cell))this.cellMenuBinding?.close("menus",false,true)},closeMenus(){this.closeMenusOutside(document)},controlPanel(title,className,onOpen){const details=h("details","cx-columns "+className),summary=h("summary","cx-btn"),panel=h("div","cx-columns-list cx-grid-panel cx-pop");summary.setAttribute("role","button");panel.setAttribute("role","dialog");panel.setAttribute("aria-label",title);if(className!=="cx-grid-filters")summary.classList.add("ghost");setText(summary,title);details.append(summary,panel);this.toolbar.appendChild(details);summary.prepend(gridIcon(className.slice(8).replace("rs","r")));panel.popover="manual";const flyout=watchFlyout(details,panel,()=>details.open);this.controlFlyouts.push(flyout);details.addEventListener("toggle",()=>{if(details.open){announceMenu(details);if(onOpen)onOpen(panel);flyout.open()}else{flyout.close();for(const inner of panel.querySelectorAll("details[open]"))inner.open=false}});details.addEventListener("keydown",event=>{if(event.key==="Escape"&&details.open){details.open=false;flyout.close();summary.focus();event.preventDefault();event.stopPropagation()}});return{details,panel}},buildSavedViews(){const panel=this.controlPanel(this.labels.gridViews,"cx-grid-views").panel;const choice=this.savedChoice=h("select"),name=h("input");name.type="text";name.maxLength=100;choice.setAttribute("aria-label",this.labels.gridChooseView);panel.appendChild(choice);panel.appendChild(gridInputLabel(this.labels.gridViewName,name));const error=h("p","cx-grid-control-error");error.setAttribute("role","status");const run=action=>{try{Promise.resolve(action()).then(()=>setText(error,""),failure=>setText(error,failure.message))}
1098
1106
  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\})/){
1099
1107
  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}))}
1100
1108
  DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{gridRegexSearch:"Search pattern",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){input.setCustomValidity("");return}
@@ -1153,19 +1161,20 @@ capturedOptions={...capture,columns}}}
1153
1161
  const exported=this.prepareExport(capturedOptions);const cardColumns=layout==="stacked"?(projection||exported.request.columns.map(column=>column.id)).map(id=>this.columns.find(column=>column.id===id)):[];const cardRoles=cardColumns.map((column,index)=>VIEW_MODES.cardRole(column,index,cardColumns));if(projection)GRID_REPORTING.captureCardText?.(exported.request,tokenColumns);return this.runGridHook(async signal=>{await loadExportPart();const progress=(phase,completed)=>onProgress?.(Object.freeze({phase,completed,total:exported.request.recordCount}));const snapshot=await EXPORT_IMPL.snapshot(this,exported,maxRows,signal,progress);if(typeof this.opts.onPrint==="function")await this.opts.onPrint({snapshot,signal,layout});else await EXPORT_IMPL.printSnapshot(this,snapshot,signal,layout,template,projection,cardRoles);gridOperationActive(this,signal);progress("ready",snapshot.rows.length)},capture.signal,exportTimeout(this,{timeoutMs}))},buildExportControls(){this.toolbar.appendChild(Object.assign(gridButton(this.labels.gridDetails,()=>{try{const row=this.focused||[...this.rowCache.values()].find(item=>this.selected.has(item.key));if(!row||row.status)throw new Error("CanopyX: focus a record for details.");this.openDetails(row.key).catch(error=>this.emit("error",{error}))}catch(error){this.emit("error",{error})}}),{className:"cx-button cx-grid-details"}));const print=this.printButton=gridButton(this.labels.gridPrint,()=>Promise.resolve().then(()=>this.exportControl?
1154
1162
  this.exportFromMenu((options,onProgress)=>this.print({...options,onProgress})):this.print({scope:"filtered"}))
1155
1163
  .catch(error=>this.emit("error",{error})));print.classList.add("cx-grid-print");print.hidden=this.tools.export!==false;this.toolbar.appendChild(print);if(this.tools.export!==false)this.exportControl=this.controlPanel(this.labels.gridExport,"cx-grid-export",panel=>this.renderGridExport(panel))},async renderGridExport(panel){if(panel.firstChild)return;setText(panel,this.labels.loading);try{await loadExportPart();if(!this.destroyed&&panel.isConnected){this.renderGridExport(panel);this.controlFlyouts.forEach(item=>item.position())}}
1156
- catch(error){if(!this.destroyed&&panel.isConnected){setText(panel,this.labels.gridLoadFailed);panel.appendChild(gridButton(this.labels.gridRetry,()=>this.renderGridExport(panel,setText(panel,""))));this.emit("error",{error})}}}});DataGrid.prototype.hiddenViewColumns=function(){return this.columns.filter(column=>!column.hidden&&(column.responsiveHidden||column.fitHidden))};DataGrid.prototype.phoneLineColumns=function(){if(this.host.clientWidth>640||(this.layoutMode||"fit")!=="fit")return[];const hidden=this.hiddenViewColumns().sort((a,b)=>gridRank(a)- gridRank(b));const compact=this.columns.filter(column=>!column.hidden&&!column.responsiveHidden&&!column.fitHidden).length<=2;return hidden.filter(column=>gridLevel(column)===0||compact).slice(0,2)};DataGrid.prototype.phoneRemainingColumns=function(row){const shown=this.phoneLineColumns(row);return this.hiddenViewColumns().filter(column=>!shown.includes(column))};DataGrid.prototype.hiddenFieldCount=function(row){return this.phoneRemainingColumns(row).length};DataGrid.prototype.hiddenFieldLabel=function(row){const count=this.hiddenFieldCount(row);return fill(plural(this.labels.hiddenColumns,count,this.lang),{count:numberFormat(this.lang).format(count)})};DataGrid.prototype.paintHiddenFields=function(slot,row,column){if(this.phone&&column.identity)slot.cell.title=cellText(row.cells[column.id],column,this.fmt)||"";const first=column===this.cols[0],fields=first&&this.phone?this.phoneLineColumns(row):[];let button=slot.hiddenFields;const count=first&&(this.phone||this.desktopHiddenFields)&&this.hiddenFieldCount(row);if(!count){button?.remove();slot.hiddenFields=null}
1164
+ catch(error){if(!this.destroyed&&panel.isConnected){setText(panel,this.labels.gridLoadFailed);panel.appendChild(gridButton(this.labels.gridRetry,()=>this.renderGridExport(panel,setText(panel,""))));this.emit("error",{error})}}}});DataGrid.prototype.hiddenViewColumns=function(){return this.columns.filter(column=>!column.hidden&&(column.responsiveHidden||column.fitHidden))};DataGrid.prototype.phoneLineColumns=function(){if(this.host.clientWidth>640||(this.layoutMode||"fit")!=="fit")return[];const hidden=this.hiddenViewColumns().sort((a,b)=>gridRank(a)- gridRank(b));const compact=this.columns.filter(column=>!column.hidden&&!column.responsiveHidden&&!column.fitHidden).length<=2;return hidden.filter(column=>gridLevel(column)===0||compact).slice(0,2)};DataGrid.prototype.paintHiddenFields=function(slot,row,column){if(this.phone&&column.identity)slot.cell.title=cellText(row.cells[column.id],column,this.fmt)||"";const first=column===this.cols[0],fields=first&&this.phone?this.phoneLineColumns(row):[];let button=slot.hiddenFields;const hidden=first&&(this.phone||this.desktopHiddenFields)?this.hiddenViewColumns().filter(column=>!fields.includes(column)):[],count=hidden.length;if(!count){button?.remove();slot.hiddenFields=null}
1157
1165
  else{if(!button){button=gridButton("",()=>Promise.resolve().then(()=>this.openDetails(button.dataset.cxRecord)).catch(error=>this.emit("error",{error})));button.classList.add("cx-hidden-fields");button.tabIndex=-1}
1158
- const label=this.hiddenFieldLabel(row),titles=this.phoneRemainingColumns(row).map(item=>item.title).join(", ");button.dataset.cxRecord=row.id;button.setAttribute("aria-label",label+": "+titles);button.title=titles;setText(button,label);slot.hiddenFields=button}
1166
+ const label=fill(plural(this.labels.hiddenColumns,count,this.lang),{count:numberFormat(this.lang).format(count)}),titles=hidden.map(item=>item.title).join(", ");button.dataset.cxRecord=row.id;button.setAttribute("aria-label",label+": "+titles);button.title=titles;setText(button,label);slot.hiddenFields=button}
1159
1167
  if(!first||!this.phone){slot.childSlots?.forEach(disposeHostSlot);slot.childSlots=null;slot.phoneLine?.remove();slot.phoneLine=null;if(slot.phonePrimary){slot.phonePrimary.replaceWith(...slot.phonePrimary.childNodes);slot.phonePrimary=null}
1160
1168
  if(first&&count)slot.cell.appendChild(button);return}
1161
1169
  let primary=slot.phonePrimary;if(!primary||primary.parentNode!==slot.cell)primary=h("span","cx-phone-primary");for(const node of[...slot.cell.childNodes])if(node!==primary&&node!==slot.phoneLine&&node!==button)primary.appendChild(node);if(primary.parentNode!==slot.cell)slot.cell.prepend(primary);slot.phonePrimary=primary;if(!fields.length&&!count){slot.childSlots?.forEach(disposeHostSlot);slot.childSlots=null;slot.phoneLine?.remove();slot.phoneLine=null;return}
1162
1170
  let line=slot.phoneLine;if(!line||line.parentNode!==slot.cell){line=h("span","cx-phone-fields");slot.cell.appendChild(line)}
1163
1171
  slot.phoneLine=line;const shape=JSON.stringify(fields.map(item=>item.id));if(line.dataset.cxFields!==shape){slot.childSlots?.forEach(disposeHostSlot);line.replaceChildren();line.dataset.cxFields=shape;slot.childSlots=[];for(const field of fields){const item=h("span","cx-phone-field"),label=h("span","cx-phone-field-title"),value=h("span","cx-phone-value");setText(label,field.title+":");item.append(label,value);line.appendChild(item);const content=value.appendChild(h("span","cx-content")),textSpan=content.appendChild(h("span","cx-text"));slot.childSlots.push({cell:value,content,base:"cx-phone-value",cls:null,title:null,badges:[],mode:"default",textSpan,text:textSpan.appendChild(document.createTextNode(""))})}}
1164
- if(count&&button.parentNode!==line)line.appendChild(button);fields.forEach((field,index)=>{this.paintSlot(slot.childSlots[index],row,field,this.columns.indexOf(field),{level:0,expanded:false});slot.childSlots[index].cell.title=cellText(row.cells[field.id],field,this.fmt)||""})};LINK_IMPL.DataGrid=DataGrid;LINK_IMPL.gridQueryStart=gridQueryStart;linkMethods(DataGrid);linkGridPart(DataGrid);function createDataGrid(host,options){if(!host||!options||!options.view)throw new Error("CanopyX: createDataGrid needs a host element and a grid document.");const existing=activeGrids.get(host);if(existing)return existing;const grid=new DataGrid(host,options);const api={element:host,view:grid.view,ready:startPlugins(grid,()=>api),getTimeZone:()=>grid.local?"local":"utc",getSelection:()=>[...grid.selected],clearSelection:()=>grid.setSelection([]),getLoadedRows:ids=>{const wanted=new Set(Array.isArray(ids)?ids:[]),rows=[];for(const row of grid.rowCache.values())if(wanted.has(row.key))rows.push({id:row.key,cells:JSON.parse(JSON.stringify(row.h.cells||{}))});return rows},focus:()=>grid.setFocus(grid.focused||grid.rowItem(grid.rowAt(grid.logicalTop())),true),refresh:()=>{grid.version++;grid.scheduleRender()},reload:()=>grid.setQuery(gridQueryStart(grid.queryForChange(true)),grid.pendingPaging&&
1172
+ const disclosure=fields.length?line.lastElementChild:line;if(count&&button.parentNode!==disclosure)disclosure.appendChild(button);fields.forEach((field,index)=>{this.paintSlot(slot.childSlots[index],row,field,this.columns.indexOf(field),{level:0,expanded:false});const value=slot.childSlots[index].cell;value.title=cellText(row.cells[field.id],field,this.fmt)||""})};DataGrid.prototype.syncGridPhoneValues=function(){if(!this.phone)return;for(const value of this.canvas.querySelectorAll(".cx-phone-value")){if(value.querySelector(".p-pill,.p-state")&&value.scrollWidth>value.clientWidth+1)value.tabIndex=0;else value.removeAttribute("tabindex")}};LINK_IMPL.DataGrid=DataGrid;LINK_IMPL.gridQueryStart=gridQueryStart;linkMethods(DataGrid);linkGridPart(DataGrid);function createDataGrid(host,options){if(!host||!options||!options.view)throw new Error("CanopyX: createDataGrid needs a host element and a grid document.");if(options.recordDrawerModal!==undefined&&typeof options.recordDrawerModal!=="boolean")
1173
+ throw new Error("CanopyX: recordDrawerModal must be a Boolean.");const existing=activeGrids.get(host);if(existing)return existing;const grid=new DataGrid(host,options);const api={element:host,view:grid.view,ready:startPlugins(grid,()=>api),getTimeZone:()=>grid.local?"local":"utc",getSelection:()=>[...grid.selected],clearSelection:()=>grid.setSelection([]),getLoadedRows:ids=>{const wanted=new Set(Array.isArray(ids)?ids:[]),rows=[];for(const row of grid.rowCache.values())if(wanted.has(row.key))rows.push({id:row.key,cells:JSON.parse(JSON.stringify(row.h.cells||{}))});return rows},focus:()=>grid.setFocus(grid.focused||grid.rowItem(grid.rowAt(grid.logicalTop())),true),refresh:()=>{grid.version++;grid.scheduleRender()},reload:()=>grid.setQuery(gridQueryStart(grid.queryForChange(true)),grid.pendingPaging&&
1165
1174
  {pageLength:grid.pendingPaging.pageLength,allRows:grid.pendingPaging.allRows}),destroy:()=>{grid.destroy();if(activeGrids.get(host)===api)activeGrids.delete(host);if(host.canopyx===api)delete host.canopyx}};for(const name of["getQuery","setQuery","sort","getPaging","goToPage","setPageLength","firstPage","previousPage","nextPage","getOnlyChanges","setOnlyChanges","setColumnWidth","autoFitColumn","autoFitColumns","autoSizeColumns","setColumnPriority","resetColumns","setColumnPinned","setColumnVisible","setColumnOrder","getState","setState","resetView","getSavedViews","saveView","applySavedView","removeSavedView","setTimeZone","setSelection","prepareExport","toCsv","copy","exportToHost","exportAs","print","openDetails","openRecord","scrollToRow","retry","closeMenus","getFormatRules","setFormatRules","openFormatRules","getCalculatedColumns","setCalculatedColumns","openCalculatedColumn","getLayout","setLayout","getMatches","setSearchHighlight","nextMatch","previousMatch",...GRID_EDIT_API,...GRID_LIVE_API,...GRID_CALENDAR_API,"getLiveState","getFacetPanel","setFacetPanelOpen"])
1166
1175
  api[name]=(...args)=>grid[name](...args);for(const[,read,...names]of GRID_PART_API){api[read]=(...args)=>grid[read](...args);for(const name of names)api[name]=(...args)=>{try{return Promise.resolve(grid[name](...args))}catch(error){return Promise.reject(error)}}}
1167
1176
  GRID_REPORTING.api?.(api,grid);for(const name of["getViewIntent","validateViewIntent","previewViewIntent","applyViewIntent"])
1168
- api[name]=(...args)=>{try{return Promise.resolve(grid[name](...args))}catch(error){return Promise.reject(error)}};Object.assign(api,linkApi(grid));api.ready=linkReady(grid,api.ready);Object.freeze(api);activeGrids.set(host,api);host.setAttribute("data-canopyx-mounted","true");host.canopyx=api;recordStart(grid);return api}
1177
+ api[name]=(...args)=>{try{return Promise.resolve(grid[name](...args))}catch(error){return Promise.reject(error)}};Object.assign(api,linkApi(grid));api.ready=linkReady(grid,api.ready);Object.defineProperty(api,"selectOnClick",{enumerable:true,get:()=>grid.selectOnClick,set:value=>{if(typeof value!=="boolean")throw new Error("CanopyX: selectOnClick is a boolean.");grid.selectOnClick=value}});Object.freeze(api);activeGrids.set(host,api);host.setAttribute("data-canopyx-mounted","true");host.canopyx=api;recordStart(grid);return api}
1169
1178
  const GRID_ENHANCE_IMPL={},GRID_ENHANCE=definePart(DataGrid,"enhance","table enhancement",()=>({DataGrid,GRID_ENHANCE_IMPL,PROTOCOL,createDataGrid,h,setText,gridQueryRows,gridCompare,gridResultShape,isIdentifier,GRID_REPORTING,loadPart,GRID_PAGER}));const gridEnhancer=table=>(target,options)=>loadPart(GRID_ENHANCE).then(()=>GRID_ENHANCE_IMPL.create(target,options,table));const GRID_API={createDataGrid,createCalendar,enhance:gridEnhancer(true),grid:gridEnhancer(false)};Object.assign(VIEW_MODES,{DataGrid,gridMatches,gridResultShape});Object.assign(DataGrid.prototype,VIEW_MODE_METHODS);definePart(DataGrid,"highlight","search highlighting",viewModeContext);definePart(DataGrid,"layouts","layout modes",viewModeContext);const MODES_BASE={};for(const name of["prepareState","build","getState","readGridState","applyStatePresentation","initializeState"])MODES_BASE[name]=DataGrid.prototype[name];Object.assign(DataGrid.prototype,{prepareState(){this.prepareViewModes();if(this.view.stickyHeader!==undefined&&typeof this.view.stickyHeader!=="boolean")throw new Error("CanopyX: stickyHeader is a boolean.");readCardTemplate(this.view.cardTemplate,this.columns,this.layoutOptions);const result=MODES_BASE.prepareState.call(this);this.modeState(this.defaultState);if(this.initialState)this.adoptModes(this.initialState);return result},build(){MODES_BASE.build.call(this);this.host.setAttribute("data-cx-density",this.density);this.lifetime.signal.addEventListener("abort",()=>this.host.removeAttribute("data-cx-layout"),{once:true});this.modesStarted=this.highlightOptions||this.layoutOptions||this.view.stickyHeader?this.startViewModes():null},getState(){return this.modeState(MODES_BASE.getState.call(this))},readGridState(state){return Object.assign(MODES_BASE.readGridState.call(this,state),readModeState(this,state))},applyStatePresentation(state){const applied=MODES_BASE.applyStatePresentation.call(this,state);this.applyModeState(state);return applied},initializeState(){const ready=MODES_BASE.initializeState.call(this);return this.modesStarted?Promise.all([ready,this.modesStarted]).then(([result])=>result):ready}});const FLOW_GRID_VIEWS=Object.freeze({grid:createDataGrid,tree:createTreeGrid,get reporting(){return typeof GRID_REPORTING==="object"&&typeof GRID_REPORTING.api==="function"}});function checkIntentPath(path){if(!Array.isArray(path)||!path.length)throw new Error("CanopyX: checking needs a complete node-ID path.");const seen=new Set();return path.map(id=>{requireIdentifier(id,"checking path ID");if(seen.has(id))throw new Error("CanopyX: a checking path cannot repeat an ID.");seen.add(id);return id})}
1170
1179
  function checkBranch(){return{value:null,mask:0,children:new Map()}}
1171
1180
  class CheckIntents{constructor(items,mode){if(!Array.isArray(items))throw new Error("CanopyX: checkIntents must be an array.");this.mode=mode;this.root=checkBranch();for(const item of items){if(!item||typeof item.checked!=="boolean")throw new Error("CanopyX: a checking intent needs a boolean checked value.");const path=checkIntentPath(item.path);let branch=this.root;for(const id of path){if(!branch.children.has(id))branch.children.set(id,checkBranch());branch=branch.children.get(id)}
@@ -1390,14 +1399,7 @@ this.selectionScopeKey=key;this.selectionRevision=detail.revision}
1390
1399
  if(name==="select")detail={...detail,selection:this.getSelectionDescriptor()};if(name==="select"||name==="query"||name==="error")this.syncSelectionControls?.()}
1391
1400
  return SELECTION_BASE.emit.call(this,name,detail)},copyFocused(row,cell){return this.querySelection?this.copy({scope:"selected"}):SELECTION_BASE.copyFocused.call(this,row,cell)}});Object.assign(DataGrid.prototype,{selectPage(selected=true,options={}){this.requireReportingSelection(true);if(typeof selected!=="boolean"||options.signal!==undefined&&!(options.signal instanceof AbortSignal))
1392
1401
  throw new Error("CanopyX: page selection needs a boolean and optional AbortSignal.");if(!this.paged)throw new Error("CanopyX: page selection requires paged presentation.");const bounds=this.rowBounds();return bounds.last<bounds.first?Promise.resolve(this.getSelectionDescriptor()):
1393
- this.selectRange(bounds.first,bounds.last,{...options,selected,additive:true})},async selectRange(start,end,options={}){this.requireReportingSelection(true);const first=Math.min(start,end),last=Math.max(start,end),selected=options.selected??true,additive=options.additive??false;if(!Number.isInteger(start)||!Number.isInteger(end)||first<0||last>=this.rowCount()||last-first+1>REPORTING_SELECTION_LIMIT||
1394
- typeof selected!=="boolean"||typeof additive!=="boolean"||options.signal!==undefined&&!(options.signal instanceof AbortSignal))
1395
- throw new Error("CanopyX: selection ranges need accepted positions and at most 10,000 records.");if(this.cursor&&(first<this.pageOffset||last>=this.cursorWindow.end))
1396
- throw new Error("CanopyX: sequential-source selection ranges stay on the accepted page.");this.selectionController?.abort();const controller=this.selectionController=new AbortController(),dataSignal=this.dataLifetime.signal,epoch=this.queryEpoch;const abort=()=>controller.abort();dataSignal.addEventListener("abort",abort,{once:true});options.signal?.addEventListener("abort",abort,{once:true});if(options.signal?.aborted)abort();const query=this.acceptedQuery,snapshot={...this.snapshot},ids=[],seen=new Set(),scope=this.querySelection;try{gridOperationActive(this,controller.signal);if(this.cursor){for(let index=first;index<=last;index++){const row=this.rowCache.get(index);if(!row||row.status)throw new Error("CanopyX: the complete accepted cursor page is required for page/range selection.");ids.push(row.key)}}else for(let offset=Math.floor(first / this.pageSize) * this.pageSize; offset <= last; offset += this.pageSize) {
1397
- const request=gridQuery(this.view,{...query,offset,limit:this.pageSize});const page=validateGridPage(await this.requestPage(request,controller.signal),this.view,request,snapshot);gridOperationActive(this,controller.signal);for(const[index,row]of page.items.entries()){if(seen.has(row.id))throw new Error("CanopyX: a selection range repeated a record identity.");seen.add(row.id);if(page.offset+index>=first&&page.offset+index<=last)ids.push(row.id)}}
1398
- gridOperationActive(this,controller.signal);if(epoch!==this.queryEpoch||ids.length!==last-first+1)
1399
- throw new DOMException("Selection range was superseded or incomplete.","AbortError");if(scope){const excluded=new Set(this.selectionExcluded);for(const id of ids)if(selected)excluded.delete(id);else excluded.add(id);if(excluded.size>REPORTING_SELECTION_LIMIT)throw new Error("CanopyX: query selection supports at most 10,000 exclusions.");this.selectionExcluded=excluded;this.publishQuerySelection()}else{const next=additive||!selected?new Set(this.selected):new Set();for(const id of ids)if(selected)next.add(id);else next.delete(id);this.setSelection([...next])}
1400
- if(this.selectionAnchor==null)this.selectionAnchor=start;return this.getSelectionDescriptor()}finally{dataSignal.removeEventListener("abort",abort);options.signal?.removeEventListener("abort",abort);controller.abort();if(this.selectionController===controller)this.selectionController=null}}});const SELECTION_EXPORT_PREPARE=DataGrid.prototype.prepareExport,SELECTION_EXPORT_ROWS=DataGrid.prototype.exportRows,SELECTION_EXPORT_TEXT=DataGrid.prototype.exportText;DataGrid.prototype.prepareExport=function(options){if(options?.scope!=="selected"||!this.querySelection)return SELECTION_EXPORT_PREPARE.call(this,options);const selection=this.getSelectionDescriptor(),exported=SELECTION_EXPORT_PREPARE.call(this,{...options,scope:"filtered"});const request=gridFreeze({...exported.request,scope:"selected",query:selection.query,revision:selection.revision,matched:selection.matched,recordCount:selection.matched===null?null:selection.matched-selection.excludedIds.length,selection:[],querySelection:selection});const signal=options.signal;return Object.freeze({request,rows:options=>this.exportRows(request,gridExportSignal(signal,options))})};DataGrid.prototype.exportRows=async function*(request,signal){if(!request.querySelection){yield*SELECTION_EXPORT_ROWS.call(this,request,signal);return}
1402
+ this.selectRange(bounds.first,bounds.last,{...options,selected,additive:true})},async selectRange(start,end,options={}){this.requireReportingSelection(true);await this.selectRowRange(start,end,options);return this.getSelectionDescriptor()}});const SELECTION_EXPORT_PREPARE=DataGrid.prototype.prepareExport,SELECTION_EXPORT_ROWS=DataGrid.prototype.exportRows,SELECTION_EXPORT_TEXT=DataGrid.prototype.exportText;DataGrid.prototype.prepareExport=function(options){if(options?.scope!=="selected"||!this.querySelection)return SELECTION_EXPORT_PREPARE.call(this,options);const selection=this.getSelectionDescriptor(),exported=SELECTION_EXPORT_PREPARE.call(this,{...options,scope:"filtered"});const request=gridFreeze({...exported.request,scope:"selected",query:selection.query,revision:selection.revision,matched:selection.matched,recordCount:selection.matched===null?null:selection.matched-selection.excludedIds.length,selection:[],querySelection:selection});const signal=options.signal;return Object.freeze({request,rows:options=>this.exportRows(request,gridExportSignal(signal,options))})};DataGrid.prototype.exportRows=async function*(request,signal){if(!request.querySelection){yield*SELECTION_EXPORT_ROWS.call(this,request,signal);return}
1401
1403
  const excluded=new Set(request.querySelection.excludedIds);const filtered={...request,scope:"filtered"};gridCopyExportPresentation(request,filtered);for await(const row of SELECTION_EXPORT_ROWS.call(this,filtered,signal))
1402
1404
  if(!excluded.delete(row.id))yield row;if(excluded.size)throw new Error("CanopyX: excluded records are absent from the accepted query revision.")};DataGrid.prototype.exportText=async function(exported,maxRows=50000,delimiter,signal){const selection=exported.request.querySelection;if(selection&&selection.matched!==null&&Number.isInteger(maxRows)&&maxRows>=1&&maxRows<=1000000&&
1403
1405
  selection.matched-selection.excludedIds.length>maxRows)
@@ -1410,7 +1412,7 @@ this.selectRange(this.selectionAnchor,row._ri,{selected,additive}):this.setRepor
1410
1412
  !event.target.closest("a,button,input,select,textarea,[contenteditable]")&&(event.shiftKey||event.ctrlKey||event.metaKey)){this.setFocus(row,true);this.reportingSelectionIntent(row,event.shiftKey||!this.reportingRowSelected(row),event.shiftKey,event.ctrlKey||event.metaKey);return}
1411
1413
  try{SELECTION_CONTROLS_BASE.onClick.call(this,event)}
1412
1414
  catch(error){if(!this.view.reporting?.selectionControls)throw error;this.runReportingSelection(()=>{throw error});return}
1413
- if(this.view.reporting?.selectionControls&&row&&!row.status&&!event.defaultPrevented&&
1415
+ if(!this.selectOnClick&&this.view.reporting?.selectionControls&&row&&!row.status&&!event.defaultPrevented&&
1414
1416
  !event.target.closest("a,button,input,select,textarea,[contenteditable]"))this.selectionAnchor=row._ri},onKey(event){const element=event.target.closest(".cx-row"),row=element?._w;if(this.view.reporting?.selectionControls&&row&&!row.status&&event.key===" "&&!event.defaultPrevented&&
1415
1417
  !event.isComposing&&!event.altKey&&!event.target.closest("a,button,input,select,textarea,[contenteditable]")){event.preventDefault();this.reportingSelectionIntent(row,!this.reportingRowSelected(row),event.shiftKey,event.ctrlKey||event.metaKey);return}
1416
1418
  return SELECTION_CONTROLS_BASE.onKey.call(this,event)}});DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{gridGroupHeading:"{column}: {value} ({count} records)",gridGroupMissing:"Missing value",gridGroupExpand:"Expand group",gridGroupCollapse:"Collapse group",gridSummary:"Grand total",gridGroupOrder:"Group order is fixed by this report",gridGroupBy:"Group by this column",gridUngroup:"Stop grouping by this column",gridGroupDrop:"Drag a column header here to group rows",gridExpandAll:"Expand all",gridCollapseAll:"Collapse all",gridExpandLevel:"Expand level {level}",gridCollapseLevel:"Collapse level {level}",gridGroupMove:"Alt+Left and Alt+Right move this level",gridGroupSortBy:"Sort groups by",gridGroupSortValue:"by value",gridGroupSortAggregate:"by {aggregate}",gridSelectGroup:"Select the records of {group}",gridAggregateCount:"count {value}",gridAggregateSum:"sum {value}",gridAggregateAverage:"avg {value}",gridAggregateMinimum:"min {value}",gridAggregateMaximum:"max {value}",gridAggregateDistinct:"distinct {value}",gridShowDetail:"Show details",gridHideDetail:"Hide details",gridDetailOf:"Details of {record}",gridDetailFailed:"Details could not load: {error}"}));const GROUP_LEVELS=4,GROUP_OPERATIONS=["count","sum","average","minimum","maximum","distinctCount"];const GROUP_NUMERIC=["sum","average","minimum","maximum"],GRID_ROWS={base:{}};const reportingDynamicGroups=view=>view.reporting?.groupBy!==undefined||!!view.reporting?.groupable;function reportingSummaryEnabled(view){return!!view.reporting?.grouping||reportingDynamicGroups(view)||!!view.reporting?.aggregates?.length}
@@ -1448,7 +1450,7 @@ return GROUP_STATE_BASE.applyStatePresentation.call(this,state)},getShareState()
1448
1450
  function reportingValueText(grid,aggregate,value,mode="value"){if(value===null||value===undefined)return "—";const column=grid.view.columns.find(column=>column.id===aggregate.column);if(GRID_SHOW_AS.percent?.(mode))return new Intl.NumberFormat(grid.lang,{style:"percent",minimumFractionDigits:2,maximumFractionDigits:2}).format(value).replace(/[\s\u00a0\u202f]+%/g, "%");
1449
1451
  const format=aggregate.format||(!reportingCounting(aggregate.operation)&&column?.format);return mode==="rank"?numberText(value,grid.lang,{minimumFractionDigits:0,maximumFractionDigits:0}):
1450
1452
  format?numberText(value,grid.lang,format):numberText(value,grid.lang,{minimumFractionDigits:reportingCounting(aggregate.operation)?0:2,maximumFractionDigits:reportingCounting(aggregate.operation)?0:2})}
1451
- function reportingAggregateParts(grid,column,aggregates,values){const text=[],titles=[];for(const aggregate of aggregates){const mode=showAsMode(grid,aggregate),display=mode==="value"?null:GRID_SHOW_AS.entry?.(grid,values,aggregate);const value=display?display.value:values[aggregate.id];if((value===null||value===undefined)&&mode==="value")continue;const shown=reportingValueText(grid,aggregate,value,mode),caption=showAsCaption(grid,mode);text.push(mode==="value"?fill(grid.labels[AGGREGATE_LABELS[aggregate.operation]]||grid.groupAggregates?.get(aggregate.operation)?.label||aggregate.operation+" {value}",{value:shown}):shown+" "+caption.replace(/^% /, ""));
1453
+ function reportingAggregateParts(grid,column,aggregates,values){const text=[],titles=[];for(const aggregate of aggregates){const mode=showAsMode(grid,aggregate),display=mode==="value"?null:GRID_SHOW_AS.entry?.(grid,values,aggregate);const value=display?display.value:values[aggregate.id];if((value===null||value===undefined)&&mode==="value")continue;const shown=reportingValueText(grid,aggregate,value,mode),caption=showAsCaption(grid,mode);const labelled=fill(grid.labels[AGGREGATE_LABELS[aggregate.operation]]||grid.groupAggregates?.get(aggregate.operation)?.label||aggregate.operation+" {value}",{value:shown});text.push(mode==="value"?labelled.charAt(0).toLocaleUpperCase(grid.lang)+ labelled.slice(1):shown+" "+caption.replace(/^% /, ""));
1452
1454
  titles.push(reportingAggregateName(grid,aggregate)+ ": "+shown +(caption?" ("+caption+")":""))}
1453
1455
  return{text:text.join(" · "),title:titles.join(" · "),caption:""}}
1454
1456
  const GRID_EXPORT_PRESENTATION=new WeakMap();function gridCopyExportPresentation(from,to){GRID_REPORTING.copyExportFormatting?.(from,to);const capture=GRID_EXPORT_PRESENTATION.get(from);if(capture)GRID_EXPORT_PRESENTATION.set(to,capture)}
@@ -1496,7 +1498,8 @@ const FLOW_ASYNC_METHODS=["next","back","goTo","setState","validate","submit","r
1496
1498
  .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()}
1497
1499
  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}
1498
1500
  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.")}
1499
- 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"])
1501
+ if(options.recordDrawerModal!==undefined&&typeof options.recordDrawerModal!=="boolean")
1502
+ throw new Error("CanopyX: recordDrawerModal must be a Boolean.");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"])
1500
1503
  api[name]=(...args)=>{if(grid[name])return grid[name](...args);const error=new Error("CanopyX: "+name+" needs the tree tools part.");if(/^(exportAs|applySavedView|resetView|openDetails|openRecord)$/.test(name)) return Promise.reject(error);
1501
1504
  throw error};api.ready=linkReady(grid,api.ready);Object.freeze(api);activeGrids.set(host,api);host.setAttribute("data-canopyx-mounted","true");host.canopyx=api;recordStart(grid);return api}
1502
1505
  const configured=new Map();function configure(viewId,options){requireIdentifier(viewId,"view ID");if(!options||typeof options!=="object"){throw new Error("CanopyX: configure needs a view id and an options object.")}