@evotecit/canopyx 0.3.16 → 0.3.18

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 (114) hide show
  1. package/CanopyX.Html/Assets/canopyx-board.css +50 -0
  2. package/CanopyX.Html/Assets/canopyx-board.js +39 -0
  3. package/CanopyX.Html/Assets/canopyx-buckets.js +15 -0
  4. package/CanopyX.Html/Assets/canopyx-calculations.css +7 -0
  5. package/CanopyX.Html/Assets/canopyx-calculations.js +52 -0
  6. package/CanopyX.Html/Assets/canopyx-calendar-edit.js +3 -3
  7. package/CanopyX.Html/Assets/canopyx-calendar.css +5 -24
  8. package/CanopyX.Html/Assets/canopyx-calendar.js +14 -19
  9. package/CanopyX.Html/Assets/canopyx-cell-range.js +16 -14
  10. package/CanopyX.Html/Assets/canopyx-changes.css +6 -24
  11. package/CanopyX.Html/Assets/canopyx-changes.js +18 -15
  12. package/CanopyX.Html/Assets/canopyx-compare.css +37 -0
  13. package/CanopyX.Html/Assets/canopyx-compare.js +12 -0
  14. package/CanopyX.Html/Assets/canopyx-data.js +3 -3
  15. package/CanopyX.Html/Assets/canopyx-editing.css +2 -2
  16. package/CanopyX.Html/Assets/canopyx-editing.js +2 -2
  17. package/CanopyX.Html/Assets/canopyx-enhance.js +4 -4
  18. package/CanopyX.Html/Assets/canopyx-export.js +54 -13
  19. package/CanopyX.Html/Assets/canopyx-facets.css +14 -5
  20. package/CanopyX.Html/Assets/canopyx-facets.js +19 -15
  21. package/CanopyX.Html/Assets/canopyx-filter-editor.css +71 -85
  22. package/CanopyX.Html/Assets/canopyx-filter-editor.js +20 -16
  23. package/CanopyX.Html/Assets/canopyx-flow-checks.css +1 -1
  24. package/CanopyX.Html/Assets/canopyx-flow-checks.js +1 -1
  25. package/CanopyX.Html/Assets/canopyx-flow-dialog.css +2 -2
  26. package/CanopyX.Html/Assets/canopyx-flow-dialog.js +1 -1
  27. package/CanopyX.Html/Assets/canopyx-flow-entry.css +136 -12
  28. package/CanopyX.Html/Assets/canopyx-flow-entry.js +2 -2
  29. package/CanopyX.Html/Assets/canopyx-flow-module.mjs +2 -2
  30. package/CanopyX.Html/Assets/canopyx-format-editor.js +2 -2
  31. package/CanopyX.Html/Assets/canopyx-formatting.js +10 -9
  32. package/CanopyX.Html/Assets/canopyx-grid-module.mjs +182 -128
  33. package/CanopyX.Html/Assets/canopyx-grid.css +228 -96
  34. package/CanopyX.Html/Assets/canopyx-grid.js +182 -128
  35. package/CanopyX.Html/Assets/canopyx-grouping.css +22 -15
  36. package/CanopyX.Html/Assets/canopyx-grouping.js +24 -17
  37. package/CanopyX.Html/Assets/canopyx-interactive.css +197 -74
  38. package/CanopyX.Html/Assets/canopyx-interactive.js +38 -45
  39. package/CanopyX.Html/Assets/canopyx-labels-de.js +177 -9
  40. package/CanopyX.Html/Assets/canopyx-labels-es.js +177 -9
  41. package/CanopyX.Html/Assets/canopyx-labels-fr.js +176 -8
  42. package/CanopyX.Html/Assets/canopyx-labels-it.js +176 -8
  43. package/CanopyX.Html/Assets/canopyx-labels-pl.js +176 -8
  44. package/CanopyX.Html/Assets/canopyx-layouts.css +48 -20
  45. package/CanopyX.Html/Assets/canopyx-layouts.js +36 -14
  46. package/CanopyX.Html/Assets/canopyx-link.js +2 -2
  47. package/CanopyX.Html/Assets/canopyx-live.css +1 -3
  48. package/CanopyX.Html/Assets/canopyx-live.js +3 -3
  49. package/CanopyX.Html/Assets/canopyx-matrix.css +1 -8
  50. package/CanopyX.Html/Assets/canopyx-matrix.js +11 -11
  51. package/CanopyX.Html/Assets/canopyx-module.mjs +38 -45
  52. package/CanopyX.Html/Assets/canopyx-office-export.js +2936 -0
  53. package/CanopyX.Html/Assets/canopyx-path.css +45 -0
  54. package/CanopyX.Html/Assets/canopyx-path.js +28 -0
  55. package/CanopyX.Html/Assets/canopyx-pivot.css +75 -0
  56. package/CanopyX.Html/Assets/canopyx-pivot.js +72 -0
  57. package/CanopyX.Html/Assets/canopyx-plan.css +56 -0
  58. package/CanopyX.Html/Assets/canopyx-plan.js +67 -0
  59. package/CanopyX.Html/Assets/canopyx-presenters.js +2 -2
  60. package/CanopyX.Html/Assets/canopyx-record-panel.css +8 -7
  61. package/CanopyX.Html/Assets/canopyx-record-panel.js +15 -14
  62. package/CanopyX.Html/Assets/canopyx-reporting-module.mjs +222 -161
  63. package/CanopyX.Html/Assets/canopyx-reporting.css +240 -107
  64. package/CanopyX.Html/Assets/canopyx-reporting.js +222 -161
  65. package/CanopyX.Html/Assets/canopyx-stack.css +35 -0
  66. package/CanopyX.Html/Assets/canopyx-stack.js +24 -0
  67. package/CanopyX.Html/Assets/canopyx-time-slider.css +18 -0
  68. package/CanopyX.Html/Assets/canopyx-time-slider.js +27 -0
  69. package/CanopyX.Html/Assets/canopyx-timeline.js +6 -5
  70. package/CanopyX.Html/Assets/canopyx-tree-tools.css +36 -35
  71. package/CanopyX.Html/Assets/canopyx-tree-tools.js +15 -12
  72. package/CanopyX.Html/Assets/canopyx-ui-menu.css +41 -0
  73. package/CanopyX.Html/Assets/canopyx-ui-menu.js +64 -0
  74. package/CanopyX.Html/Assets/canopyx-ui-navigation.css +73 -0
  75. package/CanopyX.Html/Assets/canopyx-ui-navigation.js +39 -0
  76. package/CanopyX.Html/Assets/canopyx-ui-overlays.css +79 -0
  77. package/CanopyX.Html/Assets/canopyx-ui-overlays.js +42 -0
  78. package/CanopyX.Html/Assets/canopyx-ui-picker.css +12 -0
  79. package/CanopyX.Html/Assets/canopyx-ui-picker.js +6 -0
  80. package/CanopyX.Html/Assets/canopyx-ui-stepper.css +174 -0
  81. package/CanopyX.Html/Assets/canopyx-ui-stepper.js +48 -0
  82. package/CanopyX.Html/Assets/canopyx-ui-tabs.css +153 -0
  83. package/CanopyX.Html/Assets/canopyx-ui-tabs.js +47 -0
  84. package/CanopyX.Html/Assets/canopyx-values.css +5 -0
  85. package/CanopyX.Html/Assets/canopyx-values.js +13 -0
  86. package/CanopyX.Html/Assets/canopyx-view-intents.css +12 -0
  87. package/CanopyX.Html/Assets/canopyx-view-intents.js +56 -0
  88. package/CanopyX.Html/Assets/canopyx.css +197 -71
  89. package/CanopyX.Html/Assets/canopyx.js +29 -19
  90. package/JavaScript/board.d.ts +30 -0
  91. package/JavaScript/changes.d.ts +4 -1
  92. package/JavaScript/facets.d.ts +5 -3
  93. package/JavaScript/grid.d.ts +150 -16
  94. package/JavaScript/hosts.d.ts +14 -1
  95. package/JavaScript/index.d.ts +4 -2
  96. package/JavaScript/locales/de.mjs +177 -9
  97. package/JavaScript/locales/es.mjs +177 -9
  98. package/JavaScript/locales/fr.mjs +176 -8
  99. package/JavaScript/locales/it.mjs +176 -8
  100. package/JavaScript/locales/pl.mjs +176 -8
  101. package/JavaScript/matrix.d.ts +4 -1
  102. package/JavaScript/path.d.ts +33 -0
  103. package/JavaScript/pivot.d.ts +135 -0
  104. package/JavaScript/plan.d.ts +23 -0
  105. package/JavaScript/protocol.d.ts +16 -3
  106. package/JavaScript/records.d.ts +2 -0
  107. package/JavaScript/stack.d.ts +28 -0
  108. package/JavaScript/time-slider.d.ts +58 -0
  109. package/JavaScript/ui.d.ts +261 -0
  110. package/JavaScript/view-intents.d.ts +45 -0
  111. package/README.md +22 -3
  112. package/ThirdParty/OfficeIMO/LICENSE +21 -0
  113. package/ThirdParty/OfficeIMO/README.md +13 -0
  114. package/package.json +76 -3
