@evotecit/canopyx 0.3.16 → 0.3.20

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 (150) 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 +74 -80
  8. package/CanopyX.Html/Assets/canopyx-calendar.js +26 -31
  9. package/CanopyX.Html/Assets/canopyx-cell-range.css +4 -4
  10. package/CanopyX.Html/Assets/canopyx-cell-range.js +16 -14
  11. package/CanopyX.Html/Assets/canopyx-changes.css +61 -79
  12. package/CanopyX.Html/Assets/canopyx-changes.js +18 -15
  13. package/CanopyX.Html/Assets/canopyx-column-groups.css +5 -1
  14. package/CanopyX.Html/Assets/canopyx-column-groups.js +15 -9
  15. package/CanopyX.Html/Assets/canopyx-compare.css +37 -0
  16. package/CanopyX.Html/Assets/canopyx-compare.js +12 -0
  17. package/CanopyX.Html/Assets/canopyx-data.js +3 -3
  18. package/CanopyX.Html/Assets/canopyx-detail-rows.css +4 -4
  19. package/CanopyX.Html/Assets/canopyx-detail-rows.js +1 -1
  20. package/CanopyX.Html/Assets/canopyx-editing.css +5 -5
  21. package/CanopyX.Html/Assets/canopyx-editing.js +2 -2
  22. package/CanopyX.Html/Assets/canopyx-enhance.js +5 -5
  23. package/CanopyX.Html/Assets/canopyx-export.js +54 -13
  24. package/CanopyX.Html/Assets/canopyx-facets.css +32 -22
  25. package/CanopyX.Html/Assets/canopyx-facets.js +19 -15
  26. package/CanopyX.Html/Assets/canopyx-filter-editor.css +75 -89
  27. package/CanopyX.Html/Assets/canopyx-filter-editor.js +20 -16
  28. package/CanopyX.Html/Assets/canopyx-flow-checks.css +3 -3
  29. package/CanopyX.Html/Assets/canopyx-flow-checks.js +1 -1
  30. package/CanopyX.Html/Assets/canopyx-flow-command.css +3 -3
  31. package/CanopyX.Html/Assets/canopyx-flow-command.js +1 -1
  32. package/CanopyX.Html/Assets/canopyx-flow-dialog.css +4 -4
  33. package/CanopyX.Html/Assets/canopyx-flow-dialog.js +1 -1
  34. package/CanopyX.Html/Assets/canopyx-flow-drafts.css +2 -2
  35. package/CanopyX.Html/Assets/canopyx-flow-drafts.js +1 -1
  36. package/CanopyX.Html/Assets/canopyx-flow-entry.css +142 -17
  37. package/CanopyX.Html/Assets/canopyx-flow-entry.js +5 -5
  38. package/CanopyX.Html/Assets/canopyx-flow-host.css +2 -2
  39. package/CanopyX.Html/Assets/canopyx-flow-host.js +1 -1
  40. package/CanopyX.Html/Assets/canopyx-flow-module.mjs +5 -5
  41. package/CanopyX.Html/Assets/canopyx-flow-pick.css +4 -4
  42. package/CanopyX.Html/Assets/canopyx-flow-pick.js +1 -1
  43. package/CanopyX.Html/Assets/canopyx-flow-preview.css +1 -1
  44. package/CanopyX.Html/Assets/canopyx-flow-preview.js +1 -1
  45. package/CanopyX.Html/Assets/canopyx-flow-records.css +2 -2
  46. package/CanopyX.Html/Assets/canopyx-flow-records.js +1 -1
  47. package/CanopyX.Html/Assets/canopyx-flow-tasks.css +4 -4
  48. package/CanopyX.Html/Assets/canopyx-flow-tasks.js +1 -1
  49. package/CanopyX.Html/Assets/canopyx-flow.css +41 -41
  50. package/CanopyX.Html/Assets/canopyx-flow.js +1 -1
  51. package/CanopyX.Html/Assets/canopyx-format-editor.css +9 -9
  52. package/CanopyX.Html/Assets/canopyx-format-editor.js +2 -2
  53. package/CanopyX.Html/Assets/canopyx-formatting.css +13 -13
  54. package/CanopyX.Html/Assets/canopyx-formatting.js +12 -11
  55. package/CanopyX.Html/Assets/canopyx-forms.css +3 -3
  56. package/CanopyX.Html/Assets/canopyx-forms.js +1 -1
  57. package/CanopyX.Html/Assets/canopyx-grid-module.mjs +220 -155
  58. package/CanopyX.Html/Assets/canopyx-grid-options.css +8 -8
  59. package/CanopyX.Html/Assets/canopyx-grid-options.js +9 -2
  60. package/CanopyX.Html/Assets/canopyx-grid.css +285 -150
  61. package/CanopyX.Html/Assets/canopyx-grid.js +220 -155
  62. package/CanopyX.Html/Assets/canopyx-grouping.css +23 -16
  63. package/CanopyX.Html/Assets/canopyx-grouping.js +24 -17
  64. package/CanopyX.Html/Assets/canopyx-highlight.css +10 -10
  65. package/CanopyX.Html/Assets/canopyx-highlight.js +1 -1
  66. package/CanopyX.Html/Assets/canopyx-interactive.css +215 -91
  67. package/CanopyX.Html/Assets/canopyx-interactive.js +47 -52
  68. package/CanopyX.Html/Assets/canopyx-labels-de.js +177 -9
  69. package/CanopyX.Html/Assets/canopyx-labels-es.js +177 -9
  70. package/CanopyX.Html/Assets/canopyx-labels-fr.js +176 -8
  71. package/CanopyX.Html/Assets/canopyx-labels-it.js +176 -8
  72. package/CanopyX.Html/Assets/canopyx-labels-pl.js +176 -8
  73. package/CanopyX.Html/Assets/canopyx-layouts.css +49 -21
  74. package/CanopyX.Html/Assets/canopyx-layouts.js +36 -14
  75. package/CanopyX.Html/Assets/canopyx-link.css +3 -3
  76. package/CanopyX.Html/Assets/canopyx-link.js +4 -4
  77. package/CanopyX.Html/Assets/canopyx-links.js +2 -2
  78. package/CanopyX.Html/Assets/canopyx-live.css +3 -5
  79. package/CanopyX.Html/Assets/canopyx-live.js +3 -3
  80. package/CanopyX.Html/Assets/canopyx-matrix.css +32 -39
  81. package/CanopyX.Html/Assets/canopyx-matrix.js +11 -11
  82. package/CanopyX.Html/Assets/canopyx-module.mjs +47 -52
  83. package/CanopyX.Html/Assets/canopyx-office-export.js +2936 -0
  84. package/CanopyX.Html/Assets/canopyx-pager.css +1 -1
  85. package/CanopyX.Html/Assets/canopyx-pager.js +1 -1
  86. package/CanopyX.Html/Assets/canopyx-path.css +45 -0
  87. package/CanopyX.Html/Assets/canopyx-path.js +28 -0
  88. package/CanopyX.Html/Assets/canopyx-pivot.css +75 -0
  89. package/CanopyX.Html/Assets/canopyx-pivot.js +72 -0
  90. package/CanopyX.Html/Assets/canopyx-plan.css +63 -0
  91. package/CanopyX.Html/Assets/canopyx-plan.js +71 -0
  92. package/CanopyX.Html/Assets/canopyx-presenters.js +2 -2
  93. package/CanopyX.Html/Assets/canopyx-record-panel.css +51 -45
  94. package/CanopyX.Html/Assets/canopyx-record-panel.js +30 -22
  95. package/CanopyX.Html/Assets/canopyx-reporting-module.mjs +262 -197
  96. package/CanopyX.Html/Assets/canopyx-reporting.css +300 -164
  97. package/CanopyX.Html/Assets/canopyx-reporting.js +262 -197
  98. package/CanopyX.Html/Assets/canopyx-stack.css +35 -0
  99. package/CanopyX.Html/Assets/canopyx-stack.js +24 -0
  100. package/CanopyX.Html/Assets/canopyx-time-slider.css +18 -0
  101. package/CanopyX.Html/Assets/canopyx-time-slider.js +27 -0
  102. package/CanopyX.Html/Assets/canopyx-timeline.css +19 -19
  103. package/CanopyX.Html/Assets/canopyx-timeline.js +6 -5
  104. package/CanopyX.Html/Assets/canopyx-tree-tools.css +47 -46
  105. package/CanopyX.Html/Assets/canopyx-tree-tools.js +15 -12
  106. package/CanopyX.Html/Assets/canopyx-ui-menu.css +41 -0
  107. package/CanopyX.Html/Assets/canopyx-ui-menu.js +64 -0
  108. package/CanopyX.Html/Assets/canopyx-ui-navigation.css +73 -0
  109. package/CanopyX.Html/Assets/canopyx-ui-navigation.js +39 -0
  110. package/CanopyX.Html/Assets/canopyx-ui-overlays.css +79 -0
  111. package/CanopyX.Html/Assets/canopyx-ui-overlays.js +45 -0
  112. package/CanopyX.Html/Assets/canopyx-ui-picker.css +12 -0
  113. package/CanopyX.Html/Assets/canopyx-ui-picker.js +6 -0
  114. package/CanopyX.Html/Assets/canopyx-ui-stepper.css +174 -0
  115. package/CanopyX.Html/Assets/canopyx-ui-stepper.js +48 -0
  116. package/CanopyX.Html/Assets/canopyx-ui-tabs.css +153 -0
  117. package/CanopyX.Html/Assets/canopyx-ui-tabs.js +47 -0
  118. package/CanopyX.Html/Assets/canopyx-values.css +5 -0
  119. package/CanopyX.Html/Assets/canopyx-values.js +13 -0
  120. package/CanopyX.Html/Assets/canopyx-view-intents.css +12 -0
  121. package/CanopyX.Html/Assets/canopyx-view-intents.js +56 -0
  122. package/CanopyX.Html/Assets/canopyx.css +212 -85
  123. package/CanopyX.Html/Assets/canopyx.js +38 -26
  124. package/JavaScript/board.d.ts +30 -0
  125. package/JavaScript/changes.d.ts +4 -1
  126. package/JavaScript/column-groups.d.ts +24 -4
  127. package/JavaScript/facets.d.ts +5 -3
  128. package/JavaScript/grid.d.ts +161 -17
  129. package/JavaScript/hosts.d.ts +16 -1
  130. package/JavaScript/index.d.ts +4 -2
  131. package/JavaScript/locales/de.mjs +177 -9
  132. package/JavaScript/locales/es.mjs +177 -9
  133. package/JavaScript/locales/fr.mjs +176 -8
  134. package/JavaScript/locales/it.mjs +176 -8
  135. package/JavaScript/locales/pl.mjs +176 -8
  136. package/JavaScript/matrix.d.ts +4 -1
  137. package/JavaScript/path.d.ts +33 -0
  138. package/JavaScript/pivot.d.ts +135 -0
  139. package/JavaScript/plan.d.ts +23 -0
  140. package/JavaScript/protocol.d.ts +18 -3
  141. package/JavaScript/records.d.ts +4 -0
  142. package/JavaScript/stack.d.ts +28 -0
  143. package/JavaScript/time-slider.d.ts +58 -0
  144. package/JavaScript/ui.d.ts +261 -0
  145. package/JavaScript/view-intents.d.ts +45 -0
  146. package/README.md +76 -187
  147. package/README.nuget.md +63 -87
  148. package/ThirdParty/OfficeIMO/LICENSE +21 -0
  149. package/ThirdParty/OfficeIMO/README.md +13 -0
  150. package/package.json +76 -3
