@evotecit/canopyx 0.3.13 → 0.3.16
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.
- package/CanopyX.Html/Assets/canopyx-calendar-edit.js +36 -18
- package/CanopyX.Html/Assets/canopyx-calendar-ics.js +7 -5
- package/CanopyX.Html/Assets/canopyx-calendar.css +124 -116
- package/CanopyX.Html/Assets/canopyx-calendar.js +74 -54
- package/CanopyX.Html/Assets/canopyx-cell-range.css +8 -8
- package/CanopyX.Html/Assets/canopyx-cell-range.js +1 -1
- package/CanopyX.Html/Assets/canopyx-changes.css +113 -113
- package/CanopyX.Html/Assets/canopyx-changes.js +7 -10
- package/CanopyX.Html/Assets/canopyx-column-groups.css +5 -5
- package/CanopyX.Html/Assets/canopyx-column-groups.js +1 -1
- package/CanopyX.Html/Assets/canopyx-data.js +2 -2
- package/CanopyX.Html/Assets/canopyx-detail-rows.css +9 -9
- package/CanopyX.Html/Assets/canopyx-detail-rows.js +2 -2
- package/CanopyX.Html/Assets/canopyx-editing.css +18 -18
- package/CanopyX.Html/Assets/canopyx-editing.js +1 -1
- package/CanopyX.Html/Assets/canopyx-enhance.js +2 -2
- package/CanopyX.Html/Assets/canopyx-facets.css +33 -33
- package/CanopyX.Html/Assets/canopyx-facets.js +5 -6
- package/CanopyX.Html/Assets/canopyx-filter-editor.css +57 -57
- package/CanopyX.Html/Assets/canopyx-filter-editor.js +7 -5
- package/CanopyX.Html/Assets/canopyx-flow-checks.css +13 -11
- package/CanopyX.Html/Assets/canopyx-flow-checks.js +5 -4
- package/CanopyX.Html/Assets/canopyx-flow-command.css +7 -7
- package/CanopyX.Html/Assets/canopyx-flow-command.js +1 -1
- package/CanopyX.Html/Assets/canopyx-flow-dialog.css +9 -7
- package/CanopyX.Html/Assets/canopyx-flow-dialog.js +1 -1
- package/CanopyX.Html/Assets/canopyx-flow-drafts.css +7 -7
- package/CanopyX.Html/Assets/canopyx-flow-drafts.js +1 -1
- package/CanopyX.Html/Assets/canopyx-flow-entry.css +17 -76
- package/CanopyX.Html/Assets/canopyx-flow-entry.js +11 -5
- package/CanopyX.Html/Assets/canopyx-flow-facts.js +2 -0
- package/CanopyX.Html/Assets/canopyx-flow-host.css +4 -4
- package/CanopyX.Html/Assets/canopyx-flow-host.js +1 -1
- package/CanopyX.Html/Assets/canopyx-flow-module.mjs +11 -5
- package/CanopyX.Html/Assets/canopyx-flow-pick.css +4 -4
- package/CanopyX.Html/Assets/canopyx-flow-pick.js +1 -1
- package/CanopyX.Html/Assets/canopyx-flow-preview.css +6 -6
- package/CanopyX.Html/Assets/canopyx-flow-preview.js +1 -1
- package/CanopyX.Html/Assets/canopyx-flow-records.css +3 -3
- package/CanopyX.Html/Assets/canopyx-flow-records.js +1 -1
- package/CanopyX.Html/Assets/canopyx-flow-tasks.css +17 -17
- package/CanopyX.Html/Assets/canopyx-flow-tasks.js +1 -1
- package/CanopyX.Html/Assets/canopyx-flow.css +79 -79
- package/CanopyX.Html/Assets/canopyx-flow.js +8 -7
- package/CanopyX.Html/Assets/canopyx-format-editor.css +23 -23
- package/CanopyX.Html/Assets/canopyx-format-editor.js +2 -3
- package/CanopyX.Html/Assets/canopyx-formatting.css +17 -17
- package/CanopyX.Html/Assets/canopyx-formatting.js +5 -5
- package/CanopyX.Html/Assets/canopyx-forms.css +5 -5
- package/CanopyX.Html/Assets/canopyx-forms.js +1 -1
- package/CanopyX.Html/Assets/canopyx-grid-module.mjs +97 -54
- package/CanopyX.Html/Assets/canopyx-grid-options.css +10 -0
- package/CanopyX.Html/Assets/canopyx-grid-options.js +47 -0
- package/CanopyX.Html/Assets/canopyx-grid.css +199 -261
- package/CanopyX.Html/Assets/canopyx-grid.js +97 -54
- package/CanopyX.Html/Assets/canopyx-grouping.css +17 -17
- package/CanopyX.Html/Assets/canopyx-grouping.js +12 -9
- package/CanopyX.Html/Assets/canopyx-highlight.css +14 -14
- package/CanopyX.Html/Assets/canopyx-highlight.js +2 -2
- package/CanopyX.Html/Assets/canopyx-interactive.css +94 -155
- package/CanopyX.Html/Assets/canopyx-interactive.js +33 -14
- package/CanopyX.Html/Assets/canopyx-labels-de.js +5 -0
- package/CanopyX.Html/Assets/canopyx-labels-es.js +5 -0
- package/CanopyX.Html/Assets/canopyx-labels-fr.js +5 -0
- package/CanopyX.Html/Assets/canopyx-labels-it.js +5 -0
- package/CanopyX.Html/Assets/canopyx-labels-pl.js +5 -0
- package/CanopyX.Html/Assets/canopyx-layouts.css +17 -17
- package/CanopyX.Html/Assets/canopyx-layouts.js +2 -10
- package/CanopyX.Html/Assets/canopyx-link.css +7 -7
- package/CanopyX.Html/Assets/canopyx-link.js +1 -1
- package/CanopyX.Html/Assets/canopyx-live.css +9 -9
- package/CanopyX.Html/Assets/canopyx-live.js +20 -15
- package/CanopyX.Html/Assets/canopyx-matrix.css +74 -74
- package/CanopyX.Html/Assets/canopyx-matrix.js +3 -4
- package/CanopyX.Html/Assets/canopyx-module.mjs +33 -14
- package/CanopyX.Html/Assets/canopyx-pager.css +2 -2
- package/CanopyX.Html/Assets/canopyx-pager.js +1 -1
- package/CanopyX.Html/Assets/canopyx-presenters.js +2 -2
- package/CanopyX.Html/Assets/canopyx-record-panel.css +57 -49
- package/CanopyX.Html/Assets/canopyx-record-panel.js +13 -8
- package/CanopyX.Html/Assets/canopyx-reporting-module.mjs +101 -57
- package/CanopyX.Html/Assets/canopyx-reporting.css +214 -276
- package/CanopyX.Html/Assets/canopyx-reporting.js +101 -57
- package/CanopyX.Html/Assets/canopyx-timeline.css +28 -28
- package/CanopyX.Html/Assets/canopyx-timeline.js +11 -10
- package/CanopyX.Html/Assets/canopyx-tree-tools.css +47 -47
- package/CanopyX.Html/Assets/canopyx-tree-tools.js +3 -3
- package/CanopyX.Html/Assets/canopyx.css +81 -142
- package/CanopyX.Html/Assets/canopyx.js +33 -14
- package/JavaScript/calendar.d.ts +15 -0
- package/JavaScript/flow.d.ts +6 -0
- package/JavaScript/grid.d.ts +29 -4
- package/JavaScript/live.d.ts +2 -0
- package/JavaScript/locales/de.mjs +5 -0
- package/JavaScript/locales/es.mjs +5 -0
- package/JavaScript/locales/fr.mjs +5 -0
- package/JavaScript/locales/it.mjs +5 -0
- package/JavaScript/locales/pl.mjs +5 -0
- package/JavaScript/plugins.d.ts +4 -0
- package/JavaScript/protocol.d.ts +1 -1
- package/JavaScript/records.d.ts +18 -4
- package/README.md +6 -2
- package/package.json +5 -1
|
@@ -24,14 +24,15 @@ function checkPage(doc,node){checkDocument(doc,"page");if(!Array.isArray(doc.ite
|
|
|
24
24
|
if(!Object.hasOwn(doc,"next"))throw new Error("CanopyX: page continuation is required.");if(doc.next!==null)requireIdentifier(doc.next,"page continuation");const parent=node?node.id:null;if(doc.parent!==parent)throw new Error("CanopyX: page parent does not match the requested node.");return doc}
|
|
25
25
|
function isCellObject(cell){return cell!==null&&typeof cell==="object"}
|
|
26
26
|
function cellValue(cell){return isCellObject(cell)?(cell.value===undefined?null:cell.value):(cell===undefined?null:cell)}
|
|
27
|
-
const NO_TONE={cls:"",host:null};const tones=new Map();function
|
|
27
|
+
const NO_TONE={cls:"",host:null};const tones=new Map();function toneVariable(name,background=false,fallback){const role={success:"good",warning:"warn",danger:"bad"}[name]||name;const key="--hfx-color-status-"+role +(background?"-bg":"-fg");return "var("+key +(STATUS_FALLBACKS[key]||fallback?"," +(STATUS_FALLBACKS[key]||fallback):"")+ ")"}
|
|
28
|
+
function toneOf(name){let tone=typeof name==="string"?tones.get(name):NO_TONE;if(!tone){if(!/^[a-z][a-z0-9-]{0,31}$/.test(name) || name.endsWith("-bg")) {
|
|
28
29
|
return NO_TONE}
|
|
29
30
|
const host=!/^(neutral|info|success|warning|danger|muted)$/.test(name);
|
|
30
31
|
tone={cls:" cx-tone-"+name +(host?" cx-toned":""),host:host?name:null};if(tones.size<256)tones.set(name,tone)}
|
|
31
32
|
return tone}
|
|
32
33
|
function applyTone(element,base,tone){element.className=base+tone.cls;toneColors(element,tone)}
|
|
33
34
|
function toneColors(element,tone){if((element._tone||null)===tone.host){return}
|
|
34
|
-
element._tone=tone.host;if(tone.host){element.style.setProperty("--cx-t",
|
|
35
|
+
element._tone=tone.host;if(tone.host){element.style.setProperty("--cx-t",toneVariable(tone.host));element.style.setProperty("--cx-t-bg",toneVariable(tone.host,true))}else{element.style.removeProperty("--cx-t");element.style.removeProperty("--cx-t-bg")}}
|
|
35
36
|
function pad2(value){return value<10?"0"+value:String(value)}
|
|
36
37
|
const dateTexts=new Map();function dateText(value){let texts=dateTexts.get(value);if(texts===undefined){const time=Date.parse(value);const d=new Date(time);texts=isNaN(time)?null:[String(d.getUTCFullYear()).padStart(4,"0")+ "-"+pad2(d.getUTCMonth()+ 1)+ "-"+pad2(d.getUTCDate())+ " "+pad2(d.getUTCHours())+ ":"+pad2(d.getUTCMinutes()),String(d.getFullYear()).padStart(4,"0")+ "-"+pad2(d.getMonth()+ 1)+ "-"+pad2(d.getDate())+ " "+pad2(d.getHours())+ ":"+pad2(d.getMinutes())];if(dateTexts.size>=DATE_CACHE)dateTexts.clear();dateTexts.set(value,texts)}
|
|
37
38
|
return texts}
|
|
@@ -88,6 +89,12 @@ function trusted(kind,value){if(trustPolicy===undefined){try{trustPolicy=global.
|
|
|
88
89
|
catch(_){trustPolicy=null}}
|
|
89
90
|
return trustPolicy?trustPolicy["create"+kind](value):value}
|
|
90
91
|
function hostHtml(element,html,sanitize,kind){const text=String(html??""),value=sanitize?sanitize(text,{kind}):text;if(value?.nodeType)element.replaceChildren(value);else if(typeof value==="string")element.innerHTML=trusted("HTML",value);else if(global.trustedTypes?.isHTML?.(value))element.innerHTML=value;else throw new Error("CanopyX: invalid sanitizeHtml result.")}
|
|
92
|
+
const STATUS_FALLBACKS={"--hfx-color-status-bad-bg":"light-dark(#f9e4e4,#3c272a)","--hfx-color-status-bad-fg":"light-dark(#b8292a,#f47171)","--hfx-color-status-good-bg":"light-dark(#e2f0e9,#1f362f)","--hfx-color-status-good-fg":"light-dark(#177345,#4cc78a)","--hfx-color-status-info-bg":"light-dark(#e4ecfa,#262f41)","--hfx-color-status-info-fg":"light-dark(#2b5fc0,#74a2f7)","--hfx-color-status-neutral-bg":"light-dark(#eeeff0,#2a2c31)","--hfx-color-status-neutral-fg":"light-dark(#5b6069,#a0a5ae)","--hfx-color-status-warn-bg":"light-dark(#f8efde,#3b3322)","--hfx-color-status-warn-fg":"light-dark(#8c5c05,#eeb640)"};const MODE_ATTRIBUTES=["data-theme","data-cx-theme","data-hfx-mode","data-bs-theme","data-hfx-theme","data-hfx-tokens"];const THEME_ATTRIBUTES=[...MODE_ATTRIBUTES,"data-hfx-style","data-hfx-density","data-cx-fallback-mode","style","class"];function watchTheme(host,signal){const attributes=THEME_ATTRIBUTES;const previous=host.getAttribute("data-cx-fallback-mode");const refresh=()=>{const parent=host.parentElement&&getComputedStyle(host.parentElement);const inherited=parent?.colorScheme;let mode=null;if(!parent?.getPropertyValue("--hfx-color-surface").trim()){outer:for(let owner=host;owner;owner=owner.parentElement)for(const attribute of MODE_ATTRIBUTES){const value=owner.getAttribute(attribute);if(value==="light"||value==="dark"){mode=value;break outer}}}
|
|
93
|
+
if(parent?.getPropertyValue("--hfx-color-surface").trim()||!mode&&inherited&&inherited!=="normal"){if(host.hasAttribute("data-cx-fallback-mode"))host.removeAttribute("data-cx-fallback-mode")}else if(host.getAttribute("data-cx-fallback-mode")!==(mode||"auto"))host.setAttribute("data-cx-fallback-mode",mode||"auto")};const observer=new MutationObserver(refresh);for(let owner=host;owner;owner=owner.parentElement)observer.observe(owner,{attributes:true,attributeFilter:attributes});refresh();const dispose=()=>{observer.disconnect();if(previous===null)host.removeAttribute("data-cx-fallback-mode");else host.setAttribute("data-cx-fallback-mode",previous)};signal?.addEventListener("abort",dispose,{once:true});return dispose}
|
|
94
|
+
function overlayTheme(host,element,inherit=false){for(const name of["data-hfx-style","data-hfx-mode","data-hfx-density"]){const owner=host.closest("["+name+"]");if(owner&&!inherit)element.setAttribute(name,owner.getAttribute(name));else element.removeAttribute(name)}
|
|
95
|
+
const theme=getComputedStyle(host),parent=inherit&&host.parentElement&&getComputedStyle(host.parentElement);element.style.colorScheme=theme.colorScheme;const copied=[];for(const name of theme)if((name.startsWith("--cx-")||name.startsWith("--hfx-"))&&(!parent||theme.getPropertyValue(name)!==parent.getPropertyValue(name))){element.style.setProperty(name,theme.getPropertyValue(name));copied.push(name)}
|
|
96
|
+
return copied}
|
|
97
|
+
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}
|
|
91
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();
|
|
92
99
|
}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(); }
|
|
93
100
|
else if(c==="]"){closed=true;break}}
|
|
@@ -204,7 +211,7 @@ throw new Error("CanopyX: unknown source kind '"+kind+"'.")}
|
|
|
204
211
|
async function remoteJson(url,type,timeoutMs,lifetime,signal){const controller=new AbortController();const signals=Array.from(new Set([lifetime,signal].filter(Boolean)));const abort=()=>controller.abort();signals.forEach((item)=>{if(item.aborted)abort();else item.addEventListener("abort",abort,{once:true})});let timedOut=false;const timer=setTimeout(()=>{timedOut=true;abort()},timeoutMs);try{const response=await fetch(url,{headers:{Accept:"application/json"},signal:controller.signal});if(!response.ok){if(response.body)await response.body.cancel().catch(()=>{});throw new Error(response.status+" "+response.statusText)}
|
|
205
212
|
return checkDocument(await response.json(),type)}catch(error){if(timedOut)throw new Error("CanopyX: remote request timed out after "+timeoutMs+" milliseconds.");throw error}finally{abort();clearTimeout(timer);signals.forEach((item)=>item.removeEventListener("abort",abort))}}
|
|
206
213
|
class TreeGrid{constructor(host,options){const view=checkDocument(options.view,"view");requireIdentifier(view.id,"view ID");if(view.columns.some(column=>column.format!==undefined))throw new Error("CanopyX: number formats apply to flat grids only.");this.host=host;this.view=view;this.opts=options;for(const name of["isSelectable","beforeSelect","sanitizeHtml"]){if(options[name]!==undefined&&typeof options[name]!=="function")throw new Error("CanopyX: "+name+" must be a function.")}
|
|
207
|
-
this.id="cx" + ++instanceSeq;this.lifetime=new AbortController();this.source=options.source||sourceFor(view,{signal:this.lifetime.signal,timeoutMs:options.requestTimeoutMs});this.queryAware=this.source.queryAware===true;this.dataLifetime=new AbortController();this.acceptedQuery=Object.freeze({version:1,sort:null,filters:Object.freeze([])});this.datasetRevision=null;this.rowH=view.rowHeight||
|
|
214
|
+
this.id="cx" + ++instanceSeq;this.lifetime=new AbortController();this.source=options.source||sourceFor(view,{signal:this.lifetime.signal,timeoutMs:options.requestTimeoutMs});this.queryAware=this.source.queryAware===true;this.dataLifetime=new AbortController();this.acceptedQuery=Object.freeze({version:1,sort:null,filters:Object.freeze([])});this.datasetRevision=null;this.rowH=view.rowHeight||40;this.pageSize=view.pageSize||100;this.retainedNodeLimit=options.retainedNodeLimit===undefined?1024:options.retainedNodeLimit;if(!validStructuralCount(this.retainedNodeLimit))throw new Error("CanopyX: retainedNodeLimit must be a nonnegative 32-bit integer.");this.inactiveNodeLimit=options.inactiveNodeLimit===undefined?4096:options.inactiveNodeLimit;if(!validStructuralCount(this.inactiveNodeLimit))throw new Error("CanopyX: inactiveNodeLimit must be a nonnegative 32-bit integer.");this.multi=view.selection==="multiple";this.lang=document.documentElement.lang||undefined;this.labels=labelsFor(view.labels,options.labels);this.tools=Object.assign({},view.toolbar,options.toolbar);if(Object.entries(this.tools).some(([name,value])=>!/^(search|filters|columns|views|export|more|matches|layout)$/.test(name) || typeof value !== "boolean"))
|
|
208
215
|
throw new Error("CanopyX: toolbar options are booleans by control name.");this.local=view.timeZone==="local";this.fmt=formatting(this.lang,this.local,this.labels);this.kind="tree";this.plugins=viewPlugins(options,this.kind);const renderers=hostRenderers(options.renderers||{},view.columns,this.plugins);if(!options.formatLink!==!options.parseLink){throw new Error("CanopyX: formatLink and parseLink define one link scheme and are given together.")}
|
|
209
216
|
this.columns=view.columns.map((column,index)=>({...column,hidden:index>0&&!!column.hidden,render:Object.hasOwn(renderers,column.id)?renderers[column.id]:null}));this.columns.forEach(prepareWidth);this.columns.forEach(validateColumnValues);this.keyMap=new Map();this.root={key:null,h:null,parent:null,level:0,idx:0,expanded:true,children:null,total:null,next:null,loading:false,error:null};if(!options.source&&(!view.source||view.source.kind==="inline")){this.root.inlineItems=view.roots||[]}
|
|
210
217
|
this.rows=[];this.tops=[0];this.total=0;this.version=1;this.rendered=new Map();this.pool=[];this.focused=null;this.selected=new Set();this.anchor=null;this.filter=null;this.declaredFilter=null;this.filterExpand=false;this.activeFilters=new Set();this.sortState=null;this.typeBuf="";this.typeAt=0;this.rafId=0;this.iconTemplates=this.buildIcons(view.icons||{});this.initializing=true;this.prepareViewModes();this.build();this.buildToolbar();if(view.deepLink)loadPart(LINKS).catch(()=>{});this.ready=this.modesReady?Promise.all([this.init(),this.modesReady]).then(([result])=>result):this.init()}
|
|
@@ -271,8 +278,7 @@ value.sort===undefined||typeof value!=="object")throw new Error("CanopyX: query
|
|
|
271
278
|
const named=new Set(value.filters);if(named.size!==value.filters.length||value.filters.some(id=>!(grid.view.filters||[]).some(f=>f.id===id)))
|
|
272
279
|
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})}
|
|
273
280
|
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}
|
|
274
|
-
Object.assign(TreeGrid.prototype,{getQuery(){return{version:1,sort:this.sortState&&Object.assign({},this.sortState),filters:Array.from(this.activeFilters)}},sourceRequest(signal){return this.queryAware?{signal:signal||this.dataLifetime.signal,query:this.acceptedQuery,revision:this.datasetRevision}:{signal}},syncQueryControls(){this.toolbar.querySelectorAll("[data-cx-filter]").forEach(input=>{input.checked=this.activeFilters.has(input.getAttribute("data-cx-filter"))})},querySortHeader(id){const query=this.pendingQuery||this.acceptedQuery,state=query.sort&&query.sort.column===id?query.sort.direction:null;this.sort(id,state==="asc"?"desc":state==="desc"?null:"asc").catch(()=>{})}});Object.assign(TreeGrid.prototype,{retireWrapper(w){w._invalidated=true;this.retirePage(w);if(this.inlineRetained&&this.inlineRetained.get(w.key)===w)this.inlineRetained.delete(w.key);if(this.inactiveCache)this.inactiveCache.delete(w);if(this.keyMap.get(w.key)===w)this.keyMap.delete(w.key);w.children=null;w.inlineCache=null;w.inlineOrder=null;const selected=this.selected.delete(w);if(this.anchor===w)this.anchor=null;return selected?w:null}});Object.assign(TreeGrid.prototype,{build(){const host=this.host;host.classList.add("cx-host");
|
|
275
|
-
host.style.setProperty("--cx-row-h",this.rowH+"px");this.setTreeColumnPinned(this.view.pinTreeColumn);this.toolbar=h("div","cx-toolbar");this.toolbar.hidden=true;const grid=this.grid=h("div","cx-grid");grid.id=this.id;grid.setAttribute("role","treegrid");grid.setAttribute("aria-label",this.view.label);if(this.multi){grid.setAttribute("aria-multiselectable","true")}
|
|
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")}
|
|
276
282
|
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++}
|
|
277
283
|
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)}
|
|
278
284
|
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}}
|
|
@@ -519,7 +525,7 @@ if(active>=0){list.children[active].setAttribute("aria-selected","false")}
|
|
|
519
525
|
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=""}
|
|
520
526
|
close()}else{return}
|
|
521
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)}}}
|
|
522
|
-
const PART_URL=typeof document!=="undefined"&&document.currentScript?.src;const PARTS={"tree-tools":["
|
|
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);
|
|
523
529
|
function registerPart(name,part){if(!partName(name)||!part||typeof part.version!=="string"||typeof part.install!=="function"||
|
|
524
530
|
part.requires!==undefined&&!(Array.isArray(part.requires)&&part.requires.every(partName)))throw new Error("CanopyX: invalid part.");PART_CODE.set(name,part)}
|
|
525
531
|
function definePart(View,name,label,context){const parts=View.prototype.parts||={};return parts[name]={name,label,context,parts}}
|
|
@@ -529,7 +535,7 @@ const load=(element,attribute,file,kind)=>new Promise((resolve,reject)=>{const u
|
|
|
529
535
|
.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")
|
|
530
536
|
.finally(()=>script.remove()).catch(error=>{part.scriptReady=null;throw error}));await Promise.all([style,code])}}
|
|
531
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})}
|
|
532
|
-
const partQueue=global.CanopyXParts=global.CanopyXParts||[];partQueue.forEach(entry=>registerPart(...entry));partQueue.length=0;partQueue.push=(...entries)=>{entries.forEach(entry=>registerPart(...entry));return 0};const TREE_TOOLS=definePart(TreeGrid,"tree-tools","tree tools",()=>({TreeGrid,h,setText,fill,numberFormat,watchFlyout,columnWidth,prepareWidth,cellText,cellValue,isCellObject,foldText,formatting,sortKey,compareKeys,EXPORT_FORMATS,exportFormat,exportTimeout,exportFormatsOf:EXPORT_IMPL.formatsOf,INDENT,MAX_PROTOCOL_INTEGER,hostControl,detailCell,HostCellContext,disposeHostSlot,loadPart,definePart,pluginItems,applyTone,toneOf,badgeElement,RECORD_IMPL,svgIcon,gridExportField,columnNumericTone,columnValueTone}));const SEARCH_IMPL={},SEARCH_PART=definePart(TreeGrid,"search","sidecar search",()=>({SEARCH_IMPL,checkDocument,badIndex,isCount,isIdentifier,recentCache,packBytes,shardKey,foldText,trimSeparators,rankHits,validateSearchHit,PACK_CACHE,PACK_CACHE_BYTES,SHARD_CACHE,ENTRY_CACHE,ENTRY_BATCH,SEARCH_CANDIDATES}));async function requirePart(name){await this.toolsReady;const part=Object.hasOwn(this.parts,name)?this.parts[name]:null;if(!part)throw new Error("CanopyX: unknown part '"+name+"'.");return loadPart(part)}
|
|
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)}
|
|
533
539
|
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")
|
|
534
540
|
throw new Error("CanopyX: invalid state column.");seen.add(c.id);return{id:c.id,width:c.width,hidden:c.hidden}}
|
|
535
541
|
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})})}
|
|
@@ -543,9 +549,9 @@ catch(error){/* Nodes removed since the snapshot are skipped. */ }
|
|
|
543
549
|
}},applyStatePosition(state,current){if(!state.version)return;const valid=path=>{const w=path&&this.keyMap.get(path[path.length-1]);return w&&JSON.stringify(this.pathOf(w))===JSON.stringify(path)?w:null};this.setSelection(state.selection.map(valid).filter(Boolean).map(w=>w.key));if(this.destroyed||current.signal.aborted)return;const focused=valid(state.focus);if(focused&&this.indexOf(focused)>=0)this.setFocus(focused,false);const anchor=state.anchor&&valid(state.anchor.path);if(anchor)this.restoreScrollAnchor({id:anchor.key,offset:state.anchor.offset})}});const PLUGINS=new Map();function plugin(value){const item=Object.freeze({...value}),fn=handler=>typeof handler==="function";const entry=menu=>action=>action&&typeof action.label==="string"&&
|
|
544
550
|
(fn(action.run)&&action.render===undefined||menu&&fn(action.render)&&action.run===undefined);if(!value||!partName(item.name)||Object.hasOwn(PARTS,item.name)||[item.init,item.destroy].some(hook=>hook!==undefined&&!fn(hook))||
|
|
545
551
|
["requires","views","toolbarItems","menuItems","exportFormats","recordActions"].some(key=>item[key]!==undefined&&!Array.isArray(item[key]))||
|
|
546
|
-
["cellRenderers","columnTypes","editors","events","aggregates","detailRenderers","drawerSections"].some(key=>item[key]!==undefined&&Object(item[key])!==item[key])||
|
|
552
|
+
["cellRenderers","columnTypes","editors","events","aggregates","detailRenderers","drawerSections","filterOperators","sortComparators"].some(key=>item[key]!==undefined&&Object(item[key])!==item[key])||
|
|
547
553
|
!(item.requires||[]).every(partName)||!(item.views||[]).every(kind=>kind==="tree"||kind==="grid")||
|
|
548
|
-
![...Object.values(item.cellRenderers||{}),...Object.values(item.events||{}),...Object.values(item.detailRenderers||{}),...Object.values(item.drawerSections||{})].every(fn)||
|
|
554
|
+
![...Object.values(item.cellRenderers||{}),...Object.values(item.events||{}),...Object.values(item.detailRenderers||{}),...Object.values(item.drawerSections||{}),...Object.values(item.filterOperators||{}),...Object.values(item.sortComparators||{})].every(fn)||
|
|
549
555
|
!(item.toolbarItems||[]).every(entry())||!(item.recordActions||[]).every(entry())||!(item.menuItems||[]).every(entry(true)))
|
|
550
556
|
throw new Error("CanopyX: invalid plugin '"+item.name+"'.");item.exportFormats?.forEach(exportFormat);return item}
|
|
551
557
|
function use(value){const item=plugin(value);if(PLUGINS.has(item.name))throw new Error("CanopyX: plugin '"+item.name+"' is already registered.");PLUGINS.set(item.name,item);const formats=item.exportFormats?.map(registerExportFormat)||[];return()=>{if(PLUGINS.get(item.name)===item){PLUGINS.delete(item.name);formats.forEach(dispose=>dispose())}}}
|
|
@@ -583,14 +589,27 @@ finally{navigation.dispose()}
|
|
|
583
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.
|
|
584
590
|
}
|
|
585
591
|
this.linkChanged=this.dataLifetime.signal;return this.ready.then(()=>undefined,()=>undefined)}
|
|
586
|
-
return this.openDeepLink()};
|
|
592
|
+
return this.openDeepLink()};function sharedDensity(host){const value=host.closest("[data-hfx-density]")?.getAttribute("data-hfx-density");return value==="compact"||value==="comfortable"?value:null}
|
|
593
|
+
function watchSharedDensity(view){let previous=sharedDensity(view.host);const metrics=()=>{if(previous)view.host.style.setProperty("--cx-compact",previous==="compact"?"1":"0");else view.host.style.removeProperty("--cx-compact")};metrics();const observer=new MutationObserver(()=>{const current=sharedDensity(view.host);if(current===previous||view.destroyed)return;previous=current;metrics();refreshSharedDensity(view)});for(let owner=view.host;owner;owner=owner.parentElement){observer.observe(owner,{attributes:true,attributeFilter:["data-hfx-density"]})}
|
|
594
|
+
view.lifetime.signal.addEventListener("abort",()=>observer.disconnect(),{once:true})}
|
|
595
|
+
function layoutAnchor(view){const rows=view.rowProjection||view,top=view.logicalTop(),count=rows.rowCount();if(!count)return null;const index=rows.rowAt(top),height=(view.autoRows?null:view.rowH)||1;const offset=Math.max(0,top-rows.rowTop(index));return{index,offset,share:Math.max(0,Math.min(1,offset / height)) };
|
|
596
|
+
}
|
|
597
|
+
function layoutRows(view,anchor){const rows=view.rowProjection||view;for(const row of[...view.rowCache.values(),...view.placeholders.values()])row.hpx=view.rowH;if(view.autoRows){for(const[index,height]of view.rowHeights)if(height<view.rowH)view.rowHeights.set(index,view.rowH);view.rowOffsets=null;view.measureNeeded=true;view.render()}
|
|
598
|
+
else{const bounds=view.rowBounds(),count=view.rowProjection?rows.rowCount():Math.max(0,bounds.last-bounds.first+1);view.total=count*view.rowH;view.syncScrollRange(anchor?rows.rowTop(anchor.index)+ anchor.share*view.rowH:0)}
|
|
599
|
+
if(anchor&&view.autoRows){const top=rows.rowTop(anchor.index),height=rows.rowTop(anchor.index+1)- top;view.setLogicalTop(top+Math.min(anchor.offset,Math.max(0,height-1)))}
|
|
600
|
+
view.render()}
|
|
601
|
+
function layoutApplyTree(view){const before=view.rowH,after=densityRowHeight(view,view.density);if(before!==after){const anchor=view.captureScrollAnchor();view.rowH=after;const status=row=>{if(row&&row.hpx===before)row.hpx=after};status(view.root._status);for(const row of view.keyMap.values()){if(!row.h?.detail&&row.hpx===before)row.hpx=after;status(row._status)}
|
|
602
|
+
for(const row of view.rows)if(row.status)status(row);view.retop();if(anchor)view.restoreScrollAnchor(anchor)}
|
|
603
|
+
view.fitKey=null;view.version++;if(view.fitReady)view.applyWidths();view.render()}
|
|
604
|
+
function refreshSharedDensity(view){if(!view.grid)return;if(view.kind==="grid"){view.fitKey=null;view.fitFont=null;if(view.layoutMode==="cards"&&VIEW_MODES.refreshCardDensity)VIEW_MODES.refreshCardDensity(view);else{const anchor=layoutAnchor(view);view.rowH=densityRowHeight(view,view.density);view.version++;layoutRows(view,anchor);view.applyWidths()}}else layoutApplyTree(view);view.host.style.setProperty("--cx-row-h",view.rowH+"px");view.fitHeight?.()}
|
|
605
|
+
DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{linkFilteredBy:"Filtered by {source}: {values}",linkRemoveFilter:"Remove the filter from {source}: {values}",linkFiltered:"Filtered by {source}: {count} rows",linkHighlighted:"{count} rows highlighted from {source}",linkHighlightedRows:"{count} rows highlighted",linkCleared:"Linked filters removed"}));const LINK_IMPL={TreeGrid,queryOwn:Symbol("own conditions")},LINK_PART=definePart(TreeGrid,"link","linked views",()=>({LINK_IMPL,h,setText,filterChipContent,fill,numberFormat,cellValue,setAttr,cellMatches}));const LINK_METHODS=["setExternalFilter","clearExternalFilters","setHighlight","clearHighlight","startLinkEvents"];function linkMethods(View){for(const name of LINK_METHODS)(View.prototype[name]=function(...args){return this.destroyed?Promise.resolve(/Highlight/.test(name) ? 0 : name === "startLinkEvents" ? undefined : false) : loadPart(LINK_PART).then(() => this[name](...args));
|
|
587
606
|
}).linkStub=true;View.prototype.getExternalFilters=function(){return(this.linkCommitted||[]).map(item=>JSON.parse(JSON.stringify(item)))};View.prototype.getHighlight=function(){return Array.from(this.linkHighlight||[])};View.prototype.linkStart=function(){if(this.opts.linkEvents===true)return loadPart(LINK_PART).then(()=>this.linkWatch()).catch(error=>{this.emit("error",{error});throw error})}}
|
|
588
607
|
linkMethods(TreeGrid);function linkGridPart(View){(Object.hasOwn(View.prototype,"parts")?View.prototype.parts:View.prototype.parts={}).link=LINK_PART}
|
|
589
608
|
function linkReady(grid,ready){return Promise.all([ready,grid.linkStart()]).then(([result])=>result)}
|
|
590
609
|
function linkApi(grid){const api={};for(const name of LINK_METHODS.concat("getExternalFilters","getHighlight"))api[name]=(...args)=>grid[name](...args);return api}
|
|
591
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)}
|
|
592
611
|
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}))}
|
|
593
|
-
DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{matchesHighlight:"Highlight matches",matchesCount:"[one]{count} match[other]{count} matches",matchesPosition:"{current} of {count}",matchesNone:"No matches",matchesLoaded:"[one]{count} match in loaded rows[other]{count} matches in loaded rows",matchesPrevious:"Previous match",matchesNext:"Next match",matchesAnnounce:"Match {current} of {count}, {column}",layoutMenu:"Layout",layoutFit:"Fit to width",layoutScroll:"All columns, scroll sideways",layoutCards:"Cards",layoutDensity:"Density",layoutCompact:"Compact",layoutNormal:"Normal",layoutComfortable:"Comfortable",layoutChanged:"Layout: {mode}, {density}",layoutSort:"Sort by"}));const LAYOUT_MODES=["fit","scroll","cards"],LAYOUT_DENSITIES=["compact","default","comfortable"];const DENSITY_STEP={tree:{compact:-
|
|
612
|
+
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");
|
|
594
613
|
if(!options||typeof options!=="object"||Array.isArray(options)||Object.keys(options).some(key=>!HIGHLIGHT_KEYS.includes(key))||
|
|
595
614
|
HIGHLIGHT_KEYS.slice(0,5).some(key=>options[key]!==undefined&&typeof options[key]!=="boolean")||
|
|
596
615
|
options.minLength!==undefined&&(!Number.isInteger(options.minLength)||options.minLength<1||options.minLength>32)||
|
|
@@ -606,12 +625,12 @@ function readModeState(view,state){const result={};if(state.layout!==undefined){
|
|
|
606
625
|
throw new Error("CanopyX: invalid saved layout.");if(options)result.layout={mode:options.modes.includes(layout.mode)?layout.mode:options.mode,density:layout.density}}
|
|
607
626
|
if(state.highlight!==undefined){if(typeof state.highlight!=="boolean")throw new Error("CanopyX: invalid saved highlight choice.");if(view.highlightOptions)result.highlight=state.highlight}
|
|
608
627
|
return result}
|
|
609
|
-
function densityRowHeight(view,density){const steps=DENSITY_STEP[view.kind];return Math.max(20,Math.min(64,view.baseRowH+steps[density]- steps[view.declaredDensity]))}
|
|
610
|
-
const VIEW_MODE_METHODS={prepareViewModes(){const view=this.view,columns=this.columns||view.columns;this.highlightOptions=readSearchHighlight(view.searchHighlight,columns);this.declaredDensity=this.kind==="grid"?view.density||"default":"default";this.layoutOptions=readLayout(view.layout,this.kind,this.declaredDensity);this.baseRowH=this.rowH;this.adoptModes({layout:this.layoutOptions||{mode:"fit",density:this.declaredDensity},highlight:!!this.highlightOptions?.enabled})},adoptModes(choice){if(choice.layout){this.layoutMode=choice.layout.mode;this.density=choice.layout.density}
|
|
628
|
+
function densityRowHeight(view,density){const shared=sharedDensity(view.host);if(shared)return shared==="compact"?32:40;const steps=DENSITY_STEP[view.kind];return Math.max(20,Math.min(64,view.baseRowH+steps[density]- steps[view.declaredDensity]))}
|
|
629
|
+
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}
|
|
611
630
|
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))
|
|
612
631
|
this.setLayout(state.layout).catch(error=>this.emit("error",{error}));if(state.highlight!==undefined&&state.highlight!==!!this.highlightOn)
|
|
613
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))
|
|
614
|
-
.catch(error=>this.emit("error",{error}))))},getLayout(){return Object.freeze({mode:this.layoutMode,density:this.density,modes:this.layoutOptions?this.layoutOptions.modes:Object.freeze(["fit"])})},setLayout(change){if(!this.layoutOptions)return Promise.reject(new Error("CanopyX: this view declares no layout modes."));return this.requirePart("layouts").then(()=>VIEW_MODES.setLayout(this,change))},getMatches(){return VIEW_MODES.matches?VIEW_MODES.matches(this):Object.freeze({enabled:!!this.highlightOn,total:0,current:0,complete:true})},setSearchHighlight(enabled){if(typeof enabled!=="boolean")return Promise.reject(new Error("CanopyX: the highlight switch is a boolean."));if(!this.highlightOptions)return Promise.reject(new Error("CanopyX: this view declares no search highlighting."));return this.requirePart("highlight").then(()=>VIEW_MODES.setHighlight(this,enabled))},nextMatch(options){return this.stepMatch(1,options)},previousMatch(options){return this.stepMatch(-1,options)},stepMatch(direction,options){if(!this.highlightOptions)return Promise.reject(new Error("CanopyX: this view declares no search highlighting."));return this.requirePart("highlight").then(()=>VIEW_MODES.step(this,direction,options?.focus!==false))}};Object.assign(TreeGrid.prototype,VIEW_MODE_METHODS);const viewModeContext=()=>({VIEW_MODES,TreeGrid,h,setText,fill,numberFormat,foldText,cellText,cellValue,isCellObject,setAttr,toneOf,watchFlyout,densityRowHeight,MAX_PROTOCOL_INTEGER,LAYOUT_DENSITIES,plural,svgIcon});definePart(TreeGrid,"highlight","search highlighting",viewModeContext);definePart(TreeGrid,"layouts","layout modes",viewModeContext);const MODES_TOOLBAR=TreeGrid.prototype.buildToolbar;TreeGrid.prototype.buildToolbar=function(){MODES_TOOLBAR.call(this);if(this.highlightOptions||this.layoutOptions)this.modesReady=Promise.resolve(this.toolsReady).then(()=>this.destroyed||this.startViewModes());this.lifetime.signal.addEventListener("abort",()=>this.host.removeAttribute("data-cx-layout"),{once:true})};Object.assign(TreeGrid.prototype,{destroy(){if(this.destroyed)return;this.destroyed=true;for(const row of[...this.rendered.values(),...this.pool])disposeRowHostCells(row);this.lifetime.abort();this.dataLifetime.abort();if(this.queryController)this.queryController.abort();if(this.restoreController)this.restoreController.abort();if(this.cancelResize)this.cancelResize();clearTimeout(this.saveTimer);clearTimeout(this.layoutTimer);if(this.cancelSearch)this.cancelSearch();if(this.disposeSearchFlyout)this.disposeSearchFlyout();cancelAnimationFrame(this.rafId);this.resizeObserver.disconnect();if(this.detailObserver)this.detailObserver.disconnect();this.grid.removeEventListener("scroll",this.onScroll);this.grid.removeEventListener("wheel",this.onScaledWheel);this.grid.removeEventListener("touchstart",this.onScaledTouchStart);this.grid.removeEventListener("touchmove",this.onScaledTouchMove);this.grid.removeEventListener("touchend",this.onScaledTouchEnd);this.grid.removeEventListener("touchcancel",this.onScaledTouchEnd);global.removeEventListener("beforeprint",this.onPrint);global.removeEventListener("hashchange",this.onHash);global.removeEventListener("popstate",this.onHash);if(this.linkOpening)this.linkOpening.abort();[this.toolbar,this.grid,this.live,this.outline].forEach(element=>element.remove());this.host.classList.remove("cx-pin-tree");this.host.removeAttribute("data-cx-ready");this.host.removeAttribute("data-canopyx-mounted");this.keyMap.clear();this.selected.clear();this.rendered.clear();this.pool.length=0;if(this.inactiveCache)this.inactiveCache.clear();if(this.inlineRetained)this.inlineRetained.clear();this.rows=[];this.tops=[0];this.total=0;this.root.children=null;this.root.inlineCache=null;this.root.inlineOrder=null;this.focused=null;this.anchor=null;this.source=null;this.touchScroll=null;this.opts={};for(const column of this.columns)column.render=null;this.filter=null;this.declaredFilter=null;this.pendingRestorationToggles=null;this.scrolledCell=null;this.focusHandoff=null;this.cancelResize=null;this.cancelSearch=null;this.disposeSearchFlyout=null;this.canvas.replaceChildren();this.outline.replaceChildren()}});function createTreeGrid(host,options){if(!host||!options||!options.view){throw new Error("CanopyX: createTreeGrid needs a host element and a view document.")}
|
|
633
|
+
.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.")}
|
|
615
634
|
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"])
|
|
616
635
|
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);
|
|
617
636
|
throw error};api.ready=linkReady(grid,api.ready);Object.freeze(api);activeGrids.set(host,api);host.setAttribute("data-canopyx-mounted","true");host.canopyx=api;recordStart(grid);return api}
|
package/JavaScript/calendar.d.ts
CHANGED
|
@@ -18,6 +18,12 @@ export interface GridCalendarSource {
|
|
|
18
18
|
label: string;
|
|
19
19
|
tone?: string;
|
|
20
20
|
ics?: string;
|
|
21
|
+
/** Same-origin JSON event array, requested with start/end/timeZone for each visible range. */
|
|
22
|
+
url?: string;
|
|
23
|
+
/** Extra query parameters; start, end and timeZone are reserved. */
|
|
24
|
+
fetchParams?: Readonly<Record<string, string>>;
|
|
25
|
+
/** A six-digit hexadecimal source colour. */
|
|
26
|
+
color?: string;
|
|
21
27
|
/** Starts switched off. */
|
|
22
28
|
hidden?: boolean;
|
|
23
29
|
}
|
|
@@ -86,6 +92,8 @@ export interface GridCalendarDefinition<Row extends GridRow = GridRow> {
|
|
|
86
92
|
allDay?: GridColumnId<Row>;
|
|
87
93
|
/** A text column with the event's resource id (a node id of resources.view). */
|
|
88
94
|
resource?: GridColumnId<Row>;
|
|
95
|
+
/** A text column containing a JSON array of resource ids, added to the single resource. */
|
|
96
|
+
resourceIds?: GridColumnId<Row>;
|
|
89
97
|
/** The column whose presenter draws the event's status; its tone colours the event. */
|
|
90
98
|
status?: GridColumnId<Row>;
|
|
91
99
|
/** A text column with an RRULE (FREQ DAILY, WEEKLY, MONTHLY or YEARLY with INTERVAL, COUNT, UNTIL, BYDAY, BYMONTHDAY, BYMONTH, BYSETPOS, WKST). */
|
|
@@ -186,6 +194,7 @@ export interface GridCalendarEvent {
|
|
|
186
194
|
readonly allDay: boolean;
|
|
187
195
|
readonly title: string;
|
|
188
196
|
readonly resource: string | null;
|
|
197
|
+
readonly resourceIds?: readonly string[];
|
|
189
198
|
readonly recurring: boolean;
|
|
190
199
|
readonly background?: boolean;
|
|
191
200
|
/** The event's source id (sources), or null. */
|
|
@@ -252,6 +261,10 @@ export interface CalendarEventInput {
|
|
|
252
261
|
description?: string;
|
|
253
262
|
tone?: string;
|
|
254
263
|
resource?: string;
|
|
264
|
+
resourceIds?: readonly string[];
|
|
265
|
+
/** Master event id and original occurrence start for an override. */
|
|
266
|
+
series?: string;
|
|
267
|
+
recurrenceId?: Date | string;
|
|
255
268
|
recurrence?: string;
|
|
256
269
|
exceptions?: string;
|
|
257
270
|
source?: string;
|
|
@@ -356,6 +369,8 @@ export interface GridCalendarApi {
|
|
|
356
369
|
exportCalendar(options?: { scope?: "visible" | "filtered" | "selected" | "all"; fileName?: string; download?: boolean }): Promise<{ blob: Blob; fileName: string; text: string }>;
|
|
357
370
|
/** Opens an event's record (by occurrence or record id). */
|
|
358
371
|
openCalendarEvent(id: string): Promise<unknown>;
|
|
372
|
+
/** Opens the title/time form for one recurring occurrence. False if this event cannot be edited. */
|
|
373
|
+
editCalendarOccurrence(id: string): Promise<boolean>;
|
|
359
374
|
clearCalendarSelection(): void | Promise<void>;
|
|
360
375
|
/** Shows (true) or hides a source's events; omitted switches it. Resolves with whether they show. */
|
|
361
376
|
setCalendarSource(id: string, visible?: boolean): boolean | Promise<boolean>;
|
package/JavaScript/flow.d.ts
CHANGED
|
@@ -150,6 +150,8 @@ export interface FlowStep {
|
|
|
150
150
|
title?: string;
|
|
151
151
|
description?: string;
|
|
152
152
|
type?: "form" | "info" | "pick" | "review";
|
|
153
|
+
/** Information steps: at most 32 read-only facts, with full wrapped plain-text values up to 32768 characters. Never submitted as answers. */
|
|
154
|
+
facts?: readonly { readonly label: string; readonly value: string }[];
|
|
153
155
|
fields?: readonly FlowField[];
|
|
154
156
|
sections?: readonly FlowSection[];
|
|
155
157
|
when?: FlowCondition;
|
|
@@ -261,6 +263,8 @@ export interface FlowHookContext { signal: AbortSignal }
|
|
|
261
263
|
|
|
262
264
|
/** The submit event's detail: the proposal, how to answer it, and each secret once. */
|
|
263
265
|
export interface FlowSubmitDetail extends Readonly<FlowSubmission> {
|
|
266
|
+
/** Retired when answers change, the flow resets/destroys, or the submission settles. Cancellation cannot undo a server write already committed. */
|
|
267
|
+
readonly signal: AbortSignal;
|
|
264
268
|
respondWith(answer: FlowAnswer | Promise<FlowAnswer>): void;
|
|
265
269
|
/** A secret's value, once per field, until the answer settles; null afterwards. */
|
|
266
270
|
secret(fieldId: string): string | null;
|
|
@@ -371,6 +375,8 @@ export interface FlowApi {
|
|
|
371
375
|
/** Runs a check now; resolves with its result as the flow keeps it (field messages show in place), or null when it was cancelled.
|
|
372
376
|
* Rejects for a check the flow does not have. */
|
|
373
377
|
runCheck(checkId: string): Promise<{ status: FlowCheckStatus; message: string | null; details: { label: string; value: string }[]; at: string } | null>;
|
|
378
|
+
/** Marks selected checks (all when omitted) stale after an external dependency changes. Cancels runs and ignores late answers without changing field values or dirty state. */
|
|
379
|
+
invalidateChecks(checkIds?: readonly string[]): void;
|
|
374
380
|
/** Loads a host-option field's options again. Rejects for any other field. */
|
|
375
381
|
refreshOptions(fieldId: string): Promise<void>;
|
|
376
382
|
/** Sets a task's state as the host sees it; null returns it to what the answers say. Throws for a flow that is no task list. */
|
package/JavaScript/grid.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { HostOptions, ExportFormat, ExportFormatOptions, ExportFormatResult
|
|
|
5
5
|
import type { CanopyPlugin } from "./plugins.js";
|
|
6
6
|
import type { GridEditorDefinition, GridValidation, GridEditingSettings, GridEditingOptions, GridEditingApi, GridCellValueChange,
|
|
7
7
|
GridRowCommit, GridCommitRowResult, GridCommitOutcome, GridCommit, GridCommitResult } from "./editing.js";
|
|
8
|
-
import type { RecordPanelDefinition, RecordLoader, RecordSectionRenderer, RecordAction, RecordOpenAll, OpenRecordOptions } from "./records.js";
|
|
8
|
+
import type { RecordPanelDefinition, RecordPanelOptions, RecordLoader, RecordSectionRenderer, RecordAction, RecordOpenAll, OpenRecordOptions } from "./records.js";
|
|
9
9
|
export * from "./records.js";
|
|
10
10
|
export * from "./index.js";
|
|
11
11
|
export * from "./enhance.js";
|
|
@@ -38,7 +38,7 @@ export type GridRowDetail =
|
|
|
38
38
|
| { type: "grid"; rows: GridRow[] }
|
|
39
39
|
| { type: "tree"; roots: unknown[] };
|
|
40
40
|
/** First match wins separately for the row and each condition-column cell; raw filter semantics apply. */
|
|
41
|
-
export type GridHighlightRule =
|
|
41
|
+
export type GridHighlightRule = GridBuiltinFilter & { target?: "row" | "cell" } &
|
|
42
42
|
({ tone: string; className?: string } | { tone?: string; className: string });
|
|
43
43
|
/** Portable cell semantics, independent of DOM renderers and stylesheet rules. Datetime values retain the original ISO string and its explicit time zone and precision. */
|
|
44
44
|
export interface GridExportCell {
|
|
@@ -84,6 +84,14 @@ export interface GridNumberFormat {
|
|
|
84
84
|
export type GridColumn<Row extends GridRow = GridRow> = Omit<CanopyColumn, "id" | "editable" | "width"> & {
|
|
85
85
|
/** The column's id; for a typed row, one of its cells. */
|
|
86
86
|
id: GridColumnId<Row>;
|
|
87
|
+
/** CSS class tokens applied to the column header, data and footer cells. */
|
|
88
|
+
className?: string | null;
|
|
89
|
+
alignment?: "start" | "center" | "end" | null;
|
|
90
|
+
/** Ordered raw columns used when this column is sorted. */
|
|
91
|
+
orderData?: readonly string[];
|
|
92
|
+
orderSequence?: readonly ("asc" | "desc" | "none")[];
|
|
93
|
+
/** A sortComparators plugin hook. */
|
|
94
|
+
sortComparator?: string | null;
|
|
87
95
|
/** Supports query predicates and filter controls. Default true; does not hide values, supported read-only facets, or presentation rules. */
|
|
88
96
|
filterable?: boolean;
|
|
89
97
|
/** Supports grid exports. Default true. Default export selection omits false; explicit requests reject it. */
|
|
@@ -179,7 +187,7 @@ export interface GridPager {
|
|
|
179
187
|
/** Include the reporting entry point when this optional capability set is present. */
|
|
180
188
|
export interface GridReporting {
|
|
181
189
|
/** Fixed first ordering key. Group headings and collapse never change record paging/counts/exports. */
|
|
182
|
-
readonly grouping?: GridSort;
|
|
190
|
+
readonly grouping?: GridSort & { readonly headerTemplate?: string };
|
|
183
191
|
/** Initial runtime grouping levels, outermost first (at most four). Not combined with grouping. */
|
|
184
192
|
readonly groupBy?: readonly GridGroupLevel[];
|
|
185
193
|
/** Readers group by sortable columns from column menus, the group-by bar and dragged headers. Not combined with grouping. */
|
|
@@ -263,12 +271,15 @@ export type GridAction<Q extends AcceptedGridQuery = GridQuery> =
|
|
|
263
271
|
/** render fills container on the entry's first open (and again after a render that threw); close() closes the menu and
|
|
264
272
|
* focuses its button; signal aborts when the grid is destroyed. */
|
|
265
273
|
| { label: string; render: (container: HTMLElement, context: { close(): void; signal: AbortSignal }) => void; run?: never };
|
|
266
|
-
export type
|
|
274
|
+
export type GridBuiltinFilter = {
|
|
267
275
|
readonly column: string;
|
|
268
276
|
readonly operator: "eq" | "ne" | "contains" | "startsWith" | "in" | "gt" | "ge" | "lt" | "le";
|
|
269
277
|
readonly values: readonly Exclude<CellValue, null>[];
|
|
270
278
|
} | { readonly column: string; readonly operator: "isNull" | "isNotNull"; readonly values: readonly []; };
|
|
271
279
|
|
|
280
|
+
/** A registered custom operator uses one typed, non-null operand. */
|
|
281
|
+
export type GridFilter = GridBuiltinFilter | { readonly column: string; readonly operator: string & {}; readonly values: readonly Exclude<CellValue, null>[] };
|
|
282
|
+
|
|
272
283
|
/** A nonempty nested expression: at most eight levels, 64 groups and 64 total predicates including flat filters. */
|
|
273
284
|
export interface GridFilterGroup {
|
|
274
285
|
readonly operator: "and" | "or";
|
|
@@ -309,6 +320,10 @@ interface GridDefinition<Q extends AcceptedGridQuery = GridQuery, Row extends Gr
|
|
|
309
320
|
id: string;
|
|
310
321
|
label: string;
|
|
311
322
|
columns: GridColumn<Row>[];
|
|
323
|
+
/** First matching rule per setting; explicit column properties win. */
|
|
324
|
+
columnDefaults?: readonly GridColumnDefaults[];
|
|
325
|
+
preSort?: readonly GridSort[];
|
|
326
|
+
footers?: readonly GridFooter[];
|
|
312
327
|
/** Fixed CSS pixel height (20..64), or content measurement. Fixed is the default writer behavior. */
|
|
313
328
|
rowHeight?: number | "auto";
|
|
314
329
|
/** Graphite spacing; an explicit rowHeight remains authoritative. */
|
|
@@ -425,6 +440,8 @@ export type GridView<Row extends GridRow = GridRow> = InlineGridView<Row> | Comp
|
|
|
425
440
|
|
|
426
441
|
/** A complete requested window from one dataset revision, with full and matching counts. */
|
|
427
442
|
export interface GridPage<Row extends GridRow = GridRow> {
|
|
443
|
+
/** Host-computed values by footer row id, then aggregate id; tied to this accepted revision and window. */
|
|
444
|
+
readonly footerValues?: Readonly<Record<string, Readonly<Record<string, number | null>>>>;
|
|
428
445
|
protocol: "canopyx/2";
|
|
429
446
|
type: "gridPage";
|
|
430
447
|
view: string;
|
|
@@ -464,6 +481,12 @@ export interface GridSource<Row extends GridRow = GridRow> extends GridFacetSour
|
|
|
464
481
|
}
|
|
465
482
|
/** Built-in operations, or the name of a custom aggregate a plugin registers (inline data) or the host source computes. */
|
|
466
483
|
export type GridAggregateOperation = "count" | "sum" | "average" | "minimum" | "maximum" | "distinctCount" | (string & {});
|
|
484
|
+
/** Declarative defaults selected by *, #columnId, .classToken or index:N (zero based). */
|
|
485
|
+
export type GridColumnDefaults = Pick<GridColumn, "className" | "alignment" | "sortable" | "filterable" | "hidden" | "orderData" | "orderSequence" | "sortComparator"> & { readonly targets: readonly string[] };
|
|
486
|
+
export interface GridFooter {
|
|
487
|
+
readonly id: string; readonly label: string; readonly scope: "page" | "all";
|
|
488
|
+
readonly aggregates: readonly GridAggregate[];
|
|
489
|
+
}
|
|
467
490
|
export interface GridAggregate {
|
|
468
491
|
/** The label is shown beside the value in group headings and the query totals row. */
|
|
469
492
|
readonly id: string; readonly column: string; readonly label: string;
|
|
@@ -738,6 +761,8 @@ interface GridHostBehavior<Q extends AcceptedGridQuery = GridQuery, Row extends
|
|
|
738
761
|
recordSections?: Readonly<Record<string, RecordSectionRenderer>>;
|
|
739
762
|
/** Actions of the record actions menu, after the built-in ones. */
|
|
740
763
|
recordActions?: readonly RecordAction[];
|
|
764
|
+
/** Projects a bounded plain-text record title and optional subtitle, without changing record identity. */
|
|
765
|
+
recordHeading?: RecordPanelOptions["recordHeading"];
|
|
741
766
|
/** Open all in grid of a collection; return false (or cancel canopyx:openAll) to filter the target yourself. */
|
|
742
767
|
onOpenAll?: (event: RecordOpenAll) => boolean | void;
|
|
743
768
|
/** Print one record; return false (or cancel canopyx:recordPrint) to print the sheet yourself. */
|
package/JavaScript/live.d.ts
CHANGED
|
@@ -75,6 +75,8 @@ export interface GridLiveState {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
export interface GridPollOptions<Row extends GridRow = GridRow, Q extends AcceptedGridQuery = GridQuery> {
|
|
78
|
+
/** After a successful native refresh, including unchanged rows. Not called for cancelled or failed loads; useful for snapshot provenance beside the grid. */
|
|
79
|
+
onRefresh?: (result: GridLiveResult) => void;
|
|
78
80
|
/** 250..86400000; defaults to the live pollMs. */
|
|
79
81
|
intervalMs?: number;
|
|
80
82
|
/** Poll at once instead of after the first interval. */
|
|
@@ -506,6 +506,11 @@ const labels = Object.freeze({
|
|
|
506
506
|
calendarOccurrenceTitle: "Wiederkehrenden Termin ändern",
|
|
507
507
|
calendarOccurrenceReadOnly: "Dieser Teil der Serie kann nicht gespeichert werden, weil einige Werte schreibgeschützt sind.",
|
|
508
508
|
calendarThisEvent: "Nur dieser Termin",
|
|
509
|
+
calendarEditOccurrence: "Dieses Vorkommen bearbeiten",
|
|
510
|
+
calendarRemoveOccurrence: "Dieses Vorkommen entfernen",
|
|
511
|
+
calendarOccurrenceScope: "Nur {date} ändert sich; andere Termine von {title} bleiben unverändert.",
|
|
512
|
+
calendarSharedResources: "{count} {resources}",
|
|
513
|
+
calendarResourceWindow: "{resources} {start}–{end} von {total}",
|
|
509
514
|
calendarThisAndFollowing: "Dieser und alle folgenden Termine",
|
|
510
515
|
calendarAllEvents: "Alle Termine",
|
|
511
516
|
calendarSources: "Kalender",
|
|
@@ -506,6 +506,11 @@ const labels = Object.freeze({
|
|
|
506
506
|
calendarOccurrenceTitle: "Cambiar un evento periódico",
|
|
507
507
|
calendarOccurrenceReadOnly: "No se puede guardar esta parte de la serie porque algunos valores son de solo lectura.",
|
|
508
508
|
calendarThisEvent: "Este evento",
|
|
509
|
+
calendarEditOccurrence: "Editar esta ocurrencia",
|
|
510
|
+
calendarRemoveOccurrence: "Eliminar esta ocurrencia",
|
|
511
|
+
calendarOccurrenceScope: "Solo cambia {date}; las otras fechas de {title} se mantienen.",
|
|
512
|
+
calendarSharedResources: "{count} {resources}",
|
|
513
|
+
calendarResourceWindow: "{resources} {start}–{end} de {total}",
|
|
509
514
|
calendarThisAndFollowing: "Este evento y los siguientes",
|
|
510
515
|
calendarAllEvents: "Todos los eventos",
|
|
511
516
|
calendarSources: "Calendarios",
|
|
@@ -506,6 +506,11 @@ const labels = Object.freeze({
|
|
|
506
506
|
calendarOccurrenceTitle: "Modifier un événement récurrent",
|
|
507
507
|
calendarOccurrenceReadOnly: "Cette partie de la série ne peut pas être enregistrée, car certaines valeurs sont en lecture seule.",
|
|
508
508
|
calendarThisEvent: "Cet événement",
|
|
509
|
+
calendarEditOccurrence: "Modifier cette occurrence",
|
|
510
|
+
calendarRemoveOccurrence: "Supprimer cette occurrence",
|
|
511
|
+
calendarOccurrenceScope: "Seul le {date} change ; les autres dates de {title} restent inchangées.",
|
|
512
|
+
calendarSharedResources: "{count} {resources}",
|
|
513
|
+
calendarResourceWindow: "{resources} {start}–{end} sur {total}",
|
|
509
514
|
calendarThisAndFollowing: "Cet événement et les suivants",
|
|
510
515
|
calendarAllEvents: "Tous les événements",
|
|
511
516
|
calendarSources: "Calendriers",
|
|
@@ -506,6 +506,11 @@ const labels = Object.freeze({
|
|
|
506
506
|
calendarOccurrenceTitle: "Modifica un evento ricorrente",
|
|
507
507
|
calendarOccurrenceReadOnly: "Questa parte della serie non può essere salvata perché alcuni valori sono di sola lettura.",
|
|
508
508
|
calendarThisEvent: "Questo evento",
|
|
509
|
+
calendarEditOccurrence: "Modifica questa occorrenza",
|
|
510
|
+
calendarRemoveOccurrence: "Rimuovi questa occorrenza",
|
|
511
|
+
calendarOccurrenceScope: "Cambia solo {date}; le altre date di {title} restano invariate.",
|
|
512
|
+
calendarSharedResources: "{count} {resources}",
|
|
513
|
+
calendarResourceWindow: "{resources} {start}–{end} di {total}",
|
|
509
514
|
calendarThisAndFollowing: "Questo evento e i successivi",
|
|
510
515
|
calendarAllEvents: "Tutti gli eventi",
|
|
511
516
|
calendarSources: "Calendari",
|
|
@@ -506,6 +506,11 @@ const labels = Object.freeze({
|
|
|
506
506
|
calendarOccurrenceTitle: "Zmień wydarzenie cykliczne",
|
|
507
507
|
calendarOccurrenceReadOnly: "Nie można zapisać tej części serii, ponieważ niektóre wartości są tylko do odczytu.",
|
|
508
508
|
calendarThisEvent: "To wydarzenie",
|
|
509
|
+
calendarEditOccurrence: "Edytuj to wystąpienie",
|
|
510
|
+
calendarRemoveOccurrence: "Usuń to wystąpienie",
|
|
511
|
+
calendarOccurrenceScope: "Zmienia się tylko {date}; pozostałe daty wydarzenia {title} pozostają bez zmian.",
|
|
512
|
+
calendarSharedResources: "{count} {resources}",
|
|
513
|
+
calendarResourceWindow: "{resources} {start}–{end} z {total}",
|
|
509
514
|
calendarThisAndFollowing: "To i następne wydarzenia",
|
|
510
515
|
calendarAllEvents: "Wszystkie wydarzenia",
|
|
511
516
|
calendarSources: "Kalendarze",
|
package/JavaScript/plugins.d.ts
CHANGED
|
@@ -68,6 +68,10 @@ export type CanopyPluginEventHandler = (event: CustomEvent, context: CanopyPlugi
|
|
|
68
68
|
* grid with the plugins option. Every member except name is optional.
|
|
69
69
|
*/
|
|
70
70
|
export interface CanopyPlugin {
|
|
71
|
+
/** Inline predicate hooks over raw values; cannot replace built-in operators. */
|
|
72
|
+
readonly filterOperators?: Readonly<Record<string, (value: unknown, operands: readonly unknown[], context: { readonly column: string; readonly signal: AbortSignal }) => boolean>>;
|
|
73
|
+
/** Inline ascending comparator hooks over raw sort values; missing values stay last in either direction. */
|
|
74
|
+
readonly sortComparators?: Readonly<Record<string, (left: unknown, right: unknown, context: { readonly column: string; readonly signal: AbortSignal }) => number>>;
|
|
71
75
|
/** 1 to 32 lowercase ASCII letters, digits and hyphens, starting with a letter; unique on the page. */
|
|
72
76
|
readonly name: string;
|
|
73
77
|
/** Plugins that start first, and parts of the runtime (for example "export") that load before init. */
|
package/JavaScript/protocol.d.ts
CHANGED
|
@@ -264,7 +264,7 @@ export type LabelName =
|
|
|
264
264
|
/** The record panel (docs/record-panel.md). */
|
|
265
265
|
| "recordBack" | "recordBackTo" | "recordTrail" | "recordShowing" | "recordTabs" | "recordSections" | "recordOtherFields" | "recordShowEmpty" | "recordHideEmpty" | "recordActions" | "recordCopyValues" | "recordCopyJson" | "recordCopyLink" | "recordCopied" | "recordPrint" | "recordExportCsv" | "recordExportJson" | "recordOpenAll" | "recordLoadMore" | "recordCount" | "recordItems" | "recordMore" | "recordShowAll" | "recordRetry" | "recordLoadFailed" | "recordUnavailable" | "recordField" | "recordValue" | "recordSection" | "recordBefore" | "recordAfter" | "recordAdded" | "recordRemoved" | "recordChanged"
|
|
266
266
|
/** The calendar and resource timeline (the calendar and timeline parts of flat grids). */
|
|
267
|
-
| "calendarToday" | "calendarPrevious" | "calendarNext" | "calendarViews" | "calendarMonth" | "calendarWeek" | "calendarDay" | "calendarDays"
|
|
267
|
+
| "calendarEditOccurrence" | "calendarRemoveOccurrence" | "calendarOccurrenceScope" | "calendarSharedResources" | "calendarResourceWindow" | "calendarToday" | "calendarPrevious" | "calendarNext" | "calendarViews" | "calendarMonth" | "calendarWeek" | "calendarDay" | "calendarDays"
|
|
268
268
|
| "calendarAgenda" | "calendarYear" | "calendarTimeline" | "calendarGoTo" | "calendarAllDay" | "calendarMore" | "calendarMoreLabel" | "calendarDayEvents"
|
|
269
269
|
| "calendarNoEvents" | "calendarEvents" | "calendarShowing" | "calendarRepeats" | "calendarTruncated" | "calendarLoading" | "calendarLoadError" | "calendarNow"
|
|
270
270
|
| "calendarZoom" | "calendarZoomHour" | "calendarZoomDay" | "calendarZoomWeek" | "calendarZoomMonth" | "calendarZoomQuarter" | "calendarResources" | "calendarCapacity"
|
package/JavaScript/records.d.ts
CHANGED
|
@@ -110,11 +110,19 @@ export interface RecordSectionContext {
|
|
|
110
110
|
/** Draws a drawer section's content (a chart, for example) into element. */
|
|
111
111
|
export type RecordSectionRenderer = (record: Readonly<{ id: string; cells?: Readonly<Record<string, Cell>>; fields?: Readonly<Record<string, Cell>>; label?: string }>,
|
|
112
112
|
element: HTMLElement, context: RecordSectionContext) => void | PromiseLike<void>;
|
|
113
|
-
/**
|
|
113
|
+
/** A detached snapshot of the selected record and its loaded details. */
|
|
114
|
+
export interface RecordActionContext {
|
|
115
|
+
readonly record: Readonly<{ id: string; cells?: Readonly<Record<string, Cell>>; fields?: Readonly<Record<string, Cell>> }>;
|
|
116
|
+
readonly view: string; readonly api: unknown; readonly payload: GridRecord | null; readonly signal: AbortSignal;
|
|
117
|
+
}
|
|
118
|
+
/** An action of the record panel's actions menu. Hosts must enforce authorization again when executing it. */
|
|
114
119
|
export interface RecordAction {
|
|
120
|
+
/** Evaluated after each record paint, including loaded details. Hidden actions cannot run through a stale control. */
|
|
121
|
+
readonly visible?: boolean | ((context: RecordActionContext) => boolean);
|
|
122
|
+
/** Also renders this action as a visible footer button. Menu access is retained. */
|
|
123
|
+
readonly prominent?: boolean | ((context: RecordActionContext) => boolean);
|
|
115
124
|
readonly label: string;
|
|
116
|
-
run(context:
|
|
117
|
-
readonly payload: GridRecord | null; readonly signal: AbortSignal }): void | PromiseLike<void>;
|
|
125
|
+
run(context: RecordActionContext): void | PromiseLike<void>;
|
|
118
126
|
}
|
|
119
127
|
/** The canopyx:openAll event's detail (and onOpenAll's argument): cancel it to filter the target grid yourself. */
|
|
120
128
|
export interface RecordOpenAll {
|
|
@@ -122,9 +130,15 @@ export interface RecordOpenAll {
|
|
|
122
130
|
readonly filters: readonly { readonly column: string; readonly operator: string; readonly values: readonly CellValue[] }[] | null;
|
|
123
131
|
}
|
|
124
132
|
/** Options that open a record (openRecord). */
|
|
125
|
-
export interface OpenRecordOptions {
|
|
133
|
+
export interface OpenRecordOptions {
|
|
134
|
+
readonly returnFocus?: Element | null; readonly path?: readonly string[]; readonly tab?: string;
|
|
135
|
+
/** Read this record's details again after a host mutation, even when the grid's row/revision has not changed. */
|
|
136
|
+
readonly reload?: boolean;
|
|
137
|
+
}
|
|
126
138
|
/** Host options of the record panel, on grids and trees. */
|
|
127
139
|
export interface RecordPanelOptions {
|
|
140
|
+
/** Plain-text heading projection. The record is a detached read-only snapshot; title and subtitle are bounded. */
|
|
141
|
+
recordHeading?: (record: Readonly<{id:string; cells?:Readonly<Record<string,Cell>>; fields?:Readonly<Record<string,Cell>>}>) => {title:string;subtitle?:string};
|
|
128
142
|
/** Loads a record's details when its drawer opens; used whatever the declared source. */
|
|
129
143
|
loadRecord?: RecordLoader;
|
|
130
144
|
/** Section renderers by name, beside the plugins' drawerSections. */
|