@@ -75,7 +75,8 @@ 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)=>{if(!Object.hasOwn(DEFAULT_LABELS,name)&&!/^(?:gridEdit|format|calendar|flow|matrix|change)[A-Z]\w{0,63}$/.test(name)) 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)=>{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 + "'.");
79
80
  if(typeof source[name]!=="string"||!/\S/.test(source[name])) throw new Error("CanopyX: label '" + name + "' must be a string with visible text.");
80
81
  if((name==="utcTime"||name==="localTime")&&source[name].indexOf("{time}")<0)throw new Error("CanopyX: label '"+name+"' must hold {time}.");labels[name]=source[name]})}
81
82
  return Object.freeze(labels)}
@@ -95,7 +96,7 @@ function overlayTheme(host,element,inherit=false){for(const name of["data-hfx-st
95
96
  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)}
96
97
  return copied}
97
98
  function watchOverlayTheme(host,element,signal){if(signal?.aborted)return()=>{};let copied=[];const refresh=()=>{for(const name of copied)element.style.removeProperty(name);copied=overlayTheme(host,element,element.parentElement===host.parentElement)};const observer=new MutationObserver(refresh);for(let owner=host;owner;owner=owner.parentElement)observer.observe(owner,{attributes:true,attributeFilter:THEME_ATTRIBUTES});const media=["(prefers-color-scheme:dark)","(prefers-contrast:more)","(forced-colors:active)"].map(query=>matchMedia(query));for(const query of media)query.addEventListener("change",refresh);const dispose=()=>{observer.disconnect();for(const query of media)query.removeEventListener("change",refresh);signal?.removeEventListener("abort",dispose)};signal?.addEventListener("abort",dispose,{once:true});dispose.refresh=refresh;refresh();return dispose}