@@ -0,0 +1,13 @@
1
+ (function(global){"use strict";const installed=new WeakSet();const part={version:"0d7006b0f7bfca10",install(context){if(installed.has(context.GRID_SHOW_AS))return;const{DataGrid,GRID_SHOW_AS,GRID_SHOW_AS_MODES,h,setText,gridFreeze,reportingAggregateParts,reportingAggregateName,gridButton}=context;function showAsValues(values,mode,grand=null,parent=null,rowTotals,columnTotals){if(!Array.isArray(values)||values.length>10000||values.some(value=>value!==null&&!Number.isFinite(value))||!GRID_SHOW_AS_MODES.includes(mode)||
2
+ rowTotals&&rowTotals.length!==values.length||columnTotals&&columnTotals.length!==values.length)throw new Error("CanopyX: invalid aggregate display inputs.");const ranks=new Map();if(mode==="rank")values.filter(value=>value!==null).sort((a,b)=>b-a).forEach((value,index)=>{if(!ranks.has(value))ranks.set(value,index+1)});let running=0;return values.map((value,index)=>{if(value===null)return null;const divide=denominator=>denominator!==null&&denominator!==undefined&&denominator!==0?value / denominator : null;
3
+ let result;switch(mode){case "percentGrandTotal":result=divide(grand);break;case "percentParent":result=divide(parent);break;case "percentRow":result=divide(rowTotals?.[index]);break;case "percentColumn":result=divide(columnTotals?.[index]);break;case "runningTotal":running +=value;result=running;break;case "rank":result=ranks.get(value);break;case "difference":result=!index||values[index-1]===null?null:value-values[index-1];break;case "percentChange":result=!index||values[index-1]===null||values[index-1]===0?null:(value-values[index-1])/ values[index - 1]; break;
4
+ default:result=value}
5
+ return result===null||!Number.isFinite(result)?null:result})}
6
+ const showAsPercent=mode=>["percentGrandTotal","percentParent","percentRow","percentColumn","percentChange"].includes(mode);const showAsFormat=mode=>showAsPercent(mode)?"0.00%":mode==="rank"?"0":"0.00";Object.assign(GRID_SHOW_AS,{evaluate:showAsValues,percent:showAsPercent,numberFormat:showAsFormat});function showAsSummary(grid,summary){grid.aggregateDisplayCache||=new WeakMap();const cached=grid.aggregateDisplayCache.get(summary);if(cached)return cached;const aggregates=grid.view.reporting.aggregates||[],modes=grid.aggregateShowAs||{},byValues=new WeakMap();const modeOf=aggregate=>modes[aggregate.id]??aggregate.showAs??"value";const value=(number,mode)=>Object.freeze({value:number,mode,numberFormat:showAsFormat(mode)});const totals=Object.create(null),groups=Object.create(null);for(const aggregate of aggregates){const raw=summary.aggregates[aggregate.id],mode=modeOf(aggregate);totals[aggregate.id]=value(showAsValues([raw],mode,raw,raw)[0],mode)}
7
+ byValues.set(summary.aggregates,totals);const walk=(siblings,parent)=>{const display=siblings.map(()=>Object.create(null));for(const aggregate of aggregates){const mode=modeOf(aggregate),values=showAsValues(siblings.map(group=>group.aggregates[aggregate.id]),mode,summary.aggregates[aggregate.id],parent[aggregate.id]);values.forEach((number,index)=>{display[index][aggregate.id]=value(number,mode)})}
8
+ siblings.forEach((group,index)=>{groups[group.key]=display[index];byValues.set(group.aggregates,display[index]);walk(group.groups||[],group.aggregates)})};walk(summary.groups,summary.aggregates);const result=gridFreeze({totals,groups}),entry={result,byValues};grid.aggregateDisplayCache.set(summary,entry);return entry}
9
+ function showAsEntry(grid,values,aggregate){for(const summary of[grid.summary,grid.summaryCandidate?.result]){if(!summary)continue;const entry=showAsSummary(grid,summary).byValues.get(values)?.[aggregate.id];if(entry)return entry}
10
+ return{value:values[aggregate.id],mode:"value",numberFormat:"0.00"}}
11
+ Object.assign(GRID_SHOW_AS,{summary:showAsSummary,entry:showAsEntry});DataGrid.prototype.openAggregateMenu=function(column,aggregates,values,button,text){const controls=h("form","cx-show-as-fields"),choices=[];for(const aggregate of aggregates){const label=h("label","cx-show-as-field"),name=h("span"),select=h("select","cx-input");setText(name,reportingAggregateName(this,aggregate));select.setAttribute("aria-label",aggregate.label+": "+this.labels.gridShowAs);for(const mode of GRID_SHOW_AS_MODES.filter(mode=>!["percentRow","percentColumn"].includes(mode))){const option=h("option");option.value=mode;setText(option,this.labels["gridShowAs"+mode[0].toUpperCase()+ mode.slice(1)]);select.append(option)}
12
+ select.value=this.aggregateShowAs?.[aggregate.id]??aggregate.showAs??"value";choices.push([aggregate.id,select]);label.append(name,select);controls.append(label)}
13
+ const apply=gridButton(this.labels.gridApply,()=>{});apply.type="submit";apply.dataset.variant="primary";controls.append(apply);controls.addEventListener("submit",async event=>{event.preventDefault();for(const[id,select]of choices)await this.setAggregateShowAs(id,select.value);this.reportingText?._cxOverlay.close()});this.showReportingText(column,text??reportingAggregateParts(this,column,aggregates,values).title,button,undefined,false,controls)};installed.add(context.GRID_SHOW_AS)}};(global.CanopyXParts||=[]).push(["values",part])})(typeof window!=="undefined"?window:globalThis);
@@ -0,0 +1,12 @@
1
+ body .cx-host.cx-view-intent-preview{height:auto;min-width:0;margin-top:var(--hfx-space-3,0.75rem);padding:var(--hfx-space-3,0.75rem);border:var(--hfx-border-width,1px) solid var(--hfx-color-surface-line,var(--hfx-color-border,light-dark(#e2e4e7,#272a30)));border-radius:var(--hfx-radius-control,var(--hfx-radius-md,6px));background:var(--hfx-color-surface-card,var(--hfx-color-surface,light-dark(#ffffff,#16181c)));color:var(--hfx-color-text-primary,var(--hfx-color-text,light-dark(#16181c,#f2f3f5)));}
2
+ .cx-view-intent-preview h3{margin:0 0 var(--hfx-space-2,0.5rem);font-size:inherit;font-weight:var(--hfx-weight-semibold,600);}
3
+ .cx-view-intent-preview .cx-grid-query-chips{display:flex;flex-wrap:wrap;gap:var(--hfx-space-1-5,6px);margin-bottom:var(--hfx-space-3,0.75rem);}
4
+ .cx-view-intent-preview .cx-grid-chip{display:inline-block;max-width:100%;height:auto;padding:var(--hfx-space-1,0.25rem) var(--hfx-space-2,0.5rem);border-radius:var(--hfx-radius-control,var(--hfx-radius-md,6px));background:var(--hfx-color-accent-subtle,light-dark(#e7f1f1,#1b3435));white-space:normal;overflow-wrap:anywhere;}
5
+ .cx-view-intent-actions{display:flex;flex-wrap:wrap;gap:var(--hfx-space-2,0.5rem);}
6
+ .cx-view-intent-preview [role=status]{margin:var(--hfx-space-2,0.5rem) 0 0;overflow-wrap:anywhere;}
7
+ .cx-view-intent-preview [role=status]:empty{display:none;}
8
+ @media print{.cx-view-intent-preview{display:none !important;}}
9
+ @media (forced-colors:active){
10
+ .cx-view-intent-preview .cx-grid-chip{border:var(--hfx-border-width,1px) solid CanvasText;}
11
+ .cx-view-intent-actions [data-variant="primary"]{background:Highlight;color:HighlightText;border:var(--hfx-border-width,1px) solid Highlight;forced-color-adjust:none;}
12
+ }
@@ -0,0 +1,56 @@
1
+ (function(global){"use strict";const installed=new WeakSet();const part={version:"dbd26360f2b90a49",install(context){if(installed.has(context.DataGrid.prototype))return;const{DataGrid,h,setText,fill,gridButton,gridVariant,gridQuery,gridQueryStart,gridFreeze,GRID_FILTER_LABELS,GRID_REPORTING,watchOverlayTheme}=context;const VIEW_INTENT_LABELS={viewIntentPreview:"Proposed changes",viewIntentApplied:"View changes applied.",viewIntentSuperseded:"The view changed. Preview the proposal again.",viewIntentSearch:"Search: {search}",viewIntentSort:"Sort by {columns}",viewIntentGroup:"Group rows by {columns}",viewIntentColumns:"Show columns: {columns}",viewIntentWords:"Whole words",viewIntentSubstring:"Text contains",viewIntentClearSearch:"Clear search",viewIntentRemoveGrouping:"Remove grouping",viewIntentFlat:"Show records",viewIntentAscending:"ascending",viewIntentDescending:"descending",viewIntentNotEqual:"is not",viewIntentGreater:"greater than",viewIntentAtLeast:"at least",viewIntentLess:"less than",viewIntentAtMost:"at most",viewIntentFilter:"Show rows where {column} {operator} {values}",viewIntentOnly:"Show only {column}: {values}",viewIntentPivot:"Rows: {rows}; columns: {columns}; values: {values}",viewIntentAllRows:"all records",viewIntentTotals:"totals",viewIntentTuples:"Show matching combinations of {columns}: {values}",viewIntentExcludeTuples:"Exclude matching combinations of {columns}: {values}",viewIntentNoChanges:"This view is already selected."};const VIEW_INTENT_MAX=65536;function viewIntentSnapshot(input){let nodes=0,text=0;const visit=(value,depth)=>{if(++nodes>VIEW_INTENT_MAX||depth>32)throw new Error("CanopyX: view intent exceeds its input bounds.");if(value===null||typeof value==="boolean")return value;if(typeof value==="string"){if((text +=value.length)>VIEW_INTENT_MAX)throw new Error("CanopyX: view intent is too large.");return value}
2
+ if(typeof value==="number"&&Number.isFinite(value)&&Math.abs(value)<=Number.MAX_SAFE_INTEGER)return value;if(!value||typeof value!=="object"||![Object.prototype,null,Array.prototype].includes(Object.getPrototypeOf(value)))
3
+ throw new Error("CanopyX: view intents contain JSON data only.");const array=Array.isArray(value),descriptors=Object.getOwnPropertyDescriptors(value),keys=Reflect.ownKeys(descriptors);if(keys.some(key=>typeof key!=="string"||key!=="length"&&!Object.hasOwn(descriptors[key],"value")))
4
+ throw new Error("CanopyX: view intents cannot contain accessors or symbols.");if(array){if(value.length>VIEW_INTENT_MAX||keys.length!==value.length+1||keys.some(key=>key!=="length"&&!/^(0|[1-9]\d*)$/.test(key)))
5
+ throw new Error("CanopyX: view intent arrays must be bounded JSON arrays.");return Array.from({length:value.length},(_,index)=>visit(descriptors[index].value,depth+1))}
6
+ const copy=Object.create(null);for(const key of keys){text +=key.length;copy[key]=visit(descriptors[key].value,depth+1)}
7
+ return copy};const copy=visit(input,0),json=JSON.stringify(copy);if(json.length>VIEW_INTENT_MAX)throw new Error("CanopyX: view intent holds at most 65,536 characters.");return JSON.parse(json)}
8
+ function viewIntentObject(value,names,what){if(!value||typeof value!=="object"||Array.isArray(value)||Object.keys(value).some(key=>!names.includes(key)))
9
+ throw new Error("CanopyX: invalid "+what+".");return value}
10
+ function viewIntentArray(value,maximum,what){if(!Array.isArray(value)||value.length>maximum)throw new Error("CanopyX: invalid "+what+".");return value}
11
+ function viewIntentQuery(grid,patch){viewIntentObject(patch,["search","searchMode","sort","filters","filterGroup","groupBy","tupleFilters"],"view intent query");if(patch.search!==undefined&&(typeof patch.search!=="string"||patch.search.length>16384))throw new Error("CanopyX: invalid intent search.");if(patch.searchMode!==undefined&&!["substring","words","regex"].includes(patch.searchMode))throw new Error("CanopyX: invalid intent search mode.");if(patch.sort!==undefined)viewIntentArray(patch.sort,64,"intent sorts").forEach(sort=>viewIntentObject(sort,["column","direction"],"intent sort"));let predicates=0,groups=0;const filter=item=>{if(++predicates>64)throw new Error("CanopyX: at most 64 intent predicates.");viewIntentObject(item,["column","operator","values","bucket"],"intent predicate");if(!Object.hasOwn(GRID_FILTER_LABELS,item.operator))throw new Error("CanopyX: invalid intent predicate operator.");viewIntentBucketShape(item.bucket);viewIntentArray(item.values,1000,"intent operands").forEach(value=>{if(typeof value==="string"&&value.length>16384)throw new Error("CanopyX: intent operand is too long.");const column=grid.view.columns.find(column=>column.id===item.column);if(column?.kind==="datetime"&&!item.bucket){const match=typeof value==="string"&&/^(\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d)(?:\.(\d{1,7}))?Z$/.exec(value);
12
+ if(!match||!Number.isFinite(Date.parse(value))||new Date(value).toISOString().slice(0,19)!==match[1]||match[1].startsWith("0000"))
13
+ throw new Error("CanopyX: intent date operands need valid UTC timestamps.")}})};const group=(item,depth)=>{if(depth>8||++groups>64)throw new Error("CanopyX: intent groups exceed grid limits.");viewIntentObject(item,["operator","filters","groups"],"intent group");viewIntentArray(item.filters,64,"intent group filters").forEach(filter);viewIntentArray(item.groups,64,"intent groups").forEach(child=>group(child,depth+1))};if(patch.filters!==undefined)viewIntentArray(patch.filters,64,"intent filters").forEach(filter);if(patch.filterGroup!==undefined&&patch.filterGroup!==null)group(patch.filterGroup,1);if(patch.groupBy!==undefined)viewIntentArray(patch.groupBy,4,"intent grouping levels").forEach(level=>{viewIntentObject(level,["column","direction","aggregate","bucket"],"intent grouping level");viewIntentBucketShape(level.bucket)});if(patch.tupleFilters!==undefined)viewIntentArray(patch.tupleFilters,8,"intent tuples").forEach(tuple=>{viewIntentObject(tuple,["columns","values","exclude"],"intent tuple");const columns=viewIntentArray(tuple.columns,6,"intent tuple columns");columns.forEach(field=>{viewIntentObject(field,["column","bucket"],"intent tuple column");viewIntentBucketShape(field.bucket)});viewIntentArray(tuple.values,200,"intent tuple values").forEach(row=>viewIntentArray(row,6,"intent tuple row").forEach((value,index)=>{if(typeof value==="string"&&value.length>16384)throw new Error("CanopyX: intent tuple operand is too long.");const field=columns[index],column=grid.view.columns.find(column=>column.id===field?.column);if(value!==null&&!field?.bucket&&column?.kind==="datetime"){const match=typeof value==="string"&&/^(\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d)(?:\.(\d{1,7}))?Z$/.exec(value);
14
+ if(!match||!Number.isFinite(Date.parse(value))||new Date(value).toISOString().slice(0,19)!==match[1]||match[1].startsWith("0000"))
15
+ throw new Error("CanopyX: intent date operands need valid UTC timestamps.")}}))});gridQuery(grid.view,{...patch,filterGroup:patch.filterGroup===null?undefined:patch.filterGroup},true)}
16
+ function readViewIntent(grid,input){grid.labels=Object.freeze({...VIEW_INTENT_LABELS,...grid.labels});if(grid.destroyed)throw new DOMException("Grid was destroyed.","AbortError");if(grid.view.viewIntents!==true)throw new Error("CanopyX: this grid has not enabled view intents.");const intent=viewIntentSnapshot(input);viewIntentObject(intent,["protocol","type","version","view","query","columns","pivot"],"view intent");if(intent.protocol!=="canopyx/2"||intent.type!=="viewIntent"||intent.version!==1||intent.view!==grid.view.id)
17
+ throw new Error("CanopyX: invalid view intent identity or version.");if(intent.query!==undefined)viewIntentQuery(grid,intent.query);if(intent.pivot!==undefined)viewIntentPivotState(grid,intent.pivot,grid.getState());if(intent.columns!==undefined){const columns=viewIntentArray(intent.columns,256,"intent visible columns");if(!columns.length||new Set(columns).size!==columns.length||columns.some(id=>typeof id!=="string"||!grid.columns.some(column=>column.id===id)))
18
+ throw new Error("CanopyX: intent visible columns must be unique declared columns and keep one visible.")}
19
+ if((!intent.query||!Object.keys(intent.query).length)&&intent.columns===undefined&&intent.pivot===undefined)throw new Error("CanopyX: empty view intent.");return gridFreeze(intent)}
20
+ const VIEW_INTENT_PREVIEWS=new WeakMap();const VIEW_INTENT_BASE={setQuery:DataGrid.prototype.setQuery,stateChanged:DataGrid.prototype.stateChanged,readGridState:DataGrid.prototype.readGridState,applyStatePresentation:DataGrid.prototype.applyStatePresentation};function intentStateKey(grid){return JSON.stringify(grid.getState())}
21
+ function intentPresentationKey(grid){const{query,paging,scrollTop,...presentation}=grid.getState();return JSON.stringify(presentation)}
22
+ function retireViewIntent(grid,reason){const preview=grid.viewIntentPreview;if(!preview)return;grid.viewIntentPreview=null;preview.active=false;preview.apply.disabled=true;preview.cancel.disabled=false;grid.lifetime.signal.removeEventListener("abort",preview.destroy);setText(preview.status,reason||grid.labels.viewIntentSuperseded)}
23
+ function intentCandidate(grid,intent,current){const state=JSON.parse(JSON.stringify(current)),patch=intent.query||{};state.query=gridQuery(grid.view,gridQueryStart(state.query,{...patch,filterGroup:patch.filterGroup===null?undefined:
24
+ Object.hasOwn(patch,"filterGroup")?patch.filterGroup:state.query.filterGroup}),true);state.scrollTop=0;if(state.paging)state.paging.offset=0;if(intent.columns){const columns=new Map(state.columns.map(column=>[column.id,column])),visible=new Set(intent.columns);state.columns=[...intent.columns,...state.columns.filter(column=>!visible.has(column.id)).map(column=>column.id)]
25
+ .map(id=>({...columns.get(id),hidden:!visible.has(id)}))}
26
+ return intent.pivot===undefined?grid.readGridState(state):viewIntentPivotState(grid,intent.pivot,state)}
27
+ async function confirmViewIntent(grid,handle){const entry=VIEW_INTENT_PREVIEWS.get(handle),preview=entry?.preview;if(!preview||entry.grid!==grid||!preview.active||grid.destroyed||grid.pendingQuery||preview.epoch!==grid.queryEpoch||preview.key!==intentStateKey(grid))
28
+ throw new DOMException(grid.labels.viewIntentSuperseded,"AbortError");const intent=grid.validateViewIntent(preview.intent),state=intentCandidate(grid,intent,grid.getState());const restore={input:state,before:intentPresentationKey(grid),preferenceBefore:grid.viewPreferenceIntent,applied:false};grid.viewIntentApply=restore;retireViewIntent(grid,grid.labels.loading);try{const query=await grid.setState(state);if(grid.destroyed)throw new DOMException("Grid was destroyed.","AbortError");if(!restore.applied||restore.epoch!==grid.queryEpoch||restore.after!==intentPresentationKey(grid)||restore.preferenceAfter!==grid.viewPreferenceIntent)
29
+ throw new DOMException(grid.labels.viewIntentSuperseded,"AbortError");if(intent.columns)grid.setColumnOrder(state.columns.map(column=>column.id));const focused=preview.element.contains(document.activeElement);preview.disposeTheme?.();preview.element.remove();if(grid.viewIntentElement===preview.element)grid.viewIntentElement=null;const announcement=grid.viewIntentStatus||=h("p","cx-sr-only");announcement.setAttribute("role","status");announcement.setAttribute("aria-live","polite");if(!announcement.isConnected)grid.host.append(announcement);setText(announcement,grid.labels.viewIntentApplied);if(focused)(preview.returnFocus?.isConnected?preview.returnFocus:grid.grid).focus({preventScroll:true});return query}catch(error){if(!grid.destroyed)setText(preview.status,error.message);throw error}
30
+ finally{if(grid.viewIntentApply===restore)grid.viewIntentApply=null}}
31
+ Object.assign(DataGrid.prototype,{readGridState(input){const state=VIEW_INTENT_BASE.readGridState.call(this,input),restore=this.viewIntentApply;if(restore?.input===input)restore.state=state;return state},applyStatePresentation(state){const restore=this.viewIntentApply;if(!restore||restore.state!==state)return VIEW_INTENT_BASE.applyStatePresentation.call(this,state);if(restore.before!==intentPresentationKey(this)||restore.preferenceBefore!==this.viewPreferenceIntent||
32
+ restore.preferenceBefore!==undefined&&this.restorePreferenceIntent!==this.viewPreferenceIntent)return;const applied=VIEW_INTENT_BASE.applyStatePresentation.call(this,state);restore.applied=true;restore.epoch=this.queryEpoch;restore.after=intentPresentationKey(this);restore.preferenceAfter=this.viewPreferenceIntent;return applied},validateViewIntent(input){return readViewIntent(this,input)},getViewIntent(){if(this.destroyed)throw new DOMException("Grid was destroyed.","AbortError");const current=this.getQuery();if(!current||this.pendingQuery)throw new Error("CanopyX: exporting a view intent needs a settled accepted query.");const query={search:current.search,searchMode:current.searchMode||"substring",sort:current.sort,filters:current.filters,filterGroup:current.filterGroup||null};if(current.groupBy)query.groupBy=current.groupBy;query.tupleFilters=viewIntentTupleExport(this,current.tupleFilters||[]);return this.validateViewIntent({protocol:"canopyx/2",type:"viewIntent",version:1,view:this.view.id,query,columns:this.columns.filter(column=>!column.hidden).map(column=>column.id),...(this.view.reporting?.pivot||this.view.reporting?.pivotable?{pivot:viewIntentPivotExport(this)}:{})})},previewViewIntent(input,container){const intent=this.validateViewIntent(input);if(!this.getQuery()||this.pendingQuery)throw new Error("CanopyX: preview needs a settled accepted query.");const state=this.getState();intentCandidate(this,intent,state);const adjacent=!container;container||=this.host.parentElement||this.host;if(!container||container.nodeType!==1||container.ownerDocument!==this.host.ownerDocument||!container.isConnected||container===this.grid||this.grid.contains(container))
33
+ throw new Error("CanopyX: preview needs a connected container outside the grid rows.");retireViewIntent(this);this.viewIntentTheme?.();this.viewIntentElement?.remove();if(this.viewIntentStatus)setText(this.viewIntentStatus,"");const element=h("section","cx-host cx-chrome cx-view-intent-preview"),heading=h("h3"),chips=h("div","cx-grid-query-chips"),status=h("p");element.setAttribute("aria-label",this.labels.viewIntentPreview);setText(heading,this.labels.viewIntentPreview);status.setAttribute("role","status");status.setAttribute("aria-live","polite");const descriptions=intentChips(this,intent,state);if(!descriptions.length)setText(chips,this.labels.viewIntentNoChanges);for(const text of descriptions){const chip=h("span","cx-grid-chip");setText(chip,text);chip.title=text;chips.appendChild(chip)}
34
+ const actions=h("div","cx-view-intent-actions"),apply=gridVariant(gridButton(this.labels.gridApply,()=>{confirmViewIntent(this,handle).catch(error=>{if(!this.destroyed)setText(status,error.name==="AbortError"?this.labels.viewIntentSuperseded:error.message)})}),"primary"),cancel=gridVariant(gridButton(this.labels.gridEditCancel||"Cancel",()=>handle.cancel()),"secondary");actions.append(apply,cancel);element.append(heading,chips,actions,status);const preview={returnFocus:document.activeElement,intent,key:JSON.stringify(state),epoch:this.queryEpoch,active:true,apply,cancel,status,element,destroy:()=>{preview.disposeTheme?.();retireViewIntent(this);element.remove()}};const handle=Object.freeze({element,intent,apply:()=>confirmViewIntent(this,handle),cancel:()=>{preview.disposeTheme?.();if(this.viewIntentPreview===preview)retireViewIntent(this,"");element.remove()}});VIEW_INTENT_PREVIEWS.set(handle,{grid:this,preview});this.viewIntentPreview=preview;this.viewIntentElement=element;if(!this.viewIntentCleanup){this.viewIntentCleanup=()=>{retireViewIntent(this);this.viewIntentElement?.remove()};this.lifetime.signal.addEventListener("abort",this.viewIntentCleanup,{once:true})}
35
+ this.lifetime.signal.addEventListener("abort",preview.destroy,{once:true});if(adjacent&&this.host.parentElement)this.host.after(element);else container.appendChild(element);preview.disposeTheme=this.viewIntentTheme=watchOverlayTheme(this.host,element,this.lifetime.signal);return handle},async applyViewIntent(input,container){return this.previewViewIntent(input,container)},setQuery(...args){retireViewIntent(this);return VIEW_INTENT_BASE.setQuery.apply(this,args)},stateChanged(...args){const preview=this.viewIntentPreview;if(preview&&(preview.epoch!==this.queryEpoch||preview.key!==intentStateKey(this)))retireViewIntent(this);return VIEW_INTENT_BASE.stateChanged.apply(this,args)}});function viewIntentPivotState(grid,input,current){if(!grid.view.reporting?.pivot&&grid.view.reporting?.pivotable!==true)
36
+ throw new Error("CanopyX: this view does not enable pivots.");const state=JSON.parse(JSON.stringify(current));if(input===false){if(state.pivot)state.pivot.active=false}else{viewIntentObject(input,["rows","columns","values","maxColumns","topNColumns","sortByTotal"],"intent pivot");if(input.maxColumns===null)throw new Error("CanopyX: an explicit intent column limit is an integer.");for(const levels of[input.rows,input.columns])if(Array.isArray(levels))levels.forEach(level=>{viewIntentObject(level,["column","direction","bucket"],"intent pivot level");viewIntentBucketShape(level.bucket)});state.pivot={...GRID_REPORTING.pivotDefinition(grid.view,input),active:true,collapsedRows:[],collapsedColumns:[]}}
37
+ return state}
38
+ function viewIntentPivotExport(grid){const state=grid.getState().pivot;if(!state?.active)return false;const{active,collapsedRows,collapsedColumns,columnKey,...definition}=state;return definition}
39
+ function viewIntentBucketCaption(grid,bucket){if(!bucket)return "";const labels=grid.labels,name=labels["gridBucket"+bucket.kind[0].toUpperCase()+ bucket.kind.slice(1)];return " ("+name +(bucket.kind==="width"?": "+bucket.width+", "+labels.gridBucketOrigin+": " +(bucket.origin??0):
40
+ bucket.kind==="edges"?": "+bucket.edges.join(", "):
41
+ ", " +(bucket.timeZone||"UTC")+(bucket.firstWeekday===undefined?"":", "+bucket.firstWeekday))+ ")"}
42
+ function viewIntentBucketShape(input){if(input===undefined)return;viewIntentObject(input,["kind","width","origin","edges","timeZone","firstWeekday"],"intent bucket");if(Object.values(input).some(value=>value===null))throw new Error("CanopyX: explicit intent bucket fields cannot be null.")}
43
+ function viewIntentTupleExport(grid,tuples){return tuples.map(tuple=>({...tuple,values:tuple.values.map(row=>row.map((value,index)=>{const field=tuple.columns[index],column=grid.view.columns.find(column=>column.id===field.column);return value!==null&&!field.bucket&&column.kind==="datetime"?new Date(value).toISOString():value}))}))}
44
+ function intentChips(grid,intent,current){const next=intentCandidate(grid,intent,current),before=current.query,after=next.query,labels=grid.labels;const same=(a,b)=>JSON.stringify(a??null)===JSON.stringify(b??null),chips=[];const title=id=>grid.columns.find(column=>column.id===id)?.title||id;const aggregate=id=>grid.view.reporting?.aggregates.find(value=>value.id===id)?.label||id;const direction=value=>value==="desc"?labels.viewIntentDescending:labels.viewIntentAscending;const level=value=>title(value.column)+ " (" +(value.aggregate?aggregate(value.aggregate)+ " ":"")+ direction(value.direction)+ ")"+viewIntentBucketCaption(grid,value.bucket);const predicate=filter=>{const caption=grid.filterCaption?.(filter);if(caption)return caption;const values=filter.values.map(value=>String(value)).join(", "),column=title(filter.column)+ viewIntentBucketCaption(grid,filter.bucket);if(filter.operator==="eq")return fill(labels.viewIntentOnly,{column,values});const words={ne:labels.viewIntentNotEqual,gt:labels.viewIntentGreater,ge:labels.viewIntentAtLeast,lt:labels.viewIntentLess,le:labels.viewIntentAtMost};const operator=words[filter.operator]||labels[GRID_FILTER_LABELS[filter.operator]];return fill(labels.viewIntentFilter,{column,operator,values}).trim()};const group=item=>[...item.filters.map(predicate),...item.groups.map(child=>"("+group(child)+ ")")]
45
+ .join(" " +(item.operator==="and"?labels.gridAnd:labels.gridOr)+ " ");if(!same(before.search,after.search))chips.push(after.search?fill(labels.viewIntentSearch,{search:after.search}):labels.viewIntentClearSearch);if(!same(before.searchMode||"substring",after.searchMode||"substring"))
46
+ chips.push(after.searchMode==="regex"?labels.gridRegexSearch:after.searchMode==="words"?labels.viewIntentWords:labels.viewIntentSubstring);const recordSort=query=>query.sort.filter(value=>!query.groupBy?.some(level=>level.column===value.column));if(!same(before.sort,after.sort)){const sorts=recordSort(after);if(sorts.length)chips.push(fill(labels.viewIntentSort,{columns:sorts.map(value=>title(value.column)+ " "+direction(value.direction)).join(", ")}));else if(recordSort(before).length)chips.push(labels.gridClearSort)}
47
+ if(!same(before.filters,after.filters)){for(const filter of after.filters)if(!before.filters.some(value=>same(value,filter)))chips.push(predicate(filter));for(const filter of before.filters)if(!after.filters.some(value=>same(value,filter)))
48
+ chips.push(fill(labels.gridRemoveCondition,{condition:predicate(filter)}))}
49
+ if(!same(before.filterGroup,after.filterGroup))chips.push(after.filterGroup?group(after.filterGroup):labels.gridRemoveGroup);if(!same(before.groupBy||[],after.groupBy||[]))chips.push(after.groupBy?.length?
50
+ fill(labels.viewIntentGroup,{columns:after.groupBy.map(level).join(", ")}):labels.viewIntentRemoveGrouping);const visible=state=>state.columns.filter(column=>!column.hidden).map(column=>column.id);if(!same(visible(current),visible(next)))chips.push(fill(labels.viewIntentColumns,{columns:visible(next).map(title).join(", ")}));const tuples=value=>(value||[]).map(tuple=>fill(tuple.exclude?labels.viewIntentExcludeTuples:labels.viewIntentTuples,{columns:tuple.columns.map(field=>title(field.column)+ viewIntentBucketCaption(grid,field.bucket)).join(", "),values:tuple.values.map(row=>row.map(value=>value===null?labels.gridIsNull:String(value)).join(", ")).join("; ")}));if(!same(before.tupleFilters||[],after.tupleFilters||[])){const old=tuples(before.tupleFilters),fresh=tuples(after.tupleFilters);chips.push(...fresh.filter(text=>!old.includes(text)),...old.filter(text=>!fresh.includes(text)).map(condition=>fill(labels.gridRemoveCondition,{condition})))}
51
+ const oldPivot=current.pivot,pivot=next.pivot;const pivotLevel=value=>title(value.column)+(value.direction==="desc"?" ("+direction(value.direction)+ ")":"")+ viewIntentBucketCaption(grid,value.bucket);if(pivot?.active&&(!oldPivot?.active||!same([oldPivot.rows,oldPivot.columns,oldPivot.values],[pivot.rows,pivot.columns,pivot.values])))
52
+ chips.push(fill(labels.viewIntentPivot,{rows:pivot.rows.map(pivotLevel).join(", ")||labels.viewIntentAllRows,columns:pivot.columns.map(pivotLevel).join(", ")||labels.viewIntentTotals,values:pivot.values.map(aggregate).join(", ")}));else if(!pivot?.active&&oldPivot?.active)chips.push(labels.viewIntentFlat);if(pivot?.active&&!same(oldPivot?.sortByTotal,pivot.sortByTotal)&&pivot.sortByTotal)
53
+ chips.push(fill(labels.viewIntentSort,{columns:aggregate(pivot.sortByTotal.aggregate)+ " "+direction(pivot.sortByTotal.direction)}));if(pivot?.active&&oldPivot?.active&&same([oldPivot.rows,oldPivot.columns],[pivot.rows,pivot.columns])){const result=grid.pivotResult,limit=value=>Math.min(value.maxColumns??200,value.topNColumns??200);if(result&&Math.min(limit(oldPivot),result.distinctColumns)!==Math.min(limit(pivot),result.distinctColumns))
54
+ chips.push(labels.gridPivotColumns+": "+Math.min(limit(pivot),result.distinctColumns))}
55
+ if(pivot?.active&&oldPivot?.sortByTotal&&!pivot.sortByTotal)chips.push(labels.gridClearSort);return chips}
56
+ installed.add(context.DataGrid.prototype)}};(global.CanopyXParts||=[]).push(["view-intents",part])})(typeof window!=="undefined"?window:globalThis);