98
- DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{gridViews:"Views",gridViewName:"View name",gridSaveView:"Save view",gridRemoveView:"Remove view",gridResetView:"Reset view",gridChooseView:"Choose a saved view",gridApply:"Apply",gridFindColumn:"Find a column…",gridShowAllColumns:"Show all",gridResetColumns:"Reset columns",gridReorderColumn:"{column}: drag, or press Alt+Up or Alt+Down to move",gridPinnedLeft:"Pinned left",gridPinnedRight:"Pinned right",gridResponsiveHidden:"Hidden at this width",gridExport:"Export",gridVisibleRows:"Visible rows",gridSelectedRows:"Selected rows",gridAllRows:"All rows",gridDownloadCsv:"Download CSV",gridCopy:"Copy",gridExportProgress:"{completed} of {total} records",gridExportReading:"{completed} records",gridExportCancelled:"Export cancelled",gridCancelExport:"Cancel export",gridMore:"More",gridPrint:"Print",gridDetails:"Record details",gridDetailsSection:"Details",gridPreviousRecord:"Previous record",gridNextRecord:"Next record",gridCloseRecord:"Close"}));DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{recordBack:"Back",recordBackTo:"Back to {record}",recordTrail:"Record trail",recordShowing:"Showing {record}",recordTabs:"Record views",recordSections:"Jump to a section",recordOtherFields:"Other fields",recordShowEmpty:"Show empty fields ({count})",recordHideEmpty:"Hide empty fields",recordActions:"Record actions",recordCopyValues:"Copy values",recordCopyJson:"Copy as JSON",recordCopyLink:"Copy link",recordCopied:"Copied to the clipboard",recordPrint:"Print record",recordExportCsv:"Export CSV",recordExportJson:"Export JSON",recordOpenAll:"Open all in grid",recordLoadMore:"Load more",recordCount:"{shown} of {total}",recordItems:"{count} items",recordMore:"+{count}",recordShowAll:"Show all {count}",recordRetry:"Retry",recordLoadFailed:"Could not load the record details: {error}",recordUnavailable:"Record {id} is not available here.",recordField:"Field",recordValue:"Value",recordSection:"Section",recordBefore:"Before",recordAfter:"After",recordAdded:"Added",recordRemoved:"Removed",recordChanged:"{count} changed fields"}));function boundedPattern(source,exact=true,whole=false){const bad=()=>{throw new Error("CanopyX: pattern requires literals, character classes and at most one variable repetition anchored at the start; groups, alternatives and backreferences are unsupported.")};if(typeof source!=="string"||source.length>256)bad();let width=0,variable=0;for(let i=0;i<source.length;){const unit=source[i++];if(unit==="^"&&i===1||unit==="$"&&i===source.length)continue;if(unit==="\\"){const escape=source[i++];if(!escape||!/^[dDsSwWbBnrtfv\\.^$*+?{}\[\]()|/]$/.test(escape)) bad();
99
+ DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{gridViews:"Views",gridViewName:"View name",gridSaveView:"Save view",gridRemoveView:"Remove view",gridResetView:"Reset view",gridChooseView:"Choose a saved view",gridApply:"Apply",gridFindColumn:"Find a column…",gridShowAllColumns:"Show all",gridResetColumns:"Reset columns",gridReorderColumn:"{column}: drag, or press Alt+Up or Alt+Down to move",gridPinnedLeft:"Pinned left",gridPinnedRight:"Pinned right",gridResponsiveHidden:"Hidden at this width",gridExport:"Export",gridVisibleRows:"Visible rows",gridSelectedRows:"Selected rows",gridAllRows:"All rows",gridDownloadCsv:"CSV",gridCopy:"Copy",gridRows:"rows",gridUnknownCount:"Result count unavailable",gridDownloadXlsx:"Excel workbook (.xlsx)",gridDownloadPdf:"PDF",gridExportWorkbookHint:"Formatted, with groups and totals",gridExportPdfHint:"Paged report with repeating headings",gridExportCsvHint:"Plain text values (.csv)",gridExportCopy:"Copy to clipboard",gridExportProgress:"{completed} of {total} records",gridExportReading:"{completed} records",gridExportCancelled:"Export cancelled",gridCancelExport:"Cancel export",gridMore:"More",gridPrint:"Print",gridDetails:"Record details",gridDetailsSection:"Details",gridPreviousRecord:"Previous record",gridNextRecord:"Next record",gridCloseRecord:"Close"}));DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{recordBack:"Back",recordBackTo:"Back to {record}",recordTrail:"Record trail",recordShowing:"Showing {record}",recordTabs:"Record views",recordSections:"Jump to a section",recordOtherFields:"Other fields",recordShowEmpty:"Show empty fields ({count})",recordHideEmpty:"Hide empty fields",recordActions:"Record actions",recordCopyValues:"Copy values",recordCopyJson:"Copy as JSON",recordCopyLink:"Copy link",recordCopied:"Copied to the clipboard",recordPrint:"Print record",recordExportCsv:"Export CSV",recordExportJson:"Export JSON",recordOpenAll:"Open all in grid",recordLoadMore:"Load more",recordCount:"{shown} of {total}",recordItems:"{count} items",recordMore:"+{count}",recordShowAll:"Show all {count}",recordRetry:"Retry",recordLoadFailed:"Could not load the record details: {error}",recordUnavailable:"Record {id} is not available here.",recordField:"Field",recordValue:"Value",recordSection:"Section",recordBefore:"Before",recordAfter:"After",recordAdded:"Added",recordRemoved:"Removed",recordChanged:"Changed fields: {count}"}));function boundedPattern(source,exact=true,whole=false){const bad=()=>{throw new Error("CanopyX: pattern requires literals, character classes and at most one variable repetition anchored at the start; groups, alternatives and backreferences are unsupported.")};if(typeof source!=="string"||source.length>256)bad();let width=0,variable=0;for(let i=0;i<source.length;){const unit=source[i++];if(unit==="^"&&i===1||unit==="$"&&i===source.length)continue;if(unit==="\\"){const escape=source[i++];if(!escape||!/^[dDsSwWbBnrtfv\\.^$*+?{}\[\]()|/]$/.test(escape)) bad();
99
100
  }else if(unit==="["){let closed=false;while(i<source.length){const c=source[i++];if(c==="\\"){const escape=source[i++];if(!escape||!/^[dDsSwWbnrtfv\\.^$*+?{}\[\]()|/-]$/.test(escape)) bad(); }
100
101
  else if(c==="]"){closed=true;break}}
101
102
  if(!closed)bad()}else if("()|^$*+?{}]".includes(unit))bad();let count=1;if(i<source.length&&"*+?".includes(source[i])){variable++;i++}
@@ -141,15 +142,18 @@ if(typeof value!=="string"&&typeof value!=="boolean")throw new Error("CanopyX: t
141
142
  function gridExactTokens(column){return column.kind==="text"&&(column.valueOrder?.length||Object.keys(column.valueLabels||{}).length)}
142
143
  function cellMatches(cell,predicate,column){const scalar=gridScalar(cell,column),op=predicate.operator;if(op==="isNull")return scalar===null;if(op==="isNotNull")return scalar!==null;if(scalar===null)return false;const normalize=value=>column.kind==="text"&&!gridExactTokens(column)&&typeof value==="string"?foldText(value):value;const value=normalize(scalar),values=predicate.values.map(operand=>normalize(gridScalar(operand,column))),operand=values[0];switch(op){case "eq":return value===operand;case "ne":return value!==operand;case "in":return values.includes(value);case "contains":return String(value).includes(String(operand));case "startsWith":return String(value).startsWith(String(operand));case "gt":return value>operand;case "ge":return value>=operand;case "lt":return value<operand;case "le":return value<=operand}
143
144
  return false}
144
- function validateGridRows(rows,columns,ids=new Set()){if(!Array.isArray(rows))throw new Error("CanopyX: grid rows must be an array.");const declared=new Map(columns.map(column=>[column.id,column]));for(const row of rows){requireIdentifier(row&&row.id,"grid row ID");if(ids.has(row.id))throw new Error("CanopyX: duplicate grid row ID "+row.id);ids.add(row.id);if(!row.cells||typeof row.cells!=="object"||Array.isArray(row.cells))
145
- throw new Error("CanopyX: invalid flat row fields.");gridDecoration(row.tone,row.className);for(const id of Object.keys(row.cells)){if(!declared.has(id))throw new Error("CanopyX: undeclared grid column "+id);const cell=row.cells[id];if(isCellObject(cell)){if(Array.isArray(cell)||
145
+ function validateGridRows(rows,columns,ids=new Set(),repair=null){if(!Array.isArray(rows))throw new Error("CanopyX: grid rows must be an array.");const declared=new Map(columns.map(column=>[column.id,column])),repaired=new Map();let result=rows;rows.forEach((row,index)=>{requireIdentifier(row&&row.id,"grid row ID");if(ids.has(row.id))throw new Error("CanopyX: duplicate grid row ID "+row.id);ids.add(row.id);if(!row.cells||typeof row.cells!=="object"||Array.isArray(row.cells))
146
+ throw new Error("CanopyX: invalid flat row fields.");let copy=null;const own=()=>copy||(result===rows&&(result=rows.slice()),result[index]=copy={...row,cells:{...row.cells}});try{gridDecoration(row.tone,row.className)}catch(error){if(!repair)throw error;delete own().tone;delete copy.className}
147
+ for(const id of Object.keys(row.cells)){const column=declared.get(id);try{if(!column)throw new Error("CanopyX: undeclared grid column "+id);validateGridCell(row.cells[id],column)}
148
+ catch(error){if(!repair)throw error;const cells=own().cells;if(column)cells[id]=repair(cells[id],column);else delete cells[id];const seen=repaired.get(id);if(seen)seen.count++;else repaired.set(id,{row:row.id,count:1})}}});for(const[id,seen]of repaired)
149
+ console.warn("CanopyX: "+seen.count+" cell(s) in column "+id+" did not fit the column and were coerced, emptied or dropped (first row "+seen.row+").");return result}
150
+ function validateGridCell(cell,column){if(isCellObject(cell)){if(Array.isArray(cell)||
146
151
  ["text","searchText","title","tone","secondary"].some(name=>cell[name]!==undefined&&typeof cell[name]!=="string")||
147
152
  cell.secondary!==undefined&&cell.secondary.length>4096||cell.sort!==undefined&&!(typeof cell.sort==="string"?cell.sort.length<=4096:Number.isFinite(cell.sort))||cell.series!==undefined&&!gridSeriesValid(cell.series)||
148
153
  cell.badges!==undefined&&(!Array.isArray(cell.badges)||cell.badges.some(badge=>!badge||typeof badge.text!=="string"||
149
154
  ["tone","title"].some(name=>badge[name]!==undefined&&typeof badge[name]!=="string"))))
150
155
  throw new Error("CanopyX: malformed grid cell.");if(typeof cell.sort==="number")gridScalar(cell.sort,{kind:"number"})}
151
- gridScalar(cell,declared.get(id))}}
152
- return rows}
156
+ gridScalar(cell,column)}
153
157
  function gridDecoration(tone,className){if(tone!==undefined&&(typeof tone!=="string"||!/^[a-z][a-z0-9-]{0,31}$/.test(tone) || tone.endsWith("-bg")) ||
154
158
  className!==undefined&&(typeof className!=="string"||!className.trim()||className.length>1024||/[\u0000-\u001f\u007f-\u009f]/.test(className)))
155
159
  throw new Error("CanopyX: invalid highlight tone or className.")}
@@ -278,7 +282,7 @@ value.sort===undefined||typeof value!=="object")throw new Error("CanopyX: query
278
282
  const named=new Set(value.filters);if(named.size!==value.filters.length||value.filters.some(id=>!(grid.view.filters||[]).some(f=>f.id===id)))
279
283
  throw new Error("CanopyX: query filters must be unique declared IDs.");const filters=Object.freeze((grid.view.filters||[]).filter(f=>named.has(f.id)).map(f=>f.id));return Object.freeze({version:1,sort,filters})}
280
284
  function snapshotRevision(value,expected){requireIdentifier(value&&value.revision,"dataset revision");if(expected!=null&&value.revision!==expected)throw new Error("CanopyX: dataset revision changed; reload the roots before continuing.");return value.revision}
281
- Object.assign(TreeGrid.prototype,{getQuery(){return{version:1,sort:this.sortState&&Object.assign({},this.sortState),filters:Array.from(this.activeFilters)}},sourceRequest(signal){return this.queryAware?{signal:signal||this.dataLifetime.signal,query:this.acceptedQuery,revision:this.datasetRevision}:{signal}},syncQueryControls(){this.toolbar.querySelectorAll("[data-cx-filter]").forEach(input=>{input.checked=this.activeFilters.has(input.getAttribute("data-cx-filter"))})},querySortHeader(id){const query=this.pendingQuery||this.acceptedQuery,state=query.sort&&query.sort.column===id?query.sort.direction:null;this.sort(id,state==="asc"?"desc":state==="desc"?null:"asc").catch(()=>{})}});Object.assign(TreeGrid.prototype,{retireWrapper(w){w._invalidated=true;this.retirePage(w);if(this.inlineRetained&&this.inlineRetained.get(w.key)===w)this.inlineRetained.delete(w.key);if(this.inactiveCache)this.inactiveCache.delete(w);if(this.keyMap.get(w.key)===w)this.keyMap.delete(w.key);w.children=null;w.inlineCache=null;w.inlineOrder=null;const selected=this.selected.delete(w);if(this.anchor===w)this.anchor=null;return selected?w:null}});Object.assign(TreeGrid.prototype,{build(){const host=this.host;host.classList.add("cx-host");watchTheme(host,this.lifetime.signal);host.style.setProperty("--cx-row-h",this.rowH+"px");this.setTreeColumnPinned(this.view.pinTreeColumn);this.toolbar=h("div","cx-toolbar");this.toolbar.hidden=true;const grid=this.grid=h("div","cx-grid");grid.id=this.id;grid.setAttribute("role","treegrid");grid.setAttribute("aria-label",this.view.label);if(this.multi){grid.setAttribute("aria-multiselectable","true")}
285
+ Object.assign(TreeGrid.prototype,{getQuery(){return{version:1,sort:this.sortState&&Object.assign({},this.sortState),filters:Array.from(this.activeFilters)}},sourceRequest(signal){return this.queryAware?{signal:signal||this.dataLifetime.signal,query:this.acceptedQuery,revision:this.datasetRevision}:{signal}},syncQueryControls(){this.toolbar.querySelectorAll("[data-cx-filter]").forEach(input=>{input.checked=this.activeFilters.has(input.getAttribute("data-cx-filter"))})},querySortHeader(id){const query=this.pendingQuery||this.acceptedQuery,state=query.sort&&query.sort.column===id?query.sort.direction:null;this.sort(id,state==="asc"?"desc":state==="desc"?null:"asc").catch(()=>{})}});Object.assign(TreeGrid.prototype,{retireWrapper(w){w._invalidated=true;this.retirePage(w);if(this.inlineRetained&&this.inlineRetained.get(w.key)===w)this.inlineRetained.delete(w.key);if(this.inactiveCache)this.inactiveCache.delete(w);if(this.keyMap.get(w.key)===w)this.keyMap.delete(w.key);w.children=null;w.inlineCache=null;w.inlineOrder=null;const selected=this.selected.delete(w);if(this.anchor===w)this.anchor=null;return selected?w:null}});Object.assign(TreeGrid.prototype,{build(){const host=this.host;host.classList.add("cx-host");watchTheme(host,this.lifetime.signal);host.style.setProperty("--cx-row-h",this.rowH+"px");this.setTreeColumnPinned(this.view.pinTreeColumn);this.toolbar=h("div","cx-toolbar");this.toolbar.hidden=true;const grid=this.grid=h("div","cx-grid");grid.id=this.id;grid.setAttribute("role","treegrid");grid.setAttribute("data-cx-finish-allow","empty-band");grid.setAttribute("aria-label",this.view.label);if(this.multi){grid.setAttribute("aria-multiselectable","true")}
282
286
  this.head=h("div","cx-head");this.head.setAttribute("role","rowgroup");this.headRow=h("div","cx-hrow");this.headRow.setAttribute("role","row");this.headRow.setAttribute("aria-rowindex","1");this.head.appendChild(this.headRow);this.canvas=h("div","cx-canvas");this.canvas.setAttribute("role","rowgroup");grid.appendChild(this.head);grid.appendChild(this.canvas);this.live=h("div","cx-live cx-sr-only");this.live.setAttribute("aria-live","polite");this.outline=h("div","cx-outline");host.appendChild(this.toolbar);host.appendChild(grid);host.appendChild(this.live);host.appendChild(this.outline);this.buildHeader();this.onScroll=()=>{this.scheduleRender();this.stateChanged()};this.onPrint=()=>{const table=this.outlineElement();this.outline.replaceChildren(...table?[table]:[])};grid.addEventListener("scroll",this.onScroll,{passive:true});grid.addEventListener("click",(e)=>this.onClick(e));grid.addEventListener("dblclick",(e)=>this.onDblClick(e));grid.addEventListener("pointerover",(e)=>this.cellTip(e));grid.addEventListener("keydown",(e)=>this.onKey(e));this.canvas.addEventListener("focusin",(e)=>{const rowEl=e.target.closest(".cx-row");if(rowEl&&rowEl._w&&this.focused!==rowEl._w){this.focusRevision=(this.focusRevision||0)+ 1;this.focused=rowEl._w;this.scheduleRender()}});this.canvas.addEventListener("focusout",(e)=>this.settleCell(e.relatedTarget));global.addEventListener("beforeprint",this.onPrint);this.onHash=(e)=>{const href=global.location.href;const last=this.locationEvent;this.locationEvent=last&&last.href===href&&last.type!==e.type?null:{href,type:e.type};if(this.locationEvent)this.readLocation()};global.addEventListener("hashchange",this.onHash);global.addEventListener("popstate",this.onHash);const viewWidth=()=>{if(grid.clientWidth)host.style.setProperty("--cx-view-w",grid.clientWidth+"px")};viewWidth();this.resizeObserver=new ResizeObserver(()=>{viewWidth();this.scheduleRender()});this.resizeObserver.observe(grid)},visibleColumns(){return this.columns.filter((column)=>!column.hidden)},buildHeader(){const active=document.activeElement;const focusedColumn=active&&this.headRow.contains(active)?active.closest(".cx-hcell").getAttribute("data-cx-column"):null;const focusedResize=active&&active.classList.contains("cx-resize");const nextCols=this.visibleColumns();const layoutChanged=!this.cols||this.cols.length!==nextCols.length||nextCols.some((column,i)=>column!==this.cols[i]);this.cols=nextCols;this.columnIndex=this.cols.map((column)=>this.columns.indexOf(column));if(layoutChanged){this.layout=(this.layout||0)+ 1;this.version++}
283
287
  this.grid.setAttribute("aria-colcount",String(this.cols.length));this.headRow.textContent="";this.headCells=this.cols.map((column,i)=>{const cell=h("div","cx-hcell cx-kind-" +(column.kind||"text"));cell.setAttribute("role","columnheader");cell.setAttribute("aria-label",column.title);if(column.headerDescription)cell.setAttribute("aria-description",column.headerDescription);cell.title=column.headerDescription??column.title;cell.setAttribute("data-cx-column",column.id);cell.setAttribute("aria-colindex",String(i+1));if(column.sortable){const sorted=this.sortState&&this.sortState.column===column.id?this.sortState.direction:null;cell.setAttribute("aria-sort",sorted==="asc"?"ascending":sorted==="desc"?"descending":"none");const button=h("button","cx-sort");button.type="button";button.title=column.headerDescription??column.title;setText(button,column.title);button.addEventListener("click",(event)=>this.queryAware?this.querySortHeader(column.id,event):this.sort(column.id,sorted==="asc"?"desc":sorted==="desc"?null:"asc"));cell.appendChild(button)}else{const title=h("span","cx-htext");title.title=column.headerDescription??column.title;setText(title,column.title);cell.appendChild(title)}
284
288
  const grip=h("span","cx-resize");grip.setAttribute("aria-label",fill(this.labels.resizeColumn,{column:column.title}));grip.tabIndex=0;grip.setAttribute("role","separator");grip.setAttribute("aria-orientation","vertical");grip.setAttribute("aria-valuemin",column.minW);grip.setAttribute("aria-valuemax",column.maxW);grip.addEventListener("keydown",(e)=>{if(!["ArrowLeft","ArrowRight","Home"].includes(e.key))return;e.preventDefault();e.stopPropagation();column.width=columnWidth(column,e.key==="Home"?40:column.width +(e.key==="ArrowLeft"?-1:1)*(e.shiftKey?50:10));this.applyWidths();this.stateChanged()});grip.addEventListener("pointerdown",(e)=>this.startResize(e,column));cell.appendChild(grip);this.headRow.appendChild(cell);return cell});this.applyWidths();if(focusedColumn){const index=this.cols.findIndex((c)=>c.id===focusedColumn);const button=index>=0?this.headCells[index].querySelector(focusedResize?".cx-resize":".cx-sort"):null;if(button){button.focus()}}},rowCount(){return this.rows.length},rowItem(index){return this.rows[index]},rowTop(index){return this.tops[index]},rowAt(y){const tops=this.tops;let lo=0;let hi=this.rows.length-1;while(lo<hi){const mid=(lo+hi+1)>>1;if(tops[mid]<=y){lo=mid}else{hi=mid-1}}
@@ -508,11 +512,10 @@ fill(this.labels.itemsLoaded,{count:count.format(items.length)}));this.stateChan
508
512
  const exportFormatIds=list=>Array.isArray(list)&&new Set(list).size===list.length&&list.every(exportFormatId);function exportFormat(format){if(!format||!exportFormatId(format.id)||format.id==="csv"||
509
513
  typeof format.label!=="string"||!format.label.trim()||typeof format.extension!=="string"||!/^[a-z\d]{1,16}$/i.test(format.extension) ||
510
514
  format.mime!==undefined&&typeof format.mime!=="string"||
515
+ format.values!==undefined&&!["raw","display"].includes(format.values)||
511
516
  format.showInMenu!==undefined&&typeof format.showInMenu!=="boolean"||typeof format.write!=="function")
512
- throw new Error("CanopyX: invalid export format.");return Object.freeze({id:format.id,label:format.label,extension:format.extension,mime:format.mime||"application/octet-stream",showInMenu:format.showInMenu!==false,write:format.write})}
517
+ throw new Error("CanopyX: invalid export format.");return Object.freeze({id:format.id,label:format.label,extension:format.extension,mime:format.mime||"application/octet-stream",showInMenu:format.showInMenu!==false,values:format.values,write:format.write})}
513
518
  function registerExportFormat(format){format=exportFormat(format);EXPORT_FORMATS.set(format.id,format);return()=>EXPORT_FORMATS.get(format.id)===format&&EXPORT_FORMATS.delete(format.id)}
514
- EXPORT_IMPL.formatsOf=function(grid){const list=grid.opts.exportFormats??grid.view.exportFormats,known=new Map(EXPORT_FORMATS);for(const format of grid.plugins.filter(item=>(grid.opts.plugins||[]).some(local=>local.name===item.name))
515
- .flatMap(item=>item.exportFormats||[]))known.set(format.id,exportFormat(format));if(list===undefined)return[...known.values()];const formats=Array.isArray(list)?list.map(item=>typeof item==="string"?known.get(item):exportFormat(item)).filter(Boolean):null;if(!formats||new Set(formats.map(format=>format.id)).size!==formats.length)throw new Error("CanopyX: invalid exportFormats.");return formats};function exportTimeout(grid,options){const timeout=options?.timeoutMs??grid.opts.exportTimeoutMs??600000;if(!Number.isInteger(timeout)||timeout<1||timeout>2147483647)throw new Error("CanopyX: invalid export timeout.");return timeout}
516
519
  Object.assign(TreeGrid.prototype,{buildToolbar(){const bar=this.toolbar,tools=this.tools;if(this.view.search&&this.source.canSearch&&tools.search!==false)this.buildSearch(bar,this.view.search);if(tools.filters!==false)(this.view.filters||[]).forEach((filter)=>{if(filter.hidden)return;const label=h("label","cx-switch");const input=h("input");input.type="checkbox";input.setAttribute("data-cx-filter",filter.id);input.addEventListener("change",()=>{const pending=this.setFilterActive(filter.id,input.checked);if(pending&&pending.catch)pending.catch(()=>{})});label.appendChild(input);label.appendChild(document.createTextNode(filter.label));bar.appendChild(label)});this.syncToolbar();this.toolsReady=loadPart(TREE_TOOLS).then(()=>this.destroyed||this.installTools()).catch(error=>this.emit("error",{error}))},syncToolbar(){this.toolbar.hidden=!this.toolbar.firstChild||this.opts.toolbar===false},syncColumnControls(){},clearDeclaredFilters(){if(!this.activeFilters.size){return}
517
520
  this.activeFilters.clear();this.toolbar.querySelectorAll("[data-cx-filter]").forEach((input)=>{input.checked=false});this.emit("filter",{active:[]});this.stateChanged()},buildSearch(bar,options){const box=h("div","cx-search");const input=h("input","cx-search-input");const list=h("ul","cx-results");const status=h("span","cx-sr-only");list.id=this.id+"-results";list.hidden=true;const labels=this.labels;const count=(value)=>numberFormat(this.lang).format(value);list.setAttribute("role","listbox");list.setAttribute("aria-label",labels.searchResults);input.type="search";input.placeholder=options.placeholder||labels.searchPlaceholder;input.setAttribute("aria-label",options.placeholder||labels.searchPlaceholder);input.setAttribute("role","combobox");input.setAttribute("aria-autocomplete","list");input.setAttribute("aria-expanded","false");input.setAttribute("aria-controls",list.id);status.setAttribute("aria-live","polite");let timer=0;let blurTimer=0;let sequence=0;let navigation=null;const cancelNavigation=()=>{if(navigation)navigation.abort()};let hits=[];let active=-1;const close=()=>{list.hidden=true;active=-1;input.setAttribute("aria-expanded","false");input.removeAttribute("aria-activedescendant")};const flyout=watchFlyout(box,list,()=>!list.hidden);this.disposeSearchFlyout=flyout.dispose;const choose=async(index)=>{const hit=hits[index];if(!hit){return}
518
521
  cancelNavigation();const current=navigation=new AbortController();close();try{await this.expandPath(hit.path,{select:true,focus:true,signal:current.signal})}catch(err){if(!this.destroyed&&!current.signal.aborted)setText(status,fill(labels.searchFailed,{error:err.message}))}};const show=(result)=>{hits=result.hits||[];list.textContent="";hits.forEach((hit,index)=>{const item=h("li","cx-result");item.id=list.id+"-"+index;item.setAttribute("role","option");item.setAttribute("aria-selected","false");const label=h("span","cx-result-label");setText(label,hit.label);item.appendChild(label);if(hit.kind){const kind=h("span","cx-result-kind");setText(kind,hit.kind);item.appendChild(kind)}
@@ -524,8 +527,10 @@ fill(labels.searchFailed,{error:err&&err.message?err.message:err}))}}};const mov
524
527
  if(active>=0){list.children[active].setAttribute("aria-selected","false")}
525
528
  active=active<0?(delta<0?hits.length-1:0):(active+delta+hits.length)%hits.length;const item=list.children[active];item.setAttribute("aria-selected","true");input.setAttribute("aria-activedescendant",item.id);item.scrollIntoView({block:"nearest"})};input.addEventListener("input",()=>{cancelNavigation();sequence++;clearTimeout(timer);hits=[];close();timer=setTimeout(run,150)});input.addEventListener("keydown",(e)=>{if(e.defaultPrevented||e.isComposing)return;if(e.key==="ArrowDown"||e.key==="ArrowUp"){move(e.key==="ArrowDown"?1:-1)}else if(e.key==="Enter"){if(!list.hidden){choose(active>=0?active:0)}}else if(e.key==="Escape"){cancelNavigation();sequence++;clearTimeout(timer);if(list.hidden){input.value=""}
526
529
  close()}else{return}
527
- e.preventDefault()});input.addEventListener("blur",()=>{cancelNavigation();sequence++;clearTimeout(timer);clearTimeout(blurTimer);blurTimer=setTimeout(close,150)});this.cancelSearch=()=>{cancelNavigation();sequence++;clearTimeout(timer);clearTimeout(blurTimer);hits=[];close()};box.appendChild(input);box.appendChild(list);box.appendChild(status);bar.appendChild(box);this.searchInput=input}});function watchFlyout(anchorElement,panel,isOpen){const position=()=>{if(!isOpen())return;const anchor=anchorElement.getBoundingClientRect(),fixed=getComputedStyle(panel).position==="fixed";const below=Math.max(0,global.innerHeight-anchor.bottom-8);const above=Math.max(0,anchor.top-8);const opensAbove=below<120&&above>below,room=opensAbove?above:below;panel.style.maxHeight=(panel.classList.contains("cx-fb")?room:Math.min(320,room))+ "px";panel.style.top=opensAbove?"auto":fixed?anchor.bottom+"px":"100%";panel.style.bottom=opensAbove?fixed?global.innerHeight-anchor.top+"px":"100%":"auto";const width=panel.getBoundingClientRect().width;panel.style.left=Math.max(8,Math.min(anchor.left,global.innerWidth-width-8))-(fixed?0:anchor.left)+ "px"};global.addEventListener("resize",position);global.addEventListener("scroll",position,true);return{position,dispose:()=>{global.removeEventListener("resize",position);global.removeEventListener("scroll",position,true)}}}
528
- const PART_URL=typeof document!=="undefined"&&document.currentScript?.src;const PARTS={"tree-tools":["ee95c5cc39223ef4","canopyx-tree-tools.ab224d048d87d4a8.js","canopyx-tree-tools.3a4ac9c0bfe85039.css"],"export":["9203882f58fa0155","canopyx-export.cedfec6462c161b4.js"],"links":["f1ab7e32b501ce37","canopyx-links.d96addeefb3eccf5.js"],"search":["521eebd6e1bbbd35","canopyx-search.14c69f4551c69f23.js"],"link":["e7268bbe59e2dfa8","canopyx-link.e883be9525ead7b7.js","canopyx-link.b872151e9cbbd0ce.css"],"highlight":["459b28e174406d32","canopyx-highlight.10ef4bb28c5a8f5b.js","canopyx-highlight.ab1040f93cbb5dbb.css"],"layouts":["606fcf6dcd00d420","canopyx-layouts.606c8fe836149ffe.js","canopyx-layouts.56a636b0f1a03185.css"],"record-panel":["82aa828bc880087b","canopyx-record-panel.e0736e2285995701.js","canopyx-record-panel.4b9f1a99c5b76321.css"]},PART_CODE=new Map(),partName=name=>typeof name==="string"&&/^[a-z][a-z\d-]{0,31}$/.test(name);
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
+ ready().then(value=>{if(!lifetime.signal.aborted&&isOpen())value?.[method]()}).catch(error=>{if(!lifetime.signal.aborted)(anchorElement.closest(".cx-host")||anchorElement)
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"],"export":["fa85a4b0e8aead4a","canopyx-export.f18d1ef109ccf0c6.js"],"office-export":["4fb7a4d570390ee9","canopyx-office-export.7e62c385b884e75b.js"],"links":["f1ab7e32b501ce37","canopyx-links.d96addeefb3eccf5.js"],"search":["521eebd6e1bbbd35","canopyx-search.14c69f4551c69f23.js"],"link":["fd21dd4495607a16","canopyx-link.5874879aadd6cefb.js","canopyx-link.b872151e9cbbd0ce.css"],"highlight":["459b28e174406d32","canopyx-highlight.10ef4bb28c5a8f5b.js","canopyx-highlight.ab1040f93cbb5dbb.css"],"layouts":["077268d4fb78c464","canopyx-layouts.9a318c748cde4c84.js","canopyx-layouts.18dbf5842f1c5efd.css"],"record-panel":["2a4059ade4ca1439","canopyx-record-panel.4f525c01ecbd0e07.js","canopyx-record-panel.f1d740569605e625.css"]},PART_CODE=new Map(),SHARED_PARTS={},partName=name=>typeof name==="string"&&/^[a-z][a-z\d-]{0,31}$/.test(name);
529
534
  function registerPart(name,part){if(!partName(name)||!part||typeof part.version!=="string"||typeof part.install!=="function"||
530
535
  part.requires!==undefined&&!(Array.isArray(part.requires)&&part.requires.every(partName)))throw new Error("CanopyX: invalid part.");PART_CODE.set(name,part)}
531
536
  function definePart(View,name,label,context){const parts=View.prototype.parts||={};return parts[name]={name,label,context,parts}}
@@ -534,8 +539,8 @@ script.textContent=trusted("Script",payload.textContent);script.nonce=payload.no
534
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")
535
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")
536
541
  .finally(()=>script.remove()).catch(error=>{part.scriptReady=null;throw error}));await Promise.all([style,code])}}
537
- const code=PART_CODE.get(part.name);if(code?.version!==part.version)throw new Error("CanopyX: "+part.label+" and runtime must come from the same build.");for(const name of code.requires||[])await loadPart(part.parts[name]);code.install(part.context())}).catch(error=>{part.ready=null;throw error})}
538
- const partQueue=global.CanopyXParts=global.CanopyXParts||[];partQueue.forEach(entry=>registerPart(...entry));partQueue.length=0;partQueue.push=(...entries)=>{entries.forEach(entry=>registerPart(...entry));return 0};const TREE_TOOLS=definePart(TreeGrid,"tree-tools","tree tools",()=>({TreeGrid,h,setText,fill,numberFormat,watchFlyout,columnWidth,prepareWidth,cellText,cellValue,isCellObject,foldText,formatting,sortKey,compareKeys,EXPORT_FORMATS,exportFormat,exportTimeout,exportFormatsOf:EXPORT_IMPL.formatsOf,INDENT,MAX_PROTOCOL_INTEGER,hostControl,detailCell,HostCellContext,disposeHostSlot,loadPart,definePart,pluginItems,applyTone,toneOf,badgeElement,RECORD_IMPL,svgIcon,gridExportField,columnNumericTone,columnValueTone,overlayTheme}));const SEARCH_IMPL={},SEARCH_PART=definePart(TreeGrid,"search","sidecar search",()=>({SEARCH_IMPL,checkDocument,badIndex,isCount,isIdentifier,recentCache,packBytes,shardKey,foldText,trimSeparators,rankHits,validateSearchHit,PACK_CACHE,PACK_CACHE_BYTES,SHARD_CACHE,ENTRY_CACHE,ENTRY_BATCH,SEARCH_CANDIDATES}));async function requirePart(name){await this.toolsReady;const part=Object.hasOwn(this.parts,name)?this.parts[name]:null;if(!part)throw new Error("CanopyX: unknown part '"+name+"'.");return loadPart(part)}
542
+ const code=PART_CODE.get(part.name);if(code?.version!==part.version)throw new Error("CanopyX: "+part.label+" and runtime must come from the same build.");for(const name of code.requires||[])await loadPart(part.parts[name]||SHARED_PARTS[name]);code.install(part.context())}).catch(error=>{part.ready=null;throw error})}
543
+ const partQueue=global.CanopyXParts=global.CanopyXParts||[];partQueue.forEach(entry=>registerPart(...entry));partQueue.length=0;partQueue.push=(...entries)=>{entries.forEach(entry=>registerPart(...entry));return 0};const TREE_TOOLS=definePart(TreeGrid,"tree-tools","tree tools",()=>({TreeGrid,h,setText,fill,numberFormat,watchFlyout,columnWidth,prepareWidth,cellText,cellValue,isCellObject,foldText,formatting,sortKey,compareKeys,EXPORT_FORMATS,exportFormat,INDENT,MAX_PROTOCOL_INTEGER,hostControl,detailCell,HostCellContext,disposeHostSlot,loadPart,definePart,pluginItems,applyTone,toneOf,badgeElement,RECORD_IMPL,svgIcon,gridExportField,columnNumericTone,columnValueTone,overlayTheme,UI_IMPL,UI_TOOLS}));const SEARCH_IMPL={},SEARCH_PART=definePart(TreeGrid,"search","sidecar search",()=>({SEARCH_IMPL,checkDocument,badIndex,isCount,isIdentifier,recentCache,packBytes,shardKey,foldText,trimSeparators,rankHits,validateSearchHit,PACK_CACHE,PACK_CACHE_BYTES,SHARD_CACHE,ENTRY_CACHE,ENTRY_BATCH,SEARCH_CANDIDATES}));async function requirePart(name){await this.toolsReady;const part=Object.hasOwn(this.parts,name)?this.parts[name]:SHARED_PARTS[name];if(!part)throw new Error("CanopyX: unknown part '"+name+"'.");return loadPart(part)}
539
544
  TreeGrid.prototype.requirePart=requirePart;function readStateColumn(c,seen){requireIdentifier(c&&c.id,"state column ID");if(seen.has(c.id)||!Number.isFinite(c.width)||c.width<40||c.width>MAX_COLUMN_WIDTH||typeof c.hidden!=="boolean")
540
545
  throw new Error("CanopyX: invalid state column.");seen.add(c.id);return{id:c.id,width:c.width,hidden:c.hidden}}
541
546
  function statePaths(value){if(!Array.isArray(value))throw new Error("CanopyX: state paths must be arrays.");return value.map(path=>{if(!Array.isArray(path)||!path.length)throw new Error("CanopyX: state paths cannot be empty.");return path.map(id=>{requireIdentifier(id,"state path ID");return id})})}
@@ -586,7 +591,12 @@ w.content=nodeContent(w.h)});this.inlineOrderVersion=(this.inlineOrderVersion||0
586
591
  const wanted=Array.from(new Set(ids||this.rows.filter((w)=>!w.status).map((w)=>w.key)));const mine=new Map();for(const id of wanted){const w=this.keyMap.get(id);if(w){w.countRevision=(w.countRevision||0)+ 1;mine.set(id,{w,revision:w.countRevision})}}
587
592
  const navigation=navigationScope(this,this.dataLifetime.signal);let doc;try{doc=await navigation.wait(this.source.counts(wanted,this.sourceRequest(this.dataLifetime.signal)))}
588
593
  finally{navigation.dispose()}
589
- if(navigation.cancelled())return null;if(this.queryAware)snapshotRevision(doc,this.datasetRevision);checkDocument(doc,"counts");this.applyCounts(Object.assign({},doc,{items:doc.items.filter(item=>{const captured=mine.get(item.id);return captured&&this.keyMap.get(item.id)===captured.w&&captured.w.countRevision===captured.revision})}),true);return doc}});const LINKS=definePart(TreeGrid,"links","deep links",()=>({TreeGrid,navigationScope}));for(const name of["openDeepLink","writeDeepLink"])TreeGrid.prototype[name]=function(...args){return this.view.deepLink?loadPart(LINKS).then(()=>this[name](...args),error=>this.emit("error",{error})):Promise.resolve()};TreeGrid.prototype.readLocation=function(){if(this.destroyed)return Promise.resolve();if(this.initializing){if(this.linkOpening&&this.currentLink()!==this.link){this.linkOpening.abort();this.link=null;// Deferred reopening must not reuse the canceled link if the address changes back.
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}
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
+ 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
+ return mounted}
599
+ const UI_API={mountUi,contextMenu:bindContextMenu};for(const kind of Object.keys(UI_KINDS))UI_API[kind]=(target,options)=>createUi(kind,target,options);const LINKS=definePart(TreeGrid,"links","deep links",()=>({TreeGrid,navigationScope}));for(const name of["openDeepLink","writeDeepLink"])TreeGrid.prototype[name]=function(...args){return this.view.deepLink?loadPart(LINKS).then(()=>this[name](...args),error=>this.emit("error",{error})):Promise.resolve()};TreeGrid.prototype.readLocation=function(){if(this.destroyed)return Promise.resolve();if(this.initializing){if(this.linkOpening&&this.currentLink()!==this.link){this.linkOpening.abort();this.link=null;// Deferred reopening must not reuse the canceled link if the address changes back.
590
600
  }
591
601
  this.linkChanged=this.dataLifetime.signal;return this.ready.then(()=>undefined,()=>undefined)}
592
602
  return this.openDeepLink()};function sharedDensity(host){const value=host.closest("[data-hfx-density]")?.getAttribute("data-hfx-density");return value==="compact"||value==="comfortable"?value:null}
@@ -607,7 +617,7 @@ DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{linkFilteredBy:"Fi
607
617
  linkMethods(TreeGrid);function linkGridPart(View){(Object.hasOwn(View.prototype,"parts")?View.prototype.parts:View.prototype.parts={}).link=LINK_PART}
608
618
  function linkReady(grid,ready){return Promise.all([ready,grid.linkStart()]).then(([result])=>result)}
609
619
  function linkApi(grid){const api={};for(const name of LINK_METHODS.concat("getExternalFilters","getHighlight"))api[name]=(...args)=>grid[name](...args);return api}
610
- const RECORD_IMPL={},RECORD_PART=definePart(TreeGrid,"record-panel","record panel",()=>({RECORD_IMPL,TreeGrid,h,setText,fill,cellText,cellValue,isCellObject,formatValue,toneOf,applyTone,toneColors,badgeElement,loadSidecar,requireIdentifier,validateGridRows,PROTOCOL,foldText,createTreeGrid,svgIcon,gridExportField,columnNumericTone,columnValueTone,validateColumnValues}));function loadRecordPanel(){return loadPart(RECORD_PART)}
620
+ const RECORD_IMPL={},RECORD_PART=definePart(TreeGrid,"record-panel","record panel",()=>({RECORD_IMPL,UI_IMPL,TreeGrid,h,setText,fill,cellText,cellValue,isCellObject,formatValue,toneOf,applyTone,toneColors,badgeElement,loadSidecar,requireIdentifier,validateGridRows,PROTOCOL,foldText,createTreeGrid,svgIcon,gridExportField,columnNumericTone,columnValueTone,validateColumnValues}));function loadRecordPanel(){return loadPart(RECORD_PART)}
611
621
  const RECORD_STRUCTURE=["items","fields","records","events","changes","ref"];TreeGrid.prototype.recordNeeded=function(node){return!!this.view.record||!!node&&(!!node.fields||Object.values(node.cells||{}).some(cell=>isCellObject(cell)&&RECORD_STRUCTURE.some(name=>cell[name]!==undefined)))};TreeGrid.prototype.openRecord=function(id,options){return loadRecordPanel().then(()=>RECORD_IMPL.open(this,id,options))};function recordStart(grid){if(grid.view.record?.deepLink)loadRecordPanel().then(()=>RECORD_IMPL.start(grid),error=>grid.emit("error",{error}))}
612
622
  DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{matchesHighlight:"Highlight matches",matchesCount:"[one]{count} match[other]{count} matches",matchesPosition:"{current} of {count}",matchesNone:"No matches",matchesLoaded:"[one]{count} match in loaded rows[other]{count} matches in loaded rows",matchesPrevious:"Previous match",matchesNext:"Next match",matchesAnnounce:"Match {current} of {count}, {column}",layoutMenu:"Layout",layoutFit:"Fit to width",layoutScroll:"All columns, scroll sideways",layoutCards:"Cards",layoutDensity:"Density",layoutCompact:"Compact",layoutNormal:"Normal",layoutComfortable:"Comfortable",layoutChanged:"Layout: {mode}, {density}",layoutSort:"Sort by"}));const LAYOUT_MODES=["fit","scroll","cards"],LAYOUT_DENSITIES=["compact","default","comfortable"];const DENSITY_STEP={tree:{compact:-8,default:0,comfortable:0},grid:{compact:-8,default:0,comfortable:0}};const VIEW_MODES={};const HIGHLIGHT_KEYS=["enabled","search","filters","matchCase","ignoreAccents","minLength","filterTones"];function readSearchHighlight(value,columns){if(value===undefined||value===false)return null;const options=value===true?{}:value,tone=name=>typeof name==="string"&&/^[a-z][a-z0-9-]{0,31}$/.test(name) && !name.endsWith("-bg");
613
623
  if(!options||typeof options!=="object"||Array.isArray(options)||Object.keys(options).some(key=>!HIGHLIGHT_KEYS.includes(key))||
@@ -629,7 +639,7 @@ function densityRowHeight(view,density){const shared=sharedDensity(view.host);if
629
639
  const VIEW_MODE_METHODS={prepareViewModes(){const view=this.view,columns=this.columns||view.columns;this.highlightOptions=readSearchHighlight(view.searchHighlight,columns);this.declaredDensity=this.kind==="grid"?view.density||"default":"default";this.layoutOptions=readLayout(view.layout,this.kind,this.declaredDensity);this.baseRowH=this.rowH;this.adoptModes({layout:this.layoutOptions||{mode:"fit",density:this.declaredDensity},highlight:!!this.highlightOptions?.enabled});watchSharedDensity(this)},adoptModes(choice){if(choice.layout){this.layoutMode=choice.layout.mode;this.density=choice.layout.density}
630
640
  if(choice.highlight!==undefined)this.highlightOn=choice.highlight;this.rowH=densityRowHeight(this,this.density);if(this.layoutMode==="fit")this.host.removeAttribute("data-cx-layout");else this.host.setAttribute("data-cx-layout",this.layoutMode)},modeState(state){if(this.layoutOptions)state.layout={mode:this.layoutMode,density:this.density};if(this.highlightOptions)state.highlight=!!this.highlightOn;return state},applyModeState(state){if(state.layout&&(state.layout.mode!==this.layoutMode||state.layout.density!==this.density))
631
641
  this.setLayout(state.layout).catch(error=>this.emit("error",{error}));if(state.highlight!==undefined&&state.highlight!==!!this.highlightOn)
632
- this.setSearchHighlight(state.highlight).catch(error=>this.emit("error",{error}))},startViewModes(){const parts=[this.highlightOptions&&"highlight",this.layoutOptions&&"layouts"].filter(Boolean);return Promise.all(parts.map(name=>this.requirePart(name).then(()=>this.destroyed||VIEW_MODES[name+"Start"](this))
642
+ this.setSearchHighlight(state.highlight).catch(error=>this.emit("error",{error}))},startViewModes(){const parts=[this.highlightOptions&&"highlight",(this.layoutOptions||this.view.stickyHeader)&&"layouts"].filter(Boolean);return Promise.all(parts.map(name=>this.requirePart(name).then(()=>this.destroyed||VIEW_MODES[name+"Start"](this))
633
643
  .catch(error=>this.emit("error",{error}))))},getLayout(){return Object.freeze({mode:this.layoutMode,density:this.density,modes:this.layoutOptions?this.layoutOptions.modes:Object.freeze(["fit"])})},setLayout(change){if(!this.layoutOptions)return Promise.reject(new Error("CanopyX: this view declares no layout modes."));return this.requirePart("layouts").then(()=>VIEW_MODES.setLayout(this,change))},getMatches(){return VIEW_MODES.matches?VIEW_MODES.matches(this):Object.freeze({enabled:!!this.highlightOn,total:0,current:0,complete:true})},setSearchHighlight(enabled){if(typeof enabled!=="boolean")return Promise.reject(new Error("CanopyX: the highlight switch is a boolean."));if(!this.highlightOptions)return Promise.reject(new Error("CanopyX: this view declares no search highlighting."));return this.requirePart("highlight").then(()=>VIEW_MODES.setHighlight(this,enabled))},nextMatch(options){return this.stepMatch(1,options)},previousMatch(options){return this.stepMatch(-1,options)},stepMatch(direction,options){if(!this.highlightOptions)return Promise.reject(new Error("CanopyX: this view declares no search highlighting."));return this.requirePart("highlight").then(()=>VIEW_MODES.step(this,direction,options?.focus!==false))}};Object.assign(TreeGrid.prototype,VIEW_MODE_METHODS);const viewModeContext=()=>({VIEW_MODES,TreeGrid,h,setText,fill,numberFormat,foldText,cellText,cellValue,isCellObject,setAttr,toneOf,toneVariable,watchFlyout,densityRowHeight,layoutAnchor,layoutRows,layoutApplyTree,MAX_PROTOCOL_INTEGER,LAYOUT_DENSITIES,plural,svgIcon});definePart(TreeGrid,"highlight","search highlighting",viewModeContext);definePart(TreeGrid,"layouts","layout modes",viewModeContext);const MODES_TOOLBAR=TreeGrid.prototype.buildToolbar;TreeGrid.prototype.buildToolbar=function(){MODES_TOOLBAR.call(this);if(this.highlightOptions||this.layoutOptions)this.modesReady=Promise.resolve(this.toolsReady).then(()=>this.destroyed||this.startViewModes());this.lifetime.signal.addEventListener("abort",()=>this.host.removeAttribute("data-cx-layout"),{once:true})};Object.assign(TreeGrid.prototype,{destroy(){if(this.destroyed)return;this.destroyed=true;for(const row of[...this.rendered.values(),...this.pool])disposeRowHostCells(row);this.lifetime.abort();this.dataLifetime.abort();if(this.queryController)this.queryController.abort();if(this.restoreController)this.restoreController.abort();if(this.cancelResize)this.cancelResize();clearTimeout(this.saveTimer);clearTimeout(this.layoutTimer);if(this.cancelSearch)this.cancelSearch();if(this.disposeSearchFlyout)this.disposeSearchFlyout();cancelAnimationFrame(this.rafId);this.resizeObserver.disconnect();if(this.detailObserver)this.detailObserver.disconnect();this.grid.removeEventListener("scroll",this.onScroll);this.grid.removeEventListener("wheel",this.onScaledWheel);this.grid.removeEventListener("touchstart",this.onScaledTouchStart);this.grid.removeEventListener("touchmove",this.onScaledTouchMove);this.grid.removeEventListener("touchend",this.onScaledTouchEnd);this.grid.removeEventListener("touchcancel",this.onScaledTouchEnd);global.removeEventListener("beforeprint",this.onPrint);global.removeEventListener("hashchange",this.onHash);global.removeEventListener("popstate",this.onHash);if(this.linkOpening)this.linkOpening.abort();[this.toolbar,this.grid,this.live,this.outline].forEach(element=>element.remove());this.host.classList.remove("cx-pin-tree");this.host.removeAttribute("data-cx-ready");this.host.removeAttribute("data-canopyx-mounted");this.keyMap.clear();this.selected.clear();this.rendered.clear();this.pool.length=0;if(this.inactiveCache)this.inactiveCache.clear();if(this.inlineRetained)this.inlineRetained.clear();this.rows=[];this.tops=[0];this.total=0;this.root.children=null;this.root.inlineCache=null;this.root.inlineOrder=null;this.focused=null;this.anchor=null;this.source=null;this.touchScroll=null;this.opts={};for(const column of this.columns)column.render=null;this.filter=null;this.declaredFilter=null;this.pendingRestorationToggles=null;this.scrolledCell=null;this.focusHandoff=null;this.cancelResize=null;this.cancelSearch=null;this.disposeSearchFlyout=null;this.canvas.replaceChildren();this.outline.replaceChildren()}});function createTreeGrid(host,options){if(!host||!options||!options.view){throw new Error("CanopyX: createTreeGrid needs a host element and a view document.")}
634
644
  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"])
635
645
  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);
@@ -644,5 +654,5 @@ watcher.observe(host)}
644
654
  function mount(root,automatic){const scope=root||document;const created=[];const showError=(host,err,api,view)=>{if(api){api.destroy();if(host.canopyx===api)delete host.canopyx}
645
655
  const message=err&&err.message?err.message:String(err);let labels=DEFAULT_LABELS;for(const attempt of[()=>labelsFor(view&&view.labels,view&&configured.has(view.id)?configured.get(view.id).labels:null),()=>labelsFor(view&&view.labels)]){try{labels=attempt();break}catch(e){labels=DEFAULT_LABELS}}
646
656
  const notice=document.createElement("div");notice.className="cx-mount-error";notice.setAttribute("role","alert");setText(notice,fill(labels.mountError,{error:message}));host.classList.add("cx-host");host.setAttribute("data-canopyx-mounted","true");host.setAttribute("data-cx-error",message);host.appendChild(notice);if(global.console)global.console.error(err)};const selector="[data-canopyx-host]:not([data-canopyx-mounted])";(scope.matches?.(selector)?[scope]:scope.querySelectorAll(selector)).forEach((host)=>{const config=host.querySelector("script.cx-config"),mode=host.getAttribute("data-cx-mount");if(!config||(automatic===true&&mode==="manual")){return}
647
- if(mode==="visible"&&host!==scope&&global.IntersectionObserver)return mountWhenVisible(host);watcher?.unobserve(host);host.setAttribute("data-canopyx-mounted","true");let view=null;try{view=JSON.parse(config.textContent);if(view===Object(view))parsedViews.add(view);const flow=view&&view.kind==="flow"&&typeof FLOW_API==="object",matrix=view&&view.type==="matrix"&&typeof MATRIX_API==="object";const change=view&&typeof CHANGE_VIEW_TYPES==="object"&&Object.hasOwn(CHANGE_VIEW_TYPES,view.type)?CHANGE_VIEW_TYPES[view.type]:null;const create=flow?FLOW_API.createFlow:matrix?MATRIX_API.createMatrix:change?change:view&&view.type==="grid"&&typeof createDataGrid==="function"?createDataGrid:createTreeGrid;const api=create(host,Object.assign({},view&&configured.get(view.id),flow?{flow:view}:{view}));created.push(api);api.ready.catch((err)=>{if(view.type!=="grid"&&!matrix&&!change&&activeGrids.get(host)===api&&host.canopyx===api)showError(host,err,api,view)})}catch(err){showError(host,err,null,view)}});return created}
648
- global.CanopyX=Object.freeze(Object.assign({protocol:PROTOCOL,createTreeGrid,configure,unconfigure,mount:(root)=>mount(root,false),sources:Object.freeze({inline:inlineSource,sidecar:sidecarSource,remote:remoteSource}),badge:hostBadge,labels:DEFAULT_LABELS,registerExportFormat,use,registerPart,setNonce},typeof GRID_API==="object"?GRID_API:{},typeof FLOW_API==="object"?FLOW_API:{},typeof MATRIX_API==="object"?MATRIX_API:{},typeof CHANGES_API==="object"?CHANGES_API:{}));const navigation=global.performance&&performance.getEntriesByType?performance.getEntriesByType("navigation")[0]:null;if(document.readyState==="loading"||(document.readyState==="interactive"&&navigation&&navigation.domContentLoadedEventStart===0)){document.addEventListener("DOMContentLoaded",()=>mount(document,true))}else{mount(document,true)}})(typeof window!=="undefined"?window:this);
657
+ if(mode==="visible"&&host!==scope&&global.IntersectionObserver)return mountWhenVisible(host);watcher?.unobserve(host);host.setAttribute("data-canopyx-mounted","true");let view=null;try{view=JSON.parse(config.textContent);if(view===Object(view))parsedViews.add(view);const flow=view&&view.kind==="flow"&&typeof FLOW_API==="object",matrix=view&&view.type==="matrix"&&typeof MATRIX_API==="object";const change=view&&typeof CHANGE_VIEW_TYPES==="object"&&Object.hasOwn(CHANGE_VIEW_TYPES,view.type)?CHANGE_VIEW_TYPES[view.type]:null;const create=flow?FLOW_API.createFlow:matrix?MATRIX_API.createMatrix:change?change:view&&view.type==="grid"&&typeof createDataGrid==="function"?createDataGrid:createTreeGrid;const api=create(host,Object.assign({},view&&configured.get(view.id),flow?{flow:view}:{view}));created.push(api);api.ready.catch((err)=>{if(view.type!=="grid"&&!matrix&&!change&&activeGrids.get(host)===api&&host.canopyx===api)showError(host,err,api,view)})}catch(err){showError(host,err,null,view)}});mountUi(scope);return created}
658
+ global.CanopyX=Object.freeze(Object.assign({protocol:PROTOCOL,createTreeGrid,configure,unconfigure,mount:(root)=>mount(root,false),sources:Object.freeze({inline:inlineSource,sidecar:sidecarSource,remote:remoteSource}),badge:hostBadge,labels:DEFAULT_LABELS,registerExportFormat,use,registerPart,setNonce},typeof GRID_API==="object"?GRID_API:{},typeof FLOW_API==="object"?FLOW_API:{},typeof MATRIX_API==="object"?MATRIX_API:{},typeof CHANGES_API==="object"?CHANGES_API:{},UI_API));const navigation=global.performance&&performance.getEntriesByType?performance.getEntriesByType("navigation")[0]:null;if(document.readyState==="loading"||(document.readyState==="interactive"&&navigation&&navigation.domContentLoadedEventStart===0)){document.addEventListener("DOMContentLoaded",()=>mount(document,true))}else{mount(document,true)}})(typeof window!=="undefined"?window:this);
@@ -0,0 +1,30 @@
1
+ import type { CellValue } from "./protocol.js";
2
+ import type { GridCommit } from "./editing.js";
3
+
4
+ /** Optional board renderer over the grid's records and accepted query. */
5
+ export interface GridBoardDefinition {
6
+ /** Column whose raw scalar values identify the lanes. */
7
+ column: string;
8
+ titleColumn?: string;
9
+ swimlaneColumn?: string;
10
+ /** Up to eight card fields; the compact card displays the first two and the record panel exposes the rest. */
11
+ fields?: string[];
12
+ /** Permit drag, Alt+Left/Right and lane selection to propose an edit. Requires stable keys and an editable lane column. */
13
+ editable?: boolean;
14
+ /** Ordered lane labels and work limits. Values present in records add further lanes. */
15
+ lanes?: { value: CellValue; label: string; wipLimit?: number }[];
16
+ }
17
+
18
+ /** A move changes nothing until a host accepts it or the configured editing writer saves it. */
19
+ export interface GridBoardMove {
20
+ readonly id: string;
21
+ readonly column: string;
22
+ readonly previous: CellValue;
23
+ readonly value: CellValue;
24
+ readonly proposal: GridCommit;
25
+ /** Accept with true; reject with false. One event responder may answer. */
26
+ respondWith(answer: boolean | PromiseLike<boolean>): void;
27
+ }
28
+
29
+ /** Phone lane preference; saved views retain the same query, facets and columns as a grid. */
30
+ export interface GridBoardState { lane: string; }
@@ -1,3 +1,4 @@
1
+ import type { TimePlaybackApi } from "./time-slider.js";
1
2
  // Type declarations for the change views (docs/changes.md): a text diff, a change list and a propagation view.
2
3
 
3
4
  /** A note about a change that the lines cannot show, such as changed line endings. */
@@ -237,10 +238,12 @@ export interface PropagationOptions {
237
238
 
238
239
  /** The API of a propagation view. */
239
240
  export interface PropagationApi {
241
+ /** Snapshot controls; available after ready when the document supplies timeSlider. */
242
+ readonly playback: TimePlaybackApi;
240
243
  readonly element: HTMLElement;
241
244
  readonly view: PropagationDocument;
242
245
  readonly ready: Promise<PropagationApi>;
243
- update(view: PropagationDocument): void;
246
+ update(view: PropagationDocument): void | Promise<void>;
244
247
  destroy(): void;
245
248
  }
246
249
 
@@ -1,9 +1,11 @@
1
1
  // The facet panel of flat grids (docs/facets.md): value lists with counts and ranges with histograms that filter each other.
2
- import type { GridRow, GridColumnId } from "./grid.js";
2
+ import type { GridRow, GridColumnId, GridBucket } from "./grid.js";
3
3
 
4
4
  /** One facet: a column id, or a column with its settings. */
5
5
  export type GridFacet<Row extends GridRow = GridRow> = GridColumnId<Row> | {
6
6
  column: GridColumnId<Row>;
7
+ /** Calendar or numeric partition, shown as a chronological value list. */
8
+ bucket?: GridBucket;
7
9
  /** "list" (text columns by default) or "range" with a histogram (number and date columns by default). */
8
10
  kind?: "list" | "range";
9
11
  /** The facet's heading; the column's title by default. */
@@ -22,8 +24,8 @@ export type GridFacet<Row extends GridRow = GridRow> = GridColumnId<Row> | {
22
24
  export interface GridFacetPanelDefinition<Row extends GridRow = GridRow> {
23
25
  /** 1 to 24 distinct columns; a hosted grid's must be reporting facet columns. */
24
26
  columns: readonly GridFacet<Row>[];
25
- /** Beside the grid (default) or above it. */
26
- position?: "side" | "top";
27
+ /** Beside the grid (default), above it, or as compact toolbar menus. */
28
+ position?: "side" | "top" | "toolbar";
27
29
  /** Starts open (default true); the grid state keeps the reader's choice. */
28
30
  open?: boolean;
29
31
  /** The reader can collapse the panel (default true). */