@evotecit/canopyx 0.3.16 → 0.3.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CanopyX.Html/Assets/canopyx-board.css +50 -0
- package/CanopyX.Html/Assets/canopyx-board.js +39 -0
- package/CanopyX.Html/Assets/canopyx-buckets.js +15 -0
- package/CanopyX.Html/Assets/canopyx-calculations.css +7 -0
- package/CanopyX.Html/Assets/canopyx-calculations.js +52 -0
- package/CanopyX.Html/Assets/canopyx-calendar-edit.js +3 -3
- package/CanopyX.Html/Assets/canopyx-calendar.css +5 -24
- package/CanopyX.Html/Assets/canopyx-calendar.js +14 -19
- package/CanopyX.Html/Assets/canopyx-cell-range.js +16 -14
- package/CanopyX.Html/Assets/canopyx-changes.css +6 -24
- package/CanopyX.Html/Assets/canopyx-changes.js +18 -15
- package/CanopyX.Html/Assets/canopyx-compare.css +37 -0
- package/CanopyX.Html/Assets/canopyx-compare.js +12 -0
- package/CanopyX.Html/Assets/canopyx-data.js +3 -3
- package/CanopyX.Html/Assets/canopyx-editing.css +2 -2
- package/CanopyX.Html/Assets/canopyx-editing.js +2 -2
- package/CanopyX.Html/Assets/canopyx-enhance.js +4 -4
- package/CanopyX.Html/Assets/canopyx-export.js +54 -13
- package/CanopyX.Html/Assets/canopyx-facets.css +14 -5
- package/CanopyX.Html/Assets/canopyx-facets.js +19 -15
- package/CanopyX.Html/Assets/canopyx-filter-editor.css +71 -85
- package/CanopyX.Html/Assets/canopyx-filter-editor.js +20 -16
- package/CanopyX.Html/Assets/canopyx-flow-checks.css +1 -1
- package/CanopyX.Html/Assets/canopyx-flow-checks.js +1 -1
- package/CanopyX.Html/Assets/canopyx-flow-dialog.css +2 -2
- package/CanopyX.Html/Assets/canopyx-flow-dialog.js +1 -1
- package/CanopyX.Html/Assets/canopyx-flow-entry.css +136 -12
- package/CanopyX.Html/Assets/canopyx-flow-entry.js +2 -2
- package/CanopyX.Html/Assets/canopyx-flow-module.mjs +2 -2
- package/CanopyX.Html/Assets/canopyx-format-editor.js +2 -2
- package/CanopyX.Html/Assets/canopyx-formatting.js +10 -9
- package/CanopyX.Html/Assets/canopyx-grid-module.mjs +182 -128
- package/CanopyX.Html/Assets/canopyx-grid.css +228 -96
- package/CanopyX.Html/Assets/canopyx-grid.js +182 -128
- package/CanopyX.Html/Assets/canopyx-grouping.css +22 -15
- package/CanopyX.Html/Assets/canopyx-grouping.js +24 -17
- package/CanopyX.Html/Assets/canopyx-interactive.css +197 -74
- package/CanopyX.Html/Assets/canopyx-interactive.js +38 -45
- package/CanopyX.Html/Assets/canopyx-labels-de.js +177 -9
- package/CanopyX.Html/Assets/canopyx-labels-es.js +177 -9
- package/CanopyX.Html/Assets/canopyx-labels-fr.js +176 -8
- package/CanopyX.Html/Assets/canopyx-labels-it.js +176 -8
- package/CanopyX.Html/Assets/canopyx-labels-pl.js +176 -8
- package/CanopyX.Html/Assets/canopyx-layouts.css +48 -20
- package/CanopyX.Html/Assets/canopyx-layouts.js +36 -14
- package/CanopyX.Html/Assets/canopyx-link.js +2 -2
- package/CanopyX.Html/Assets/canopyx-live.css +1 -3
- package/CanopyX.Html/Assets/canopyx-live.js +3 -3
- package/CanopyX.Html/Assets/canopyx-matrix.css +1 -8
- package/CanopyX.Html/Assets/canopyx-matrix.js +11 -11
- package/CanopyX.Html/Assets/canopyx-module.mjs +38 -45
- package/CanopyX.Html/Assets/canopyx-office-export.js +2936 -0
- package/CanopyX.Html/Assets/canopyx-path.css +45 -0
- package/CanopyX.Html/Assets/canopyx-path.js +28 -0
- package/CanopyX.Html/Assets/canopyx-pivot.css +75 -0
- package/CanopyX.Html/Assets/canopyx-pivot.js +72 -0
- package/CanopyX.Html/Assets/canopyx-plan.css +56 -0
- package/CanopyX.Html/Assets/canopyx-plan.js +67 -0
- package/CanopyX.Html/Assets/canopyx-presenters.js +2 -2
- package/CanopyX.Html/Assets/canopyx-record-panel.css +8 -7
- package/CanopyX.Html/Assets/canopyx-record-panel.js +15 -14
- package/CanopyX.Html/Assets/canopyx-reporting-module.mjs +222 -161
- package/CanopyX.Html/Assets/canopyx-reporting.css +240 -107
- package/CanopyX.Html/Assets/canopyx-reporting.js +222 -161
- package/CanopyX.Html/Assets/canopyx-stack.css +35 -0
- package/CanopyX.Html/Assets/canopyx-stack.js +24 -0
- package/CanopyX.Html/Assets/canopyx-time-slider.css +18 -0
- package/CanopyX.Html/Assets/canopyx-time-slider.js +27 -0
- package/CanopyX.Html/Assets/canopyx-timeline.js +6 -5
- package/CanopyX.Html/Assets/canopyx-tree-tools.css +36 -35
- package/CanopyX.Html/Assets/canopyx-tree-tools.js +15 -12
- package/CanopyX.Html/Assets/canopyx-ui-menu.css +41 -0
- package/CanopyX.Html/Assets/canopyx-ui-menu.js +64 -0
- package/CanopyX.Html/Assets/canopyx-ui-navigation.css +73 -0
- package/CanopyX.Html/Assets/canopyx-ui-navigation.js +39 -0
- package/CanopyX.Html/Assets/canopyx-ui-overlays.css +79 -0
- package/CanopyX.Html/Assets/canopyx-ui-overlays.js +42 -0
- package/CanopyX.Html/Assets/canopyx-ui-picker.css +12 -0
- package/CanopyX.Html/Assets/canopyx-ui-picker.js +6 -0
- package/CanopyX.Html/Assets/canopyx-ui-stepper.css +174 -0
- package/CanopyX.Html/Assets/canopyx-ui-stepper.js +48 -0
- package/CanopyX.Html/Assets/canopyx-ui-tabs.css +153 -0
- package/CanopyX.Html/Assets/canopyx-ui-tabs.js +47 -0
- package/CanopyX.Html/Assets/canopyx-values.css +5 -0
- package/CanopyX.Html/Assets/canopyx-values.js +13 -0
- package/CanopyX.Html/Assets/canopyx-view-intents.css +12 -0
- package/CanopyX.Html/Assets/canopyx-view-intents.js +56 -0
- package/CanopyX.Html/Assets/canopyx.css +197 -71
- package/CanopyX.Html/Assets/canopyx.js +29 -19
- package/JavaScript/board.d.ts +30 -0
- package/JavaScript/changes.d.ts +4 -1
- package/JavaScript/facets.d.ts +5 -3
- package/JavaScript/grid.d.ts +150 -16
- package/JavaScript/hosts.d.ts +14 -1
- package/JavaScript/index.d.ts +4 -2
- package/JavaScript/locales/de.mjs +177 -9
- package/JavaScript/locales/es.mjs +177 -9
- package/JavaScript/locales/fr.mjs +176 -8
- package/JavaScript/locales/it.mjs +176 -8
- package/JavaScript/locales/pl.mjs +176 -8
- package/JavaScript/matrix.d.ts +4 -1
- package/JavaScript/path.d.ts +33 -0
- package/JavaScript/pivot.d.ts +135 -0
- package/JavaScript/plan.d.ts +23 -0
- package/JavaScript/protocol.d.ts +16 -3
- package/JavaScript/records.d.ts +2 -0
- package/JavaScript/stack.d.ts +28 -0
- package/JavaScript/time-slider.d.ts +58 -0
- package/JavaScript/ui.d.ts +261 -0
- package/JavaScript/view-intents.d.ts +45 -0
- package/README.md +22 -3
- package/ThirdParty/OfficeIMO/LICENSE +21 -0
- package/ThirdParty/OfficeIMO/README.md +13 -0
- package/package.json +76 -3
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
.cx-board-host > .cx-grid{display:none;}
|
|
2
|
+
.cx-board{color:var(--hfx-color-text,light-dark(#16181c,#f2f3f5));font:var(--hfx-weight-regular,400) var(--hfx-type-body-size,0.875rem) var(--hfx-font-sans,"Segoe UI Variable Text","Segoe UI",system-ui,-apple-system,"Helvetica Neue",Arial,sans-serif);min-width:0;min-height:0;flex:1 1 auto;display:flex;flex-direction:column;}
|
|
3
|
+
.cx-board-tools{display:flex;align-items:center;gap:calc(var(--hfx-space-1,0.25rem)*2.5);margin:var(--hfx-space-2,0.5rem) 0;}
|
|
4
|
+
.cx-board-tools label{font-weight:var(--hfx-weight-semibold,600);}
|
|
5
|
+
.cx-board select{max-width:100%;}
|
|
6
|
+
.cx-board-help{color:var(--hfx-color-text-muted,light-dark(#626770,#8f949d));font-size:var(--hfx-type-caption-size,0.75rem);margin:calc(var(--hfx-space-1,0.25rem)*2.5) 0;}
|
|
7
|
+
.cx-board-lanes{display:grid;flex:1 1 auto;min-height:0;grid-auto-flow:column;grid-auto-columns:minmax(calc(var(--hfx-space-1,0.25rem)*65),1fr);gap:calc(var(--hfx-space-1,0.25rem)*3.5);overflow-x:auto;padding-bottom:calc(var(--hfx-space-1,0.25rem)*2.5);}
|
|
8
|
+
.cx-board-lane{display:flex;flex-direction:column;min-width:0;border:var(--hfx-border-width,1px) solid var(--hfx-color-border,light-dark(#e2e4e7,#272a30));border-radius:var(--hfx-radius-control,var(--hfx-radius-md,6px));background:color-mix(in srgb,var(--hfx-color-text,light-dark(#16181c,#f2f3f5)) 3%,var(--hfx-color-surface,light-dark(#ffffff,#16181c)));overflow:hidden;}
|
|
9
|
+
.cx-board-heading{display:flex;align-items:center;justify-content:space-between;gap:var(--hfx-space-2,0.5rem);padding:var(--hfx-space-3,0.75rem);border-bottom:var(--hfx-border-width,1px) solid var(--hfx-color-border,light-dark(#e2e4e7,#272a30));}
|
|
10
|
+
.cx-board-heading h3{margin:0;font-size:var(--hfx-type-body-size,0.875rem);font-weight:var(--hfx-weight-semibold,600);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
|
|
11
|
+
.cx-board-count{font-size:var(--hfx-type-caption-size,0.75rem);font-variant-numeric:tabular-nums;color:var(--hfx-color-text-muted,light-dark(#626770,#8f949d));white-space:nowrap;}
|
|
12
|
+
.cx-board-full .cx-board-count{color:var(--hfx-color-status-warn-fg,light-dark(#8c5c05,#eeb640));font-weight:var(--hfx-weight-semibold,600);}
|
|
13
|
+
.cx-board-scroll{flex:1 1 auto;min-height:0;overflow:auto;overscroll-behavior:contain;outline-offset:calc(var(--hfx-space-1,0.25rem)*-0.5);}
|
|
14
|
+
.cx-board-canvas{position:relative;min-height:calc(var(--hfx-space-1,0.25rem)*16);}
|
|
15
|
+
.cx-board-card{position:absolute;left:var(--hfx-space-2,0.5rem);right:var(--hfx-space-2,0.5rem);box-sizing:border-box;height:auto;margin-bottom:var(--hfx-space-2,0.5rem);padding:var(--hfx-space-3,0.75rem);background:var(--hfx-color-surface,light-dark(#ffffff,#16181c));border:var(--hfx-border-width,1px) solid var(--hfx-color-border,light-dark(#e2e4e7,#272a30));border-radius:var(--hfx-radius-control,var(--hfx-radius-md,6px));display:flex;flex-direction:column;gap:var(--hfx-space-2,0.5rem);}
|
|
16
|
+
.cx-board-card:hover{border-color:var(--hfx-color-accent,light-dark(#11776f,#37c9b8));}
|
|
17
|
+
.cx-board-card:focus-visible{outline:var(--hfx-focus-width,2px) solid var(--hfx-color-focus-ring,light-dark(#02726a,#37c9b8));outline-offset:var(--hfx-focus-offset,2px);}
|
|
18
|
+
.cx-board-card[draggable=true]{cursor:grab;}
|
|
19
|
+
.cx-board .cx-board-title{display:flex;align-items:flex-start;text-align:start;width:100%;min-width:0;overflow:hidden;white-space:normal;min-block-size:calc(2 * var(--hfx-type-body-size,0.875rem) * var(--hfx-type-body-line,1.5));}
|
|
20
|
+
.cx-board-title > span{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden;}
|
|
21
|
+
.cx-board-fields{display:grid;grid-template-columns:minmax(calc(var(--hfx-space-1,0.25rem)*12),auto) minmax(0,1fr);gap:var(--hfx-space-1,0.25rem) var(--hfx-space-3,0.75rem);margin:0;font-size:var(--hfx-type-caption-size,0.75rem);}
|
|
22
|
+
.cx-board-fields dt{color:var(--hfx-color-text-muted,light-dark(#626770,#8f949d));white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
|
|
23
|
+
.cx-board-fields dd{margin:0;text-align:end;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
|
|
24
|
+
.cx-board-move{margin-top:auto;width:100%;font-size:var(--hfx-type-caption-size,0.75rem) !important;}
|
|
25
|
+
.cx-board-swimlane{position:absolute;margin:0;padding:var(--hfx-space-2,0.5rem) var(--hfx-space-3,0.75rem);box-sizing:border-box;height:calc(var(--hfx-space-1,0.25rem)*9);left:0;right:0;color:var(--hfx-color-text-muted,light-dark(#626770,#8f949d));font-size:var(--hfx-type-caption-size,0.75rem);font-weight:var(--hfx-weight-semibold,600);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
|
|
26
|
+
.cx-board-empty{color:var(--hfx-color-text-muted,light-dark(#626770,#8f949d));margin:calc(var(--hfx-space-1,0.25rem)*4.5) var(--hfx-space-3,0.75rem);font-size:var(--hfx-type-caption-size,0.75rem);}
|
|
27
|
+
.cx-board-drop{outline:var(--hfx-focus-width,2px) solid var(--hfx-color-accent,light-dark(#11776f,#37c9b8));outline-offset:calc(var(--hfx-focus-offset,2px)*-1);}
|
|
28
|
+
.cx-board-warning{padding:calc(var(--hfx-space-1,0.25rem)*2.5);border:var(--hfx-border-width,1px) solid var(--hfx-color-border,light-dark(#e2e4e7,#272a30));border-radius:var(--hfx-radius-control,var(--hfx-radius-md,6px));}
|
|
29
|
+
@media (min-width: 641px){.cx-board-tools{display:none;}}
|
|
30
|
+
@media (max-width: 640px){
|
|
31
|
+
.cx-board-lanes{display:block;overflow-x:hidden;}
|
|
32
|
+
.cx-board-lane{display:none;}
|
|
33
|
+
.cx-board-lane.cx-board-active{display:flex;height:100%;box-sizing:border-box;}
|
|
34
|
+
.cx-board-tools select{flex:1;min-width:0;}
|
|
35
|
+
.cx-board-help{line-height:var(--hfx-type-body-line,1.5);}
|
|
36
|
+
}
|
|
37
|
+
@media print{
|
|
38
|
+
.cx-board-tools,.cx-board-help,.cx-board-move{display:none;}
|
|
39
|
+
.cx-board-lanes{display:flex;flex-wrap:wrap;overflow:visible;}
|
|
40
|
+
.cx-board-lane{display:block !important;flex:1 1 calc(var(--hfx-space-1,0.25rem)*65);break-inside:avoid;}
|
|
41
|
+
.cx-board-scroll{height:auto;overflow:visible;flex:none;}
|
|
42
|
+
.cx-board-canvas{height:auto !important;}
|
|
43
|
+
.cx-board-card,.cx-board-swimlane{position:relative;top:auto !important;left:auto;right:auto;margin:var(--hfx-space-2,0.5rem);break-inside:avoid;}
|
|
44
|
+
}
|
|
45
|
+
.cx-board .cx-board-title{color:var(--hfx-color-text,light-dark(#16181c,#f2f3f5));font-weight:var(--hfx-weight-semibold,600);font-size:var(--hfx-type-body-size,0.875rem);line-height:var(--hfx-type-body-line,1.5);padding:0;border:0;border-radius:0;background:transparent;box-shadow:none;justify-content:flex-start;min-height:0;}
|
|
46
|
+
.cx-board .cx-board-title:hover{color:var(--hfx-color-text,light-dark(#16181c,#f2f3f5));background:transparent;text-decoration:underline;}
|
|
47
|
+
.cx-board .cx-board-title:focus-visible{outline:var(--hfx-focus-width,2px) solid var(--hfx-color-focus-ring,light-dark(#02726a,#37c9b8));outline-offset:var(--hfx-focus-offset,2px);}
|
|
48
|
+
.cx-board-tools{padding-inline:var(--hfx-space-3,0.75rem);}
|
|
49
|
+
.cx-board-help{position:absolute;inline-size:var(--hfx-border-width,1px);block-size:var(--hfx-border-width,1px);overflow:hidden;clip-path:inset(50%);white-space:nowrap;}
|
|
50
|
+
.cx-board .cx-board-title{height:auto;min-block-size:calc(2 * var(--hfx-type-body-size,0.875rem) * var(--hfx-type-body-line,1.5));}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
(function(global){"use strict";const installed=new WeakSet();const part={version:"31d8984cbdc39866",install(context){if(installed.has(context.DataGrid.prototype))return;const{DataGrid,h,setText,fill,cellValue,cellText,gridScalar,gridQueryRows,gridQuery,validateGridPage,validateGridCursorPage,numberFormat,PROTOCOL}=context;const BOARD_TEXT={boardLane:"Lane",boardUnassigned:"Unassigned",boardEmpty:"No records in this lane",boardWip:"{count} / {limit}",boardWipFull:"{lane} has reached its work limit ({limit}).",boardMove:"Move to lane",boardMoved:"{title} moved to {lane}.",boardRejected:"Move was not accepted.",boardPending:"Waiting for the host to accept the move…",boardPartial:"Showing the first {count} records. Narrow the filters to see the rest.",boardKeys:"Use Alt+Left or Alt+Right to move between lanes; Up and Down to browse cards."};const boardKey=(value,column)=>JSON.stringify(column?gridScalar(value,column):value??null);const boardText=(grid,row,id)=>cellText(row.cells[id],grid.columns.find(column=>column.id===id),grid.fmt);function boardScalar(value){return value==null||["string","number","boolean"].includes(typeof value)&&(typeof value!=="number"||Number.isFinite(value))}
|
|
2
|
+
function boardSettings(grid){const input=grid.view.board,known=id=>typeof id==="string"&&grid.columns.some(column=>column.id===id);if(!input||!known(input.column)||input.titleColumn!==undefined&&!known(input.titleColumn)||
|
|
3
|
+
input.swimlaneColumn!==undefined&&(!known(input.swimlaneColumn)||input.swimlaneColumn===input.column)||
|
|
4
|
+
input.fields!==undefined&&(!Array.isArray(input.fields)||input.fields.length>8||new Set(input.fields).size!==input.fields.length||input.fields.some(id=>!known(id)))||
|
|
5
|
+
input.editable!==undefined&&typeof input.editable!=="boolean"||grid.view.calendar||grid.cursor||grid.paged)
|
|
6
|
+
throw new Error("CanopyX: a board needs known columns and continuous offset navigation, without a calendar.");const seen=new Set(),column=grid.columns.find(column=>column.id===input.column);if(input.lanes!==undefined&&(!Array.isArray(input.lanes)||input.lanes.length>200||input.lanes.some(lane=>{if(!lane||!boardScalar(lane.value)||typeof lane.label!=="string"||!lane.label.trim()||
|
|
7
|
+
lane.wipLimit!==undefined&&(!Number.isInteger(lane.wipLimit)||lane.wipLimit<1||lane.wipLimit>100000))return true;const key=boardKey(lane.value,column);if(seen.has(key))return true;seen.add(key);return false})))throw new Error("CanopyX: board lanes need unique scalar values, labels and positive work limits.");if(input.editable&&(!column.editable||grid.view.rowIdentity==="ordinal"))
|
|
8
|
+
throw new Error("CanopyX: board moves need an editable lane column and stable record identities.");return{...input,titleColumn:input.titleColumn||grid.columns.find(column=>column.rowHeader)?.id||grid.columns.find(column=>!column.hidden).id}}
|
|
9
|
+
Object.assign(DataGrid.prototype,{startBoard(){if(this.board)return;const settings=boardSettings(this),labels={};for(const[key,text]of Object.entries(BOARD_TEXT))labels[key]=this.opts.labels?.[key]||this.view.labels?.[key]||text;const board=this.board={settings,labels,rows:[],lanes:[],pending:new Set(),targets:new Map(),epoch:0,version:0};this.setReadOnly=(...args)=>{const result=DataGrid.prototype.setReadOnly.apply(this,args);this.boardPaint();return result};this.host.classList.add("cx-board-host");this.grid.hidden=true;if(this.pager)this.pager.hidden=true;this.boardFrame=h("section","cx-board");this.boardFrame.setAttribute("aria-label",this.view.label);this.host.insertBefore(this.boardFrame,this.grid.nextSibling);this.host.addEventListener("canopyx:commit",()=>this.boardReload(),{signal:this.lifetime.signal});this.host.addEventListener("canopyx:rowsChanged",event=>{board.version++;board.epoch++;if((this.view.source.kind!=="inline"||this.opts.source)&&event.detail.source==="api"){const updated=new Set(event.detail.updated),held=new Map([...this.rowCache.values()].filter(row=>!row.status&&updated.has(row.key)).map(row=>[row.key,row.h]));this.boardSetRows(board.rows.map(row=>held.get(row.id)||row),board.total);this.boardFrame.setAttribute("aria-busy","false")}else void this.boardReload()},{signal:this.lifetime.signal});window.addEventListener("beforeprint",()=>{board.printing=true;this.boardPaint()},{signal:this.lifetime.signal});window.addEventListener("afterprint",()=>{board.printing=false;this.boardPaint()},{signal:this.lifetime.signal});this.lifetime.signal.addEventListener("abort",()=>{this.boardFrame.remove();this.host.classList.remove("cx-board-host")},{once:true})},async boardReload(){const board=this.board;if(!board||this.destroyed||!this.acceptedQuery)return;const epoch=++board.epoch,signal=this.dataLifetime.signal,query=this.acceptedQuery;this.boardFrame.setAttribute("aria-busy","true");try{let rows=[],total=0;if(this.view.source.kind==="inline"&&!this.opts.source){if(this.view.rowData)await this.source.decoded;rows=gridQueryRows(this.view,query,new Map(this.columns.map(column=>[column.id,column])));total=rows.length}else{while(rows.length<100000){const request=gridQuery(this.view,{...query,offset:rows.length,limit:Math.min(10000,100000-rows.length)});const page=validateGridPage(await this.requestPage(request,signal),this.view,request,this.snapshot);total=page.matched;rows.push(...page.items);if(rows.length>=total||!page.items.length)break}}
|
|
10
|
+
if(this.destroyed||signal.aborted||epoch!==board.epoch)return;this.boardSetRows(rows,total)}catch(error){if(!signal.aborted&&!this.destroyed&&epoch===board.epoch){this.setNotice(error.message,true);this.emit("error",{error})}}
|
|
11
|
+
finally{if(epoch===board.epoch)this.boardFrame.setAttribute("aria-busy","false")}},boardSetRows(rows,total){const board=this.board;board.rows=rows;board.total=total;board.partial=rows.length<total;const column=this.columns.find(column=>column.id===board.settings.column);const lanes=new Map((board.settings.lanes||[]).map(lane=>[boardKey(lane.value,column),{...lane,key:boardKey(lane.value,column),rows:[],count:0}]));for(const row of rows){const value=cellValue(row.cells[board.settings.column]);if(!boardScalar(value))throw new Error("CanopyX: a board lane cell must be scalar.");const key=boardKey(value,column);if(!lanes.has(key))lanes.set(key,{key,value:value??null,label:value==null?board.labels.boardUnassigned:boardText(this,row,board.settings.column),rows:[],count:0});lanes.get(key).rows.push(row)}
|
|
12
|
+
const countRows=this.view.source.kind==="inline"&&!this.opts.source?this.view.rows:rows;for(const row of countRows){const lane=lanes.get(boardKey(cellValue(row.cells[board.settings.column]),column));if(lane)lane.count++}
|
|
13
|
+
board.lanes=[...lanes.values()];this.boardPaint()}});const BOARD_QUERY=DataGrid.prototype.setQuery;DataGrid.prototype.setQuery=async function(...args){const result=await BOARD_QUERY.apply(this,args);if(this.board)await this.boardReload();return result};function boardMeasureTemplate(frame,board){const fields=board.settings.fields||board.grid.columns.filter(column=>!column.hidden&&![board.settings.column,board.settings.titleColumn,board.settings.swimlaneColumn].includes(column.id)).slice(0,2).map(column=>column.id);const{card}=boardCardTemplate.call(board.grid,{id:"measure"},"Measure",fields.slice(0,2).map(()=>({title:"M",text:"M"})));const group=h("h4","cx-board-swimlane");if(board.settings.editable)boardMoveTemplate("",[{key:"",label:"M"}],"",true,card);for(const probe of[card,group]){probe.style.visibility="hidden";probe.setAttribute("aria-hidden","true")}
|
|
14
|
+
frame.append(card,group);const cardHeight=card.getBoundingClientRect().height+Number.parseFloat(getComputedStyle(card).marginBottom);const groupHeight=group.getBoundingClientRect().height;card.remove();group.remove();return{cardHeight,groupHeight}}
|
|
15
|
+
function boardToolsTemplate(board){const toolbar=h("div","cx-board-tools"),label=h("label"),picker=h("select","cx-select cx-board-picker");label.htmlFor=this.id+"-board-lane";picker.id=label.htmlFor;setText(label,board.labels.boardLane);for(const lane of board.lanes){const option=h("option");option.value=lane.key;setText(option,lane.label+" ("+lane.rows.length+")");picker.appendChild(option)}
|
|
16
|
+
picker.value=board.lane||"";const help=h("p","cx-board-help");help.id=this.id+"-board-help";setText(help,board.labels.boardKeys);toolbar.append(label,picker);this.boardFrame.append(toolbar,help);if(board.partial){const warning=h("p","cx-board-warning");warning.setAttribute("role","status");setText(warning,fill(board.labels.boardPartial,{count:board.rows.length}));this.boardFrame.appendChild(warning)}
|
|
17
|
+
return picker}
|
|
18
|
+
function boardLaneTemplate(board,lane,lanes){const section=h("section","cx-board-lane"),header=h("header","cx-board-heading"),title=h("h3"),count=h("span","cx-board-count");section.dataset.lane=lane.key;title.id=this.id+"-lane-"+board.lanes.indexOf(lane);setText(title,lane.label);section.setAttribute("aria-labelledby",title.id);setText(count,lane.wipLimit?fill(board.labels.boardWip,{count:lane.count,limit:lane.wipLimit}):String(lane.rows.length));count.title=lane.wipLimit?fill(board.labels.boardWipFull,{lane:lane.label,limit:lane.wipLimit}):lane.label;section.classList.toggle("cx-board-full",!!lane.wipLimit&&lane.count>=lane.wipLimit);header.append(title,count);section.appendChild(header);const scroll=h("div","cx-board-scroll"),canvas=h("div","cx-board-canvas");scroll.dataset.lane=lane.key;scroll.tabIndex=0;scroll.setAttribute("aria-label",lane.label);scroll.appendChild(canvas);section.appendChild(scroll);lanes.appendChild(section);return{section,scroll,canvas}}
|
|
19
|
+
function boardCardTemplate(row,text,fields){const card=h("article","cx-board-card"),title=h("button","cx-btn cx-board-title");card.dataset.cxBoardRecord=row.id;card.tabIndex=0;card.setAttribute("aria-label",text);card.setAttribute("aria-describedby",this.id+"-board-help");title.type="button";const caption=h("span");setText(caption,text);title.appendChild(caption);title.title=text;card.appendChild(title);const details=h("dl","cx-board-fields");for(const field of fields){const key=h("dt"),value=h("dd"),text=field.text;setText(key,field.title);key.title=field.title;setText(value,text);value.title=text;details.append(key,value)}
|
|
20
|
+
card.appendChild(details);return{card,title}}
|
|
21
|
+
function boardMoveTemplate(label,options,value,disabled,card){const move=h("select","cx-select cx-board-move");move.setAttribute("aria-label",label);for(const target of options){const option=h("option");option.value=target.key;option.disabled=target.disabled;setText(option,target.label);move.appendChild(option)}
|
|
22
|
+
move.value=value;move.disabled=disabled;card.appendChild(move);return move}
|
|
23
|
+
function boardItems(board,lane){const group=board.settings.swimlaneColumn;if(!group)return lane.rows.map(row=>({row,height:board.cardHeight}));const groups=new Map();for(const row of lane.rows){const value=cellValue(row.cells[group]),key=boardKey(value,board.grid.columns.find(column=>column.id===group));if(!groups.has(key))groups.set(key,{label:value==null?board.labels.boardUnassigned:boardText(board.grid,row,group),rows:[]});groups.get(key).rows.push(row)}
|
|
24
|
+
return[...groups.values()].flatMap(item=>[{label:item.label,count:item.rows.length,height:board.groupHeight},...item.rows.map(row=>({row,height:board.cardHeight}))])}
|
|
25
|
+
Object.assign(DataGrid.prototype,{boardPaint(){const board=this.board,held=document.activeElement?.closest("[data-cx-board-record]")?.dataset.cxBoardRecord;board.grid=this;const positions=new Map([...this.boardFrame.querySelectorAll(".cx-board-scroll")].map(node=>[node.dataset.lane,node.scrollTop]));this.boardFrame.replaceChildren();Object.assign(board,boardMeasureTemplate(this.boardFrame,board));if(!board.lanes.some(lane=>lane.key===board.lane))board.lane=board.lanes[0]?.key;const picker=boardToolsTemplate.call(this,board);picker.addEventListener("change",()=>{board.lane=picker.value;this.boardSyncLane();this.stateChanged()});const lanes=h("div","cx-board-lanes");this.boardFrame.appendChild(lanes);for(const lane of board.lanes){const{section,scroll,canvas}=boardLaneTemplate.call(this,board,lane,lanes);const items=boardItems(board,lane);let top=0;for(const item of items){item.top=top;top +=item.height}
|
|
26
|
+
canvas.style.height=top+"px";const paint=()=>{const focus=document.activeElement?.closest("[data-cx-board-record]"),preserve=focus&&canvas.contains(focus)?focus.dataset.cxBoardRecord:null;const from=board.printing?0:Math.max(0,scroll.scrollTop-board.cardHeight),to=board.printing?Infinity:scroll.scrollTop +(scroll.clientHeight||440)+ board.cardHeight;let low=0,high=items.length;while(low<high){const at=(low+high)>>>1;if(items[at].top+items[at].height<from)low=at+1;else high=at}
|
|
27
|
+
const fragment=document.createDocumentFragment();for(let at=low;at<items.length&&items[at].top<to;at++){const item=items[at],node=item.row?this.boardCard(item.row,lane):h("h4","cx-board-swimlane");if(!item.row)setText(node,item.label+" · "+item.count);node.style.top=item.top+"px";fragment.appendChild(node)}
|
|
28
|
+
canvas.replaceChildren(fragment);if(preserve)[...canvas.querySelectorAll("[data-cx-board-record]")].find(node=>node.dataset.cxBoardRecord===preserve)?.focus({preventScroll:true})};scroll.addEventListener("scroll",paint,{passive:true});scroll.scrollTop=positions.get(lane.key)||0;lane.scroll=scroll;lane.items=items;lane.paint=paint;scroll.addEventListener("dragover",event=>{if(board.drag&&this.boardCanMove(board.drag,lane)){event.preventDefault();event.dataTransfer.dropEffect="move";section.classList.add("cx-board-drop")}});scroll.addEventListener("dragleave",()=>section.classList.remove("cx-board-drop"));scroll.addEventListener("drop",event=>{event.preventDefault();section.classList.remove("cx-board-drop");if(board.drag)this.boardMove(board.drag.id,lane.key);board.drag=null});if(!items.length){const empty=h("p","cx-board-empty");setText(empty,board.labels.boardEmpty);canvas.appendChild(empty)}
|
|
29
|
+
else paint()}
|
|
30
|
+
this.boardSyncLane();if(held)this.boardFocus(held)},boardSyncLane(){for(const lane of this.boardFrame.querySelectorAll(".cx-board-lane"))lane.classList.toggle("cx-board-active",lane.dataset.lane===this.board.lane)},boardFocus(id){const lane=this.board.lanes.find(item=>item.rows.some(row=>row.id===id));if(!lane)return;this.board.lane=lane.key;this.boardSyncLane();const picker=this.boardFrame.querySelector(".cx-board-picker");if(picker)picker.value=lane.key;const item=lane.items.find(item=>item.row?.id===id);lane.scroll.scrollTop=Math.max(0,item.top-8);lane.paint();[...lane.scroll.querySelectorAll("[data-cx-board-record]")].find(node=>node.dataset.cxBoardRecord===id)?.focus({preventScroll:true})},boardCard(row,lane){const board=this.board,settings=board.settings,text=boardText(this,row,settings.titleColumn);const fields=settings.fields||this.columns.filter(column=>!column.hidden&&![settings.column,settings.titleColumn,settings.swimlaneColumn].includes(column.id)).slice(0,2).map(column=>column.id);const values=fields.slice(0,2).map(id=>({title:this.columns.find(column=>column.id===id).title,text:boardText(this,row,id)}));const{card,title}=boardCardTemplate.call(this,row,text,values);title.addEventListener("click",()=>this.openRecord(row.id).catch(error=>this.emit("error",{error})));if(settings.editable){const options=board.lanes.map(target=>({key:target.key,label:target.label,disabled:target.key!==lane.key&&!this.boardCanMove(row,target)}));const disabled=board.pending.has(row.id)||this.editReadOnly||!!this.edit&&!this.canEditCell(row,settings.column);const move=boardMoveTemplate(board.labels.boardMove+": "+text,options,lane.key,disabled,card);move.addEventListener("change",()=>{const key=move.value;move.value=lane.key;this.boardMove(row.id,key)});card.draggable=!move.disabled;card.addEventListener("dragstart",event=>{board.drag=row;event.dataTransfer.effectAllowed="move";event.dataTransfer.setData("text/plain",row.id)});card.addEventListener("dragend",()=>{board.drag=null;for(const node of this.boardFrame.querySelectorAll(".cx-board-drop"))node.classList.remove("cx-board-drop")})}
|
|
31
|
+
card.addEventListener("keydown",event=>{if(event.target!==card)return;if(event.altKey&&["ArrowLeft","ArrowRight"].includes(event.key)){event.preventDefault();const target=board.lanes[board.lanes.indexOf(lane)+(event.key==="ArrowLeft"?-1:1)];if(target)this.boardMove(row.id,target.key)}else if(["ArrowUp","ArrowDown"].includes(event.key)){event.preventDefault();const target=lane.rows[lane.rows.indexOf(row)+(event.key==="ArrowUp"?-1:1)];if(target)this.boardFocus(target.id)}else if(event.key==="Enter"){event.preventDefault();this.openRecord(row.id).catch(error=>this.emit("error",{error}))}});return card}});Object.assign(DataGrid.prototype,{boardCanMove(row,lane){const board=this.board;return!!board.settings.editable&&!board.pending.has(row.id)&&!this.pendingQuery&&!this.editReadOnly&&(!this.edit||this.canEditCell(row,board.settings.column))&&
|
|
32
|
+
lane.key!==boardKey(cellValue(row.cells[board.settings.column]),this.columns.find(column=>column.id===board.settings.column))&&(!lane.wipLimit||
|
|
33
|
+
lane.count +[...board.targets.values()].filter(key=>key===lane.key).length<lane.wipLimit)},async boardMove(id,key){const board=this.board,row=board.rows.find(row=>row.id===id),lane=board.lanes.find(lane=>lane.key===key);if(!row||!lane)return false;if(!this.boardCanMove(row,lane)){if(lane.wipLimit&&lane.count>=lane.wipLimit)setText(this.live,fill(board.labels.boardWipFull,{lane:lane.label,limit:lane.wipLimit}));return false}
|
|
34
|
+
const epoch=this.queryEpoch,signal=this.dataLifetime.signal,revision=this.snapshot.revision,version=board.version;board.pending.add(id);board.targets.set(id,key);this.boardPaint();setText(this.live,board.labels.boardPending);try{await this.loadEditing();if(this.edit.changes.has(id)||!this.canEditCell(row,board.settings.column))return false;const proposal={protocol:PROTOCOL,type:"gridCommit",view:this.view.id,revision,rows:[{id,values:{[board.settings.column]:lane.value}}]};let response,answered=false;const detail={id,column:board.settings.column,previous:cellValue(row.cells[board.settings.column]),value:lane.value,proposal:JSON.parse(JSON.stringify(proposal)),respondWith:answer=>{if(answered)throw new Error("CanopyX: board move already answered.");answered=true;response=answer}};const permitted=this.host.dispatchEvent(new CustomEvent("canopyx:boardMove",{detail,cancelable:true}));if(typeof this.opts.onBoardMove==="function"){const result=this.opts.onBoardMove(detail);if(result!==undefined&&!answered){response=result;answered=true}}
|
|
35
|
+
const writer=typeof this.edit.options.commit==="function"||typeof this.source.commit==="function";if(!permitted||(!answered&&!writer))return false;if(answered&&await this.runGridHook(()=>Promise.resolve(response),signal)!==true)return false;if(this.destroyed||signal.aborted||epoch!==this.queryEpoch||revision!==this.snapshot.revision||version!==board.version||this.edit.changes.has(id))return false;const currentRow=board.rows.find(item=>item.id===id);if(!currentRow||!this.canEditCell(currentRow,board.settings.column))return false;const current=board.lanes.find(item=>item.key===key);const otherMoves=[...board.targets].filter(([record,target])=>record!==id&&target===key).length;if(!current||current.wipLimit&¤t.count+otherMoves>=current.wipLimit)return false;const record=JSON.parse(JSON.stringify(currentRow)),spec=this.edit.specs.get(board.settings.column);if(!this.editApply(id,spec,lane.value,"board",record))return false;const result=await this.commitChanges({ids:[id]});if(!result.ok){this.revertChanges([id]);return false}
|
|
36
|
+
await this.boardReload();this.boardFocus(id);setText(this.live,fill(board.labels.boardMoved,{title:boardText(this,row,board.settings.titleColumn),lane:lane.label}));return true}catch(error){if(!signal.aborted)this.emit("error",{error});return false}
|
|
37
|
+
finally{board.pending.delete(id);board.targets.delete(id);if(!this.destroyed){this.boardPaint();if(boardKey(cellValue(board.rows.find(row=>row.id===id)?.cells[board.settings.column]),this.columns.find(column=>column.id===board.settings.column))!==key)setText(this.live,board.labels.boardRejected)}}}});const BOARD_GET_STATE=DataGrid.prototype.getState,BOARD_READ_STATE=DataGrid.prototype.readGridState,BOARD_SET_STATE=DataGrid.prototype.setState;DataGrid.prototype.getState=function(){const state=BOARD_GET_STATE.call(this);if(this.board?.lane)state.board={lane:this.board.lane};return state};DataGrid.prototype.readGridState=function(input){const state=BOARD_READ_STATE.call(this,input);if(input.board!==undefined){if(!input.board||typeof input.board.lane!=="string"||input.board.lane.length>4096)throw new Error("CanopyX: invalid board state.");let value;try{value=JSON.parse(input.board.lane)}catch(_){throw new Error("CanopyX: invalid board lane.")}
|
|
38
|
+
if(!boardScalar(value))throw new Error("CanopyX: invalid board lane.");state.board={lane:input.board.lane}}
|
|
39
|
+
return state};DataGrid.prototype.setState=function(input,...args){const state=this.readGridState(input);if(this.board&&state.board)this.board.lane=state.board.lane;return BOARD_SET_STATE.call(this,state,...args)};installed.add(context.DataGrid.prototype)}};(global.CanopyXParts||=[]).push(["board",part])})(typeof window!=="undefined"?window:globalThis);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
(function(global){"use strict";const installed=new WeakSet();const part={version:"cc69c8336c15df83",install(context){if(installed.has(context.GRID_BUCKETS))return;const{GRID_BUCKETS}=context;const bucketClocks=new Map();function bucketClock(zone){let clock=bucketClocks.get(zone);if(!clock){clock=new Intl.DateTimeFormat("en-US-u-ca-gregory-nu-latn",{timeZone:zone,year:"numeric",month:"numeric",day:"numeric",hour:"numeric",hourCycle:"h23"});if(bucketClocks.size>=64)bucketClocks.delete(bucketClocks.keys().next().value);bucketClocks.set(zone,clock)}
|
|
2
|
+
return clock}
|
|
3
|
+
function bucketDate(year,month,day){const date=new Date(0);date.setUTCFullYear(year,month-1,day);date.setUTCHours(0,0,0,0);return date}
|
|
4
|
+
function bucketKey(spec,raw){if(raw===null||raw===undefined)return null;if(spec.kind==="width"||spec.kind==="edges"){if(typeof raw!=="number"||!Number.isFinite(raw))return null;if(spec.kind==="width"){const key=Math.floor((raw -(spec.origin??0))/ spec.width);
|
|
5
|
+
if(!Number.isSafeInteger(key))throw new Error("CanopyX: the bucket index exceeds the safe integer range.");return key}
|
|
6
|
+
let index=0;while(index<spec.edges.length&&raw>=spec.edges[index])index++;return index}
|
|
7
|
+
const instant=new Date(raw);if(!Number.isFinite(instant.getTime()))return null;const parts=Object.fromEntries(bucketClock(spec.timeZone||"UTC").formatToParts(instant).filter(part=>part.type!=="literal").map(part=>[part.type,Number(part.value)]));const ordinal=bucketDate(parts.year,parts.month,parts.day).getTime()/ 86400000 + 719162, first = spec.firstWeekday ?? 1;
|
|
8
|
+
switch(spec.kind){case "day":return ordinal;case "week":return Math.floor((ordinal -(first+6)%7)/ 7);
|
|
9
|
+
case "month":return(parts.year-1)*12+parts.month-1;case "quarter":return(parts.year-1)*4+Math.floor((parts.month-1)/ 3);
|
|
10
|
+
case "year":return parts.year;case "hour":return parts.hour;case "weekday":return(ordinal+8-first)%7;default:throw new Error("CanopyX: unknown bucket kind.")}}
|
|
11
|
+
function bucketLabel(spec,key,language){const number=new Intl.NumberFormat(language,{maximumFractionDigits:15}),first=spec.firstWeekday??1;if(spec.kind==="width")return "["+number.format((spec.origin??0)+ key*spec.width)+ ", "+number.format((spec.origin??0)+(key+1)*spec.width)+ ")";if(spec.kind==="edges")return key===0?"< "+number.format(spec.edges[0]):key===spec.edges.length?"≥ "+number.format(spec.edges[key-1]):"["+number.format(spec.edges[key-1])+ ", "+number.format(spec.edges[key])+ ")";if(spec.kind==="hour")return String(key).padStart(2,"0")+ ":00";if(spec.kind==="weekday")return new Intl.DateTimeFormat(language,{weekday:"long",timeZone:"UTC"}).format(bucketDate(2026,1,4 +(key+first)%7));if(spec.kind==="year")return String(key);if(spec.kind==="month")return String(Math.floor(key / 12) + 1).padStart(4, "0") + "-" + String(key % 12 + 1).padStart(2, "0");
|
|
12
|
+
if(spec.kind==="quarter")return(Math.floor(key / 4) + 1) + " Q" + (key % 4 + 1);
|
|
13
|
+
const ordinal=spec.kind==="week"?key*7 +(first+6)%7:key;const date=new Date((ordinal-719162)*86400000);if(spec.kind==="day")return date.toISOString().slice(0,10);const middle=new Date(date.getTime()+ 3*86400000),year=middle.getUTCFullYear(),january=bucketDate(year,1,4);const weekStart=january.getTime()-(january.getUTCDay()- first+7)%7*86400000;const week=Math.floor((date.getTime()- weekStart)/ (7 * 86400000)) + 1;
|
|
14
|
+
return String(year).padStart(4,"0")+ "-W"+String(week).padStart(2,"0")}
|
|
15
|
+
Object.assign(GRID_BUCKETS,{key:bucketKey,label:bucketLabel});installed.add(context.GRID_BUCKETS)}};(global.CanopyXParts||=[]).push(["buckets",part])})(typeof window!=="undefined"?window:globalThis);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
.cx-calculation-editor{display:grid;gap:var(--hfx-space-3,0.75rem);padding:0;}
|
|
2
|
+
.cx-calculation-editor label{display:grid;gap:var(--hfx-space-1,0.25rem);min-width:0;}
|
|
3
|
+
.cx-calculation-editor :is(.cx-input,.cx-textarea){width:100%;min-width:0;box-sizing:border-box;}
|
|
4
|
+
.cx-calculation-editor textarea{resize:vertical;font-family:var(--hfx-font-mono,"Cascadia Mono","Cascadia Code",Consolas,"SFMono-Regular",Menlo,monospace);}
|
|
5
|
+
.cx-calculation-editor p{margin:0;line-height:var(--hfx-type-caption-line-height,1.35);}
|
|
6
|
+
.cx-calculation-error{color:var(--hfx-color-status-bad-fg,light-dark(#b8292a,#f47171));}
|
|
7
|
+
@media print{.cx-calculation-editor{display:none;}}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
(function(global){"use strict";const installed=new WeakSet();const part={version:"f902dc5856fc7bdd",install(context){if(installed.has(context.GRID_CALCULATIONS))return;const{DataGrid,GRID_CALCULATIONS,requireIdentifier,cellValue,h,setText,fill,gridButton,gridQuery,gridQueryStart,inlineGridSource,rowDataSource,loadGridFilterEditor,gridFreeze,gridFitPrepare}=context;function calculationParse(expression){if(typeof expression!=="string"||!expression.trim()||expression.length>2048)throw new Error("CanopyX: calculation expression must contain 1 to 2048 characters.");let at=0,nodes=0,nesting=0;const dependencies=[],fail=()=>{throw new Error("CanopyX: invalid calculation at "+at+".")},space=()=>{while(/\s/.test(expression[at] || "") && at < expression.length) at++; },
|
|
2
|
+
make=(op,args=[],value)=>{const depth=1+Math.max(0,...args.map(node=>node.depth));if(++nodes>256||depth>32)fail();return{op,args,value,depth}},take=token=>{space();if(expression.startsWith(token,at)){at +=token.length;return true}return false};function primary(){space();if(++nesting>32)fail();try{if(take("(")){const node=comparison();if(!take(")"))fail();return node}
|
|
3
|
+
if(take("[")){const end=expression.indexOf("]",at);if(end<0)fail();const id=expression.slice(at,end);requireIdentifier(id,"calculation column");at=end+1;if(!dependencies.includes(id))dependencies.push(id);if(dependencies.length>64)fail();return make("column",[],id)}
|
|
4
|
+
if(expression[at]==='"'){const start=at++;let escaped=false;while(at<expression.length){const char=expression[at++];if(char==='"'&&!escaped){let value;try{value=JSON.parse(expression.slice(start,at))}catch(_){fail()}
|
|
5
|
+
return make("literal",[],value)}
|
|
6
|
+
escaped=char==="\\"&&!escaped}
|
|
7
|
+
fail()}
|
|
8
|
+
const number=/^(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/.exec(expression.slice(at));
|
|
9
|
+
if(number){at +=number[0].length;const value=Number(number[0]);if(!Number.isFinite(value))fail();return make("literal",[],value)}
|
|
10
|
+
const name=/^[a-zA-Z]+/.exec(expression.slice(at)); if (!name) fail();
|
|
11
|
+
at +=name[0].length;const upper=name[0].toUpperCase();if(["TRUE","FALSE","NULL"].includes(upper))return make("literal",[],upper==="NULL"?null:upper==="TRUE");const arity={IF:[3,3],COALESCE:[1,32],ROUND:[2,2],CONCAT:[1,32],DATEPART:[2,2],DATEDIFF:[3,3]}[upper];if(!arity||!take("("))fail();const args=[];if(!take(")")){do{if(args.length===32)fail();args.push(comparison())}while(take(","));if(!take(")"))fail()}
|
|
12
|
+
if(args.length<arity[0]||args.length>arity[1])fail();return make(upper,args)}finally{nesting--}}
|
|
13
|
+
function unary(){if(take("+"))return make("positive",[unaryBounded()]);if(take("-"))return make("negative",[unaryBounded()]);return primary()}
|
|
14
|
+
function unaryBounded(){if(++nesting>32)fail();try{return unary()}finally{nesting--}}
|
|
15
|
+
function product(){let node=unary();for(;;){space();const op=expression[at];if(!"*/%".includes(op||" "))return node;at++;node=make(op,[node,unary()])}}
|
|
16
|
+
function sum(){let node=product();for(;;){space();const op=expression[at];if(op!=="+"&&op!=="-")return node;at++;node=make(op,[node,product()])}}
|
|
17
|
+
function comparison(){let node=sum();for(;;){space();const op=/^(?:<=|>=|!=|<>|==|=|<|>)/.exec(expression.slice(at)); if (!op) return node;
|
|
18
|
+
at +=op[0].length;node=make(op[0],[node,sum()])}}
|
|
19
|
+
const root=comparison();space();if(at!==expression.length)fail();return Object.freeze({expression,dependencies:Object.freeze(dependencies),root})}
|
|
20
|
+
class CalculationFailure extends Error{}
|
|
21
|
+
function calculationDate(value){const failure=()=>{throw new CalculationFailure("date")};if(typeof value!=="string")return failure();const match=/^(\d{4})-(\d{2})-(\d{2})(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{1,7}))?)?(Z|[+-]\d{2}:\d{2}))?$/.exec(value);
|
|
22
|
+
if(!match)return failure();const[year,month,day,hour,minute,second]=match.slice(1,7).map(item=>Number(item||0)),calendar=new Date(0);calendar.setUTCFullYear(year,month-1,day);calendar.setUTCHours(hour,minute,second,0);if(year<1||calendar.getUTCFullYear()!==year||calendar.getUTCMonth()!==month-1||calendar.getUTCDate()!==day||hour>23||minute>59||second>59)return failure();const zone=match[8],offset=zone&&zone!=="Z"?Number(zone.slice(1,3))*60+Number(zone.slice(4)):0;if(offset>840||zone&&zone!=="Z"&&(Number(zone.slice(1,3))>14||Number(zone.slice(4))>59))return failure();const instant=calendar.getTime()+ Number((match[7]||"").padEnd(3,"0").slice(0,3))-(zone?.[0]==="-"?-offset:offset)*60000,result=new Date(instant);return result.getUTCFullYear()<1||result.getUTCFullYear()>9999?failure():result}
|
|
23
|
+
function calculationEvaluate(program,resolver){const failure=code=>{throw new CalculationFailure(code)},finite=value=>Number.isFinite(value)?value===0?0:value:failure("number-range"),number=value=>typeof value==="number"?finite(value):failure("type"),text=value=>{const result=value===null?"":String(value);return result.length<=4096?result:failure("text-limit")},scalar=value=>{if(value?.calculationError)failure(value.calculationError);if(value==null)return null;if(typeof value==="number")return finite(value);if(typeof value==="string")return text(value);if(typeof value==="boolean")return value;return failure("type")},date=calculationDate;function evaluate(node){const{op,args}=node;if(op==="literal")return node.value;if(op==="column")return scalar(resolver(node.value));if(op==="IF"){const condition=evaluate(args[0]);if(condition!==null&&typeof condition!=="boolean")failure("type");return evaluate(args[condition?1:2])}
|
|
24
|
+
if(op==="COALESCE"){for(const arg of args){const value=evaluate(arg);if(value!==null)return value}return null}
|
|
25
|
+
const values=args.map(evaluate),[a,b,c]=values;if(op==="CONCAT")return text(values.map(text).join(""));if(op==="="||op==="=="||op==="!="||op==="<>"){if(a!==null&&b!==null&&typeof a!==typeof b)failure("type");return op==="!="||op==="<>"?a!==b:a===b}
|
|
26
|
+
if(values.some(value=>value===null))return null;if(["<","<=",">",">="].includes(op)){if(typeof a!==typeof b)failure("type");return op==="<"?a<b:op==="<="?a<=b:op===">"?a>b:a>=b}
|
|
27
|
+
if(op==="DATEPART"||op==="DATEDIFF"){if(typeof a!=="string")failure("type");const unit=a.toLowerCase(),start=date(b);if(op==="DATEDIFF"){const units={day:86400000,hour:3600000,minute:60000,second:1000,millisecond:1};if(!Object.hasOwn(units,unit))return failure("date");return finite((date(c).getTime()- start.getTime())/ units[unit]);
|
|
28
|
+
}
|
|
29
|
+
switch(unit){case "year":return start.getUTCFullYear();case "quarter":return Math.floor(start.getUTCMonth()/ 3) + 1;
|
|
30
|
+
case "month":return start.getUTCMonth()+ 1;case "day":return start.getUTCDate();case "hour":return start.getUTCHours();case "minute":return start.getUTCMinutes();case "second":return start.getUTCSeconds();case "weekday":return(start.getUTCDay()+ 6)%7+1;default:return failure("date")}}
|
|
31
|
+
const x=number(a);if(op==="positive")return x;if(op==="negative")return finite(-x);const y=number(b);if(op==="ROUND"){if(!Number.isInteger(y)||y<-12||y>12)failure("type");const scale=Number("1e"+y),scaled=finite(x*scale);return finite(Math.round(scaled)/ scale);
|
|
32
|
+
}
|
|
33
|
+
if((op==="/"||op==="%")&&y===0)failure("divide-by-zero");return finite(op==="+"?x+y:op==="-"?x-y:op==="*"?x*y:op==="/"?x / y : x % y);
|
|
34
|
+
}
|
|
35
|
+
try{return{value:evaluate(program.root),error:null}}
|
|
36
|
+
catch(error){if(!(error instanceof CalculationFailure))throw error;return{value:null,error:error.message}}}
|
|
37
|
+
const calculationPlans=new WeakMap();const calculationRaw=(row,id)=>Object.hasOwn(row.cells,id)?cellValue(row.cells[id]):null;function calculationDefinitions(view){return view.columns.filter(column=>column.calculation!==undefined).map(column=>({id:column.id,title:column.title,kind:column.kind,expression:column.calculation}))}
|
|
38
|
+
function calculationPlan(columns){const known=new Map(columns.map(column=>[column.id,column])),programs=new Map(),ordered=[],visiting=new Set(),visited=new Set();for(const column of columns)if(column.calculation!==undefined){if(column.editable||programs.size>=32)throw new Error("CanopyX: at most 32 read-only calculated columns are supported.");const program=calculationParse(column.calculation);if(program.dependencies.some(id=>!known.has(id)))throw new Error("CanopyX: unknown calculation column reference.");programs.set(column.id,program)}
|
|
39
|
+
const visit=id=>{if(visited.has(id))return;if(visiting.has(id))throw new Error("CanopyX: calculated-column dependency cycle.");visiting.add(id);for(const dependency of programs.get(id).dependencies)if(programs.has(dependency))visit(dependency);visiting.delete(id);visited.add(id);ordered.push({column:known.get(id),program:programs.get(id)})};for(const id of programs.keys())visit(id);return{ordered,inputs:[...new Set([...programs.values()].flatMap(program=>program.dependencies).filter(id=>!programs.has(id)))],cache:new WeakMap(),key:JSON.stringify(columns.filter(column=>column.calculation!==undefined).map(column=>[column.id,column.kind,column.calculation])),revision:0}}
|
|
40
|
+
function calculationApply(view,rows=view.rows){if(view.source?.kind!=="inline"||!view.columns.some(column=>column.calculation!==undefined))return;let plan=calculationPlans.get(view);if(!plan){plan=calculationPlan(view.columns);calculationPlans.set(view,plan)}
|
|
41
|
+
for(const row of rows){const inputs=plan.inputs.map(id=>calculationRaw(row,id)),previous=plan.cache.get(row);if(previous&&inputs.every((value,index)=>Object.is(value,previous[index])))continue;const results=new Map();for(const{column,program}of plan.ordered){const result=calculationEvaluate(program,id=>results.has(id)?results.get(id):calculationRaw(row,id));if(!result.error&&result.value!==null){if(column.kind==="number")result.error=typeof result.value!=="number"?"type":Math.abs(result.value)>Number.MAX_SAFE_INTEGER?"number-range":null;else if(column.kind==="text"&&!["string","boolean"].includes(typeof result.value))result.error="type";else if(column.kind==="datetime"){try{result.value=calculationDate(result.value).toISOString().replace(/\.000Z$/, "Z"); }
|
|
42
|
+
catch(fault){if(!(fault instanceof CalculationFailure))throw fault;result.error=fault.message}}}
|
|
43
|
+
const error=result.error;results.set(column.id,error?{calculationError:error}:result.value);Object.defineProperty(row.cells,column.id,{value:error?{value:null,text:error==="divide-by-zero"?"#DIV/0":"#ERROR",tone:"danger",title:column.title+" ("+column.calculation+"): "+fill(view.labels?.gridCalculationError||DEFAULT_CALCULATION_ERROR,{error:error==="divide-by-zero"?view.labels?.gridCalculationDivideZero||"Division by zero":error})}:result.value,enumerable:true,configurable:true,writable:true})}
|
|
44
|
+
plan.cache.set(row,inputs)}}
|
|
45
|
+
const DEFAULT_CALCULATION_ERROR="Calculation error: {error}";function calculationColumns(grid,definitions){if(!Array.isArray(definitions)||definitions.length>32)throw new Error("CanopyX: invalid calculated columns.");const base=grid.calculationBaseColumns||grid.view.columns.filter(column=>column.calculation===undefined),seen=new Set(base.map(column=>column.id)),authored=grid.calculationAuthoredColumns||grid.view.columns.filter(column=>column.calculation!==undefined);const calculated=definitions.map(input=>{if(!input||typeof input!=="object"||Array.isArray(input)||Object.keys(input).some(key=>!["id","title","kind","expression"].includes(key)))throw new Error("CanopyX: invalid calculated column.");requireIdentifier(input.id,"calculated column ID");if(seen.has(input.id)||typeof input.title!=="string"||!input.title.trim()||input.title.length>256||!["text","number","datetime"].includes(input.kind))throw new Error("CanopyX: invalid calculated column identity or kind.");seen.add(input.id);const original=authored.find(column=>column.id===input.id);if(original&&original.kind!==input.kind)throw new Error("CanopyX: authored calculated columns retain their declared result kind.");return{...(original||{width:160,autoWidth:true,sortable:true,filterable:true,exportable:true}),id:input.id,title:input.title,kind:input.kind,calculation:input.expression,editable:false}});if(authored.some(column=>!calculated.some(item=>item.id===column.id)))throw new Error("CanopyX: authored calculated columns must remain declared.");const columns=[...base,...calculated];calculationPlan(columns);return columns}
|
|
46
|
+
function calculationProspective(grid,columns,action){const viewColumns=grid.view.columns,runtimeColumns=grid.columns;grid.view.columns=columns;grid.columns=columns;try{return action()}finally{grid.view.columns=viewColumns;grid.columns=runtimeColumns}}
|
|
47
|
+
function calculationInstall(grid,columns){const ids=new Set(columns.map(column=>column.id)),previous=new Map(grid.columns.map(column=>[column.id,column]));const oldPlan=calculationPlans.get(grid.view),plan=calculationPlan(columns);plan.revision=(oldPlan?.revision||0)+(oldPlan?.key===plan.key?0:1);for(const row of grid.view.rows||[])for(const column of grid.view.columns)if(column.calculation!==undefined&&!ids.has(column.id))delete row.cells[column.id];grid.view.columns=columns;grid.columns=columns.map(column=>({...column,...previous.get(column.id),id:column.id,title:column.title,kind:column.kind,calculation:column.calculation,autoWidth:previous.get(column.id)?.autoWidth??(column.autoWidth||column.width===undefined),render:previous.get(column.id)?.render||null}));gridFitPrepare(grid);calculationPlans.set(grid.view,plan);calculationApply(grid.view);if(grid.view.source.kind==="inline"){if(grid.view.rowData&&!grid.source.decoded&&!grid.acceptedQuery)grid.source=rowDataSource(grid);else grid.source=inlineGridSource(grid.view)}
|
|
48
|
+
grid.columnList=null;grid.columnFind=null}
|
|
49
|
+
GRID_CALCULATIONS.definitions=view=>gridFreeze(calculationDefinitions(view));GRID_CALCULATIONS.apply=calculationApply;GRID_CALCULATIONS.revision=view=>{const revision=calculationPlans.get(view)?.revision;return revision?"inline-calculation-"+revision:undefined};GRID_CALCULATIONS.prepare=grid=>{if(grid.calculationPrepared)return;if(grid.opts.source&&grid.view.source.kind==="inline")throw new Error("CanopyX: calculated inline columns require the built-in inline source.");grid.calculationBaseColumns=grid.view.columns.filter(column=>column.calculation===undefined);grid.calculationAuthoredColumns=grid.view.columns.filter(column=>column.calculation!==undefined);calculationPlans.set(grid.view,calculationPlan(grid.view.columns));calculationApply(grid.view);grid.calculationPrepared=true;grid.prepareState()};const CALCULATION_STATE={get:DataGrid.prototype.getState,read:DataGrid.prototype.readGridState,set:DataGrid.prototype.setState};const CALCULATION_EXPORT_ROWS=DataGrid.prototype.exportRows;DataGrid.prototype.exportRows=async function*(request,signal){const revision=GRID_CALCULATIONS.revision(this.view),changed=()=>{throw new Error("CanopyX: calculated columns changed during export; capture it again.")};if(revision&&request.revision!==revision)changed();for await(const record of CALCULATION_EXPORT_ROWS.call(this,request,signal)){if(GRID_CALCULATIONS.revision(this.view)!==revision)changed();yield record}};Object.assign(DataGrid.prototype,{getCalculatedColumns(){return GRID_CALCULATIONS.definitions(this.view)},getState(){const state=CALCULATION_STATE.get.call(this);if(this.view.calculatedColumnsEditable)state.calculatedColumns=calculationDefinitions(this.view);return state},readGridState(input){if(!this.view.calculatedColumnsEditable){if(input.calculatedColumns!==undefined)throw new Error("CanopyX: this view does not allow saved calculated columns.");return CALCULATION_STATE.read.call(this,input)}
|
|
50
|
+
const definitions=input.calculatedColumns||calculationDefinitions({columns:this.calculationAuthoredColumns||this.view.columns.filter(column=>column.calculation!==undefined)}),columns=calculationColumns(this,definitions),state=calculationProspective(this,columns,()=>CALCULATION_STATE.read.call(this,input));state.calculatedColumns=JSON.parse(JSON.stringify(definitions));return state},async setState(input){if(this.view.calculatedColumnsEditable){const state=this.readGridState(input),columns=calculationColumns(this,state.calculatedColumns);if(this.source.decoded)await this.source.decoded;calculationInstall(this,columns)}
|
|
51
|
+
return CALCULATION_STATE.set.call(this,input)},async setCalculatedColumns(definitions){if(!this.view.calculatedColumnsEditable||this.view.source.kind!=="inline")throw new Error("CanopyX: calculated-column editing is not enabled.");const columns=calculationColumns(this,definitions),query=calculationProspective(this,columns,()=>gridQuery(this.view,gridQueryStart(this.queryForChange(true))));if(this.source.decoded)await this.source.decoded;calculationInstall(this,columns);this.noteViewPreferenceIntent?.();await this.setQuery(query);this.stateChanged();this.emit("calculations",{columns:this.getCalculatedColumns()});return this.getCalculatedColumns()}});DataGrid.prototype.openCalculatedColumn=async function(anchor){if(!this.view.calculatedColumnsEditable||this.view.source.kind!=="inline")throw new Error("CanopyX: calculated-column editing is not enabled.");await loadGridFilterEditor();if(this.destroyed||this.pendingQuery)return;const form=h("form","cx-calculation-editor"),help=h("p"),error=h("p","cx-calculation-error"),id=h("input","cx-input"),title=h("input","cx-input"),kind=h("select","cx-input"),expression=h("textarea","cx-textarea");let ordinal=1;while(this.view.columns.some(column=>column.id==="calculated"+ordinal))ordinal++;id.value="calculated"+ordinal;id.maxLength=128;title.maxLength=256;expression.maxLength=2048;expression.rows=4;expression.spellcheck=false;const field=(label,control)=>{const row=h("label"),text=h("span");setText(text,label);row.append(text,control);form.append(row);control.required=true;return row};field(this.labels.gridCalculationTitle,title);field(this.labels.gridCalculationId,id);for(const[value,label]of[["number",this.labels.gridCalculationNumber],["text",this.labels.gridText],["datetime",this.labels.gridCalculationDate]]){const option=h("option");option.value=value;setText(option,label||value);kind.append(option)}
|
|
52
|
+
field(this.labels.gridCalculationResultType,kind);field(this.labels.gridCalculationExpression,expression);setText(help,this.labels.gridCalculationHelp);error.setAttribute("role","alert");error.hidden=true;const apply=gridButton(this.labels.gridApply,()=>{});apply.type="submit";apply.dataset.variant="primary";form.append(help,error,apply);form.addEventListener("submit",event=>{event.preventDefault();const definitions=[...calculationDefinitions(this.view),{id:id.value.trim(),title:title.value.trim(),kind:kind.value,expression:expression.value}];try{calculationColumns(this,definitions);this.reportingText?._cxOverlay.close();this.setCalculatedColumns(definitions).catch(fault=>this.emit("error",{error:fault}))}catch(_){error.hidden=false;setText(error,this.labels.gridCalculationInvalid)}});this.showReportingText({...this.view.columns[0],title:this.labels.gridCalculationAdd},"",anchor,undefined,false,form)};installed.add(context.GRID_CALCULATIONS)}};(global.CanopyXParts||=[]).push(["calculations",part])})(typeof window!=="undefined"?window:globalThis);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
(function(global){"use strict";const installed=new WeakSet();const part={version:"
|
|
1
|
+
(function(global){"use strict";const installed=new WeakSet();const part={version:"09747e191820d94c",requires:["calendar"],install(context){if(installed.has(context.DataGrid.prototype))return;const{DataGrid,h,setText,fill,cellValue,GRID_DRAG}=context;const{CAL_DAY,CAL_GUTTER,CAL_MINUTE,CAL_SLOT_PX,calDayText,calDow,calInAllDayRow,calIso,calOverlaps,calZone,calDayGrid}=DataGrid.prototype.calKit;Object.assign(DataGrid.prototype,{calCanEdit(event,resize){const edit=this.cal.editable;if(!edit||!event||event.background||event.base?.external||this.editReadOnly||!this.edit||this.destroyed)return false;if(resize?!edit.resize||event.marker:!edit.move)return false;const columns=[this.cal.start,resize||!event.marker?this.cal.end:null].filter(Boolean);const record=this.editRecord?.(event.key)||event.row;return columns.every(column=>column.editable&&this.canEditCell(record,column.id))&&(!event.recurring||!!this.cal.recurrence)},calCheck(event,proposal,plan){const edit=this.cal.editable,labels=this.calLabels;const resource=proposal.resource;if(!this.edit||this.destroyed)return labels.calendarUnavailable;const resize=proposal.end-proposal.start!==event.end-event.start;if(!this.calCanEdit(event,resize))return this.edit.labels.gridEditNotSaved;if(resource!==undefined&&resource!==event.resource&&(!edit.resources||!(this.cal.resource||this.cal.resourceIds)||
|
|
2
2
|
this.calResourceValues(event,resource).some(([id])=>!this.canEditCell(this.editRecord?.(event.key)||event.row,id))))return this.edit.labels.gridEditNotSaved;if(!this.calAllowsSpan(proposal.start,proposal.end,proposal.allDay))return labels.calendarOutsideRange;if(edit.allowed&&resource!=null){const allowed=String(cellValue(event.row.cells[edit.allowed.id])??"").split(/[\s,;]+/).filter(Boolean);
|
|
3
3
|
if(allowed.length&&!allowed.includes(resource))return fill(labels.calendarNotAllowed,{resource:this.calResourceName?this.calResourceName(resource):resource})}
|
|
4
4
|
const resources=this.calEventResources(event).map(id=>id===event.resource&&resource!==undefined?resource:id);if(resource!=null&&!resources.includes(resource))resources.push(resource);if(!resources.length)resources.push(null);const spanProblem=(resources.length?resources:[null]).map(resource=>this.calSpanProblem({...proposal,resource})).find(Boolean);if(spanProblem)return spanProblem;if(plan)return plan.problem||this.calOccurrenceProblem(event,proposal,plan);if(!edit.overlap){for(const other of this.calEvents){if(other.base.identity===event.base.identity||other.background||((this.cal.resource||this.cal.resourceIds)&&!resources.some(id=>this.calHasResource(other,id))))continue;if(other.start<proposal.end&&other.end>proposal.start||other.marker&&other.start>=proposal.start&&other.start<proposal.end)return fill(labels.calendarConflict,{title:other.title})}}
|
|
@@ -52,7 +52,7 @@ else{const count=sign*(vertical?7:1),length=end-start;start=days(start,count);en
|
|
|
52
52
|
moving.proposal={start,end,resource,allDay:event.allDay};moving.problem=this.calCheck(event,moving.proposal);this.calDrawGhost(moving);const named=resource!=null&&resource!==event.resource&&this.calResourceName?", "+this.calResourceName(resource):"";this.calAnnounce(this.calTimeText({...event,start,end,sd:this.calZone.day(start),ed:this.calZone.day(Math.max(start,end-1))})+ named +(moving.problem?", "+moving.problem:""));return true},calStopMoving(){const moving=this.calMoving;if(!moving)return;this.calMoving=null;moving.element.classList.remove("cx-cal-dragging");moving.element.removeEventListener("blur",moving.blur);this.calGhost?.remove();this.calGhost=null}});Object.assign(DataGrid.prototype,{calCreateProposal(cell,last){const cal=this.cal,zone=this.calZone,day=Number(cell.dataset.cxDay),resource=this.calCellResource(cell);if(cell.dataset.cxMinutes!==undefined){const from=Number(cell.dataset.cxMinutes),to=last?.dataset.cxMinutes!==undefined?Number(last.dataset.cxMinutes):from;const first=Math.min(from,to),end=last?Math.max(from,to)+ cal.slotMinutes:first+cal.create.minutes;return{start:zone.instant(day,first),end:zone.instant(day,Math.min(end,1440)),allDay:false,resource}}
|
|
53
53
|
const other=last?Number(last.dataset.cxDay):day,a=Math.min(day,other),b=Math.max(day,other);if(cal.create.allDay)return{start:a*CAL_DAY,end:(b+1)*CAL_DAY,allDay:true,resource};const at=cal.working?.start??540;return{start:zone.instant(a,at),end:zone.instant(b,at+cal.create.minutes),allDay:false,resource}},calCreateProblem(proposal){const labels=this.calLabels;if(!this.calAllowsSpan(proposal.start,proposal.end,proposal.allDay))return labels.calendarOutsideRange;for(const range of this.calRanges)if(range.kind==="unavailable"&&(range.resource==null||range.resource===proposal.resource)&&calOverlaps(proposal.start,proposal.end,range.start,range.end))return labels.calendarUnavailable;return null},async calCreate(proposal,anchor){if(!this.cal.create||this.editReadOnly)return false;const problem=this.calCreateProblem(proposal);if(problem){this.calAnnounce(problem);this.calNotice(problem,true,true);return false}
|
|
54
54
|
const detail={start:calIso(proposal.start),end:calIso(proposal.end),allDay:proposal.allDay,resource:proposal.resource};let go=this.emit("eventCreate",detail);if(go&&typeof this.opts.onCreate==="function"){try{go=this.opts.onCreate(gridFreezeCopy(detail))!==false}catch(error){this.emit("error",{error});go=false}}
|
|
55
|
-
if(!go)return false;this.calCreateForm(proposal,anchor);return true},calCreateForm(proposal,anchor){this.calCloseCreate(false);const labels=this.calLabels,panel=this.calCreating=h("form","cx-cal-create"),titleId=this.id+"-cal-new";const heading=h("h3","cx-cal-create-h"),when=h("p","cx-cal-det-when"),label=h("label","cx-cal-create-l"),input=h("input","cx-cal-create-input");const add=h("button","cx-btn cx-cal-create-add"),cancel=h("button","cx-btn ghost cx-cal-create-cancel"),actions=h("div","cx-cal-create-actions");panel.setAttribute("role","dialog");panel.setAttribute("aria-modal","false");panel.setAttribute("aria-labelledby",titleId);heading.id=titleId;setText(heading,labels.calendarNewEvent);setText(when,this.calTimeText({start:proposal.start,end:proposal.end,allDay:proposal.allDay,sd:proposal.allDay?Math.floor(proposal.start / CAL_DAY) : this.calZone.day(proposal.start),
|
|
55
|
+
if(!go)return false;this.calCreateForm(proposal,anchor);return true},calCreateForm(proposal,anchor){this.calCloseCreate(false);const labels=this.calLabels,panel=this.calCreating=h("form","cx-cal-create"),titleId=this.id+"-cal-new";const heading=h("h3","cx-cal-create-h"),when=h("p","cx-cal-det-when"),label=h("label","cx-cal-create-l"),input=h("input","cx-input cx-cal-create-input");const add=h("button","cx-btn cx-cal-create-add"),cancel=h("button","cx-btn ghost cx-cal-create-cancel"),actions=h("div","cx-cal-create-actions");add.dataset.variant="primary";panel.setAttribute("role","dialog");panel.setAttribute("aria-modal","false");panel.setAttribute("aria-labelledby",titleId);heading.id=titleId;setText(heading,labels.calendarNewEvent);setText(when,this.calTimeText({start:proposal.start,end:proposal.end,allDay:proposal.allDay,sd:proposal.allDay?Math.floor(proposal.start / CAL_DAY) : this.calZone.day(proposal.start),
|
|
56
56
|
ed:proposal.allDay?Math.floor((proposal.end-1)/ CAL_DAY) : this.calZone.day(Math.max(proposal.start, proposal.end - 1)), marker: false }));
|
|
57
57
|
input.id=titleId+"-title";input.type="text";input.maxLength=1000;input.autocomplete="off";label.htmlFor=input.id;setText(label,labels.calendarEventTitle);add.type="submit";setText(add,labels.calendarCreate);cancel.type="button";setText(cancel,labels.calendarCancel);actions.append(cancel,add);panel.append(heading,when,label,input,actions);panel._calAnchor=anchor;this.calPlace(panel,anchor||this.calBody);cancel.addEventListener("click",()=>this.calCloseCreate(true));panel.addEventListener("keydown",key=>{if(key.key==="Escape"){key.preventDefault();key.stopPropagation();this.calCloseCreate(true)}});panel.addEventListener("submit",submit=>{submit.preventDefault();const title=input.value.trim();if(!title){input.focus();return}
|
|
58
58
|
this.calCloseCreate(true);this.calInsertEvent(proposal,title).catch(error=>this.emit("error",{error}))});this.calCreateOutside=press=>{if(!panel.contains(press.target))this.calCloseCreate(false)};document.addEventListener("pointerdown",this.calCreateOutside,true);input.focus({preventScroll:true})},calCloseCreate(restore){const panel=this.calCreating;if(!panel)return;this.calCreating=null;document.removeEventListener("pointerdown",this.calCreateOutside,true);panel.remove();if(restore&&panel._calAnchor?.isConnected)panel._calAnchor.focus({preventScroll:true})},async calInsertEvent(proposal,title,extra){const cal=this.cal,cells={[cal.title.id]:title,[cal.start.id]:calIso(proposal.start),...extra};if(cal.end)cells[cal.end.id]=calIso(proposal.end);if(cal.allDay?.editable&&proposal.allDay)cells[cal.allDay.id]=true;if(cal.resource?.editable&&proposal.resource!=null)cells[cal.resource.id]=proposal.resource;else if(!cal.resource&&cal.resourceIds?.editable&&proposal.resource!=null)cells[cal.resourceIds.id]=JSON.stringify([proposal.resource]);await this.loadEditing();const result=await this.insertRow({cells});if(!result.applied)return false;const time=this.calFmt.shortDay(proposal.allDay?Math.floor(proposal.start / CAL_DAY) : this.calZone.day(proposal.start)) + (proposal.allDay ? "" : " " + this.calFmt.time(proposal.start));
|
|
@@ -115,7 +115,7 @@ const history=this.edit.undo.length;if(!await this.calCommit([event.key],event.t
|
|
|
115
115
|
return this.calCommit([inserted.id],event.title,true)},calInvalidInsert(result){const message=Object.values(result.errors||{})[0]||this.edit.labels.gridEditNotSaved;this.calNotice(message,true,true);this.calAnnounce(message);this.calReload({keep:true})}});Object.assign(DataGrid.prototype,{async editCalendarOccurrence(id){const event=this.calEventTarget(id)?._calEvent||this.calEvents.find(item=>item.id===id);if(!event?.recurring||!this.cal.series?.editable||!this.cal.recurrenceId?.editable||!this.calCanEdit(event,false))return false;await this.loadEditing();calWrapEditRecord();const decision=this.calEditSnapshot(event),current=this.calEditCurrent(event,decision);if(!current)return false;this.calOccurrenceForm(current,decision);return true},calOccurrenceForm(event,decision){this.calCloseOccurrence(false);this.calCloseDetails(false);this.calHideHover();const panel=this.calOccurrenceEditor=h("form","cx-cal-create cx-cal-occurrence-editor"),heading=h("h3","cx-cal-create-h");const labels=this.calLabels,titleId=this.id+"-cal-occurrence",fields=new Map();heading.id=titleId;setText(heading,labels.calendarEditOccurrence);panel.setAttribute("role","dialog");panel.setAttribute("aria-modal","false");panel.setAttribute("aria-labelledby",titleId);panel.appendChild(heading);const when=h("p","cx-cal-det-when");when.id=titleId+"-scope";setText(when,fill(labels.calendarOccurrenceScope,{date:this.calFmt.day({weekday:"short",day:"numeric",month:"short"},event.sd),title:event.title}));panel.setAttribute("aria-describedby",when.id);panel.appendChild(when);const resources=this.calEventResources(event);if(resources.length>1){const line=h("p","cx-cal-det-when");setText(line,resources.map(id=>this.calResourceName?.(id)||id).join(", "));panel.appendChild(line)}
|
|
116
116
|
const wall=time=>{if(event.allDay)return calDayText(Math.floor(time / CAL_DAY));
|
|
117
117
|
const minutes=this.calZone.parts(time).minutes,pad=value=>String(value).padStart(2,"0");return calDayText(this.calZone.day(time))+ "T"+pad(Math.floor(minutes / 60)) + ":" + pad(minutes % 60);
|
|
118
|
-
};const addField=(name,text,value,type,column)=>{const label=h("label","cx-cal-create-l"),input=h("input","cx-cal-create-input");input.id=titleId+"-"+name;input.name=name;input.type=type;input.value=value;input.required=true;input.disabled=!column?.editable||!this.canEditCell(event.row,column.id);if(type==="text")input.maxLength=1000;else if(type==="datetime-local")input.step="60";label.htmlFor=input.id;setText(label,text);fields.set(name,input);panel.append(label,input)};addField("title",labels.calendarEventTitle,event.title,"text",this.cal.title);addField("start",this.cal.start.title,wall(event.start),event.allDay?"date":"datetime-local",this.cal.start);if(this.cal.end)addField("end",this.cal.end.title,wall(event.end),event.allDay?"date":"datetime-local",this.cal.end);const original=new Map([...fields].map(([name,input])=>[name,input.value]));const message=h("p","cx-cal-occurrence-error");message.setAttribute("role","status");message.hidden=true;const actions=h("div","cx-cal-create-actions"),cancel=h("button","cx-btn ghost"),save=h("button","cx-btn cx-cal-create-add");cancel.type="button";save.type="submit";setText(cancel,labels.calendarCancel);setText(save,this.edit.labels.gridEditSave);cancel.addEventListener("click",()=>this.calCloseOccurrence(true));const remove=h("button","cx-btn ghost cx-cal-occurrence-remove");remove.type="button";setText(remove,labels.calendarRemoveOccurrence);remove.disabled=!this.cal.exceptions?.editable||!this.canEditCell(event.row,this.cal.exceptions.id);remove.addEventListener("click",async()=>{save.disabled=remove.disabled=true;try{const current=this.calEditCurrent(event,decision);if(!current){this.calRefuseDecision();this.calCloseOccurrence(true);return}
|
|
118
|
+
};const addField=(name,text,value,type,column)=>{const label=h("label","cx-cal-create-l"),input=h("input","cx-input cx-cal-create-input");input.id=titleId+"-"+name;input.name=name;input.type=type;input.value=value;input.required=true;input.disabled=!column?.editable||!this.canEditCell(event.row,column.id);if(type==="text")input.maxLength=1000;else if(type==="datetime-local")input.step="60";label.htmlFor=input.id;setText(label,text);fields.set(name,input);panel.append(label,input)};addField("title",labels.calendarEventTitle,event.title,"text",this.cal.title);addField("start",this.cal.start.title,wall(event.start),event.allDay?"date":"datetime-local",this.cal.start);if(this.cal.end)addField("end",this.cal.end.title,wall(event.end),event.allDay?"date":"datetime-local",this.cal.end);const original=new Map([...fields].map(([name,input])=>[name,input.value]));const message=h("p","cx-cal-occurrence-error");message.setAttribute("role","status");message.hidden=true;const actions=h("div","cx-cal-create-actions"),cancel=h("button","cx-btn ghost"),save=h("button","cx-btn cx-cal-create-add");save.dataset.variant="primary";cancel.type="button";save.type="submit";setText(cancel,labels.calendarCancel);setText(save,this.edit.labels.gridEditSave);cancel.addEventListener("click",()=>this.calCloseOccurrence(true));const remove=h("button","cx-btn ghost cx-cal-occurrence-remove");remove.dataset.variant="danger";remove.type="button";setText(remove,labels.calendarRemoveOccurrence);remove.disabled=!this.cal.exceptions?.editable||!this.canEditCell(event.row,this.cal.exceptions.id);remove.addEventListener("click",async()=>{save.disabled=remove.disabled=true;try{const current=this.calEditCurrent(event,decision);if(!current){this.calRefuseDecision();this.calCloseOccurrence(true);return}
|
|
119
119
|
if(await this.calRemoveOccurrence(current))this.calCloseOccurrence(true);else{setText(message,this.calNoticeElement.textContent||this.edit.labels.gridEditNotSaved);message.hidden=false}}catch(error){this.emit("error",{error});setText(message,this.edit.labels.gridEditNotSaved);message.hidden=false}
|
|
120
120
|
finally{save.disabled=remove.disabled=false}});actions.append(remove,cancel,save);panel.append(message,actions);panel._calAnchor=this.calEventTarget(event.id);this.calPlace(panel,panel._calAnchor||this.calBody);if(this.calPhone){panel.classList.add("cx-cal-occurrence-sheet");panel.style.removeProperty("width");panel.style.removeProperty("left");panel.style.removeProperty("top")}
|
|
121
121
|
else{const box=panel.getBoundingClientRect(),frame=this.calRoot.getBoundingClientRect();let top=box.top;for(const card of this.calBody.querySelectorAll(".cx-cal-ev")){const other=card.getBoundingClientRect();if(card.dataset.cxEvent!==event.id&&other.left<box.right&&other.right>box.left&&other.bottom>top&&other.top<top+box.height)
|
|
@@ -3,16 +3,9 @@
|
|
|
3
3
|
.cx-calendar .cx-cal{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;position:relative;background:var(--hfx-color-surface,light-dark(#ffffff,#16181c));}
|
|
4
4
|
.cx-cal-bar{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:var(--cx-size-8px) var(--cx-size-12px);padding:var(--cx-size-8px) var(--cx-size-12px);border-bottom:var(--cx-size-1px) solid var(--hfx-color-border,light-dark(#e2e4e7,#272a30));}
|
|
5
5
|
.cx-cal-nav{display:flex;align-items:center;gap:var(--cx-size-4px);}
|
|
6
|
-
.cx-chrome .cx-cal-nav > .cx-cal-gotoday[aria-disabled="true"]{opacity:.45;cursor:default;}
|
|
7
6
|
.cx-cal-title{margin:0;min-width:0;font-size:var(--cx-size-17px);font-weight:600;line-height:1.3;color:var(--hfx-color-text,light-dark(#16181c,#f2f3f5));white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
|
|
8
7
|
.cx-cal-ico{width:var(--cx-size-16px);height:var(--cx-size-16px);flex:none;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;}
|
|
9
|
-
.cx-cal-views{display:inline-flex;border:var(--cx-size-1px) solid var(--hfx-color-border-strong,light-dark(#cdd0d5,#363a42));border-radius:var(--hfx-radius-control,var(--hfx-radius-md,6px));overflow:hidden;}
|
|
10
|
-
.cx-chrome .cx-cal-views > .cx-cal-view{border:0;border-radius:0;height:calc(var(--hfx-control-height-md,calc(36px - var(--cx-compact,0) * 8px)) - var(--cx-size-2px));min-height:0;padding:0 var(--cx-size-12px);font-weight:500;}
|
|
11
|
-
.cx-chrome .cx-cal-views > .cx-cal-view + .cx-cal-view{border-inline-start:var(--cx-size-1px) solid var(--hfx-color-border,light-dark(#e2e4e7,#272a30));}
|
|
12
|
-
.cx-chrome .cx-cal-views > .cx-cal-view[aria-pressed="true"]{background:var(--hfx-color-accent-subtle,light-dark(#e7f1f1,#1b3435));color:var(--hfx-color-accent-text,light-dark(#02726a,#37c9b8));font-weight:600;}
|
|
13
|
-
.cx-cal-bar :is(.cx-cal-jump,.cx-cal-jumpbtn,.cx-cal-zoom,.cx-cal-view-select){height:var(--hfx-control-height-md,calc(36px - var(--cx-compact,0) * 8px));padding:0 var(--cx-size-8px);border:var(--cx-size-1px) solid var(--hfx-color-border-control,light-dark(#8a8f98,#6e737c));border-radius:var(--hfx-radius-control,var(--hfx-radius-md,6px));background:var(--hfx-color-surface,light-dark(#ffffff,#16181c));color:var(--hfx-color-text,light-dark(#16181c,#f2f3f5));font:inherit;font-size:var(--cx-size-13d5px);}
|
|
14
8
|
.cx-cal-bar .cx-cal-view-select{display:none;}
|
|
15
|
-
.cx-cal-bar :is(.cx-cal-jump,.cx-cal-jumpbtn,.cx-cal-zoom,.cx-cal-view-select):focus-visible{outline:var(--hfx-focus-width,2px) solid var(--hfx-color-focus-ring,light-dark(#02726a,#37c9b8));outline-offset:var(--hfx-focus-offset,2px);}
|
|
16
9
|
.cx-cal-notice{flex:none;padding:var(--cx-size-6px) var(--cx-size-12px);font-size:var(--cx-size-13px);color:var(--hfx-color-text-secondary,light-dark(#4d525b,#b0b4bc));background:var(--hfx-color-surface-sunken,light-dark(#f7f8f9,#111317));border-bottom:var(--cx-size-1px) solid var(--hfx-color-border,light-dark(#e2e4e7,#272a30));}
|
|
17
10
|
.cx-cal-notice.cx-cal-error{color:var(--hfx-color-status-bad-fg,light-dark(#b8292a,#f47171));}
|
|
18
11
|
.cx-cal-body{flex:1 1 auto;min-height:0;overflow:auto;position:relative;}
|
|
@@ -215,8 +208,7 @@ top:calc(var(--t) * var(--cx-cal-ppm) + var(--cx-size-1px));height:calc(var(--h)
|
|
|
215
208
|
.cx-cal-phone .cx-cal-day{display:flex;flex-direction:column;align-items:center;padding:var(--cx-size-2px) 0;cursor:pointer;}
|
|
216
209
|
.cx-cal-phone .cx-cal-month{min-height:0;}
|
|
217
210
|
.cx-cal-rpick{display:flex;align-items:center;gap:var(--cx-size-8px);height:var(--cx-size-44px);padding:0 var(--cx-size-8px);border-bottom:var(--cx-size-1px) solid var(--hfx-color-border,light-dark(#e2e4e7,#272a30));}
|
|
218
|
-
.cx-cal-rpick-select{flex:1 1 auto;
|
|
219
|
-
.cx-cal-rpick-select:focus-visible{outline:var(--hfx-focus-width,2px) solid var(--hfx-color-focus-ring,light-dark(#02726a,#37c9b8));outline-offset:var(--hfx-focus-offset,2px);}
|
|
211
|
+
.cx-cal-rpick-select{flex:1 1 auto;}
|
|
220
212
|
.cx-cal-rpick + .cx-cal-time{height:calc(100% - var(--cx-size-44px));}
|
|
221
213
|
.cx-cal-phone .cx-cal-weeks,.cx-cal-phone .cx-cal-week{flex:none;}
|
|
222
214
|
.cx-cal-phone .cx-cal-day[data-cx-listed] > .cx-cal-num{display:inline-grid;place-items:center;min-width:var(--cx-size-24px);height:var(--cx-size-24px);border-radius:var(--hfx-radius-control,var(--hfx-radius-md,6px));box-shadow:inset 0 0 0 var(--cx-size-2px) var(--hfx-color-accent,light-dark(#11776f,#37c9b8));}
|
|
@@ -253,35 +245,24 @@ top:calc(var(--t) * var(--cx-cal-ppm) + var(--cx-size-1px));height:calc(var(--h)
|
|
|
253
245
|
.cx-cal-dow,.cx-cal-ahead{position:static;}
|
|
254
246
|
}
|
|
255
247
|
.cx-cal-rtl .cx-cal-prev svg,.cx-cal-rtl .cx-cal-next svg{transform:scaleX(-1);}
|
|
256
|
-
.cx-cal-bar :is(.cx-cal-prev,.cx-cal-next)[aria-disabled="true"]{opacity:.45;cursor:default;}
|
|
257
248
|
:is(.cx-cal-create,.cx-cal-ask){position:absolute;z-index:22;display:flex;flex-direction:column;gap:var(--cx-size-6px);margin:0;padding:var(--cx-size-12px);background:var(--hfx-color-surface-raised,light-dark(#ffffff,#1e2126));color:var(--hfx-color-text,light-dark(#16181c,#f2f3f5));border:var(--cx-size-1px) solid var(--hfx-color-border,light-dark(#e2e4e7,#272a30));border-radius:var(--hfx-radius-overlay,var(--hfx-radius-lg,10px));box-shadow:var(--hfx-elevation-2,0 1px 2px rgba(22,24,28,.05),0 6px 18px -10px rgba(22,24,28,.18));font-size:var(--cx-size-13px);line-height:1.4;}
|
|
258
249
|
.cx-cal-create-h{margin:0;font-size:var(--cx-size-14px);font-weight:600;}
|
|
259
250
|
.cx-cal-create-l{margin-top:var(--cx-size-4px);font-weight:600;color:var(--hfx-color-text-secondary,light-dark(#4d525b,#b0b4bc));font-size:var(--cx-size-12px);}
|
|
260
|
-
.cx-cal-create-input{min-height:var(--cx-size-34px);padding:0 var(--cx-size-8px);font:inherit;color:inherit;background:var(--hfx-color-surface,light-dark(#ffffff,#16181c));border:var(--cx-size-1px) solid var(--hfx-color-border,light-dark(#e2e4e7,#272a30));border-radius:var(--hfx-radius-control,var(--hfx-radius-md,6px));}
|
|
261
|
-
.cx-cal-create .cx-btn.cx-cal-create-add{background:var(--hfx-color-accent,light-dark(#11776f,#37c9b8));border-color:var(--hfx-color-accent,light-dark(#11776f,#37c9b8));color:var(--hfx-color-accent-contrast,light-dark(#ffffff,#0c0d10));}
|
|
262
|
-
.cx-cal-create-input:focus-visible{outline:var(--hfx-focus-width,2px) solid var(--hfx-color-focus-ring,light-dark(#02726a,#37c9b8));outline-offset:var(--hfx-focus-offset,2px);}
|
|
263
251
|
.cx-cal-create .cx-cal-occurrence-remove{margin-inline-end:auto;color:var(--hfx-color-status-bad-fg,light-dark(#b8292a,#f47171));}
|
|
264
252
|
.cx-cal-occurrence-sheet{position:fixed;inset:auto 0 0;box-sizing:border-box;width:100%;--cx-cal-sheet-max-height:85dvh;max-height:var(--cx-cal-sheet-max-height);overflow:auto;border-radius:var(--hfx-radius-overlay,var(--hfx-radius-lg,10px)) var(--hfx-radius-overlay,var(--hfx-radius-lg,10px)) 0 0;padding:var(--cx-size-16px) var(--cx-size-16px) max(var(--cx-size-16px),env(safe-area-inset-bottom));--cx-cal-sheet-layer:30;z-index:var(--cx-cal-sheet-layer);}
|
|
265
253
|
:is(.cx-cal-create-actions,.cx-cal-ask-actions){display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--cx-size-6px);margin-top:var(--cx-size-6px);}
|
|
266
254
|
.cx-cal-ask-actions{flex-direction:column;align-items:stretch;}
|
|
267
255
|
.cx-cal-ask-actions .cx-btn{justify-content:flex-start;}
|
|
268
|
-
.cx-cal-menu{position:absolute;z-index:23;display:flex;flex-direction:column;min-width:var(--cx-size-180px);max-width:calc(100% - var(--cx-size-8px));padding:var(--cx-size-4px);background:var(--hfx-color-surface-raised,light-dark(#ffffff,#1e2126));color:var(--hfx-color-text,light-dark(#16181c,#f2f3f5));border:var(--cx-size-1px) solid var(--hfx-color-border,light-dark(#e2e4e7,#272a30));border-radius:var(--hfx-radius-overlay,var(--hfx-radius-lg,10px));box-shadow:var(--hfx-elevation-2,0 1px 2px rgba(22,24,28,.05),0 6px 18px -10px rgba(22,24,28,.18));font-size:var(--cx-size-13px);}
|
|
269
|
-
.cx-cal-menu-item{display:block;width:100%;min-height:var(--cx-size-34px);padding:0 var(--cx-size-10px);font:inherit;text-align:start;color:inherit;background:transparent;border:0;border-radius:calc(var(--hfx-radius-control,var(--hfx-radius-md,6px)) - var(--cx-size-2px));cursor:pointer;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
|
|
270
|
-
.cx-cal-menu-item:is(:hover,:focus-visible){background:var(--hfx-color-accent-subtle,light-dark(#e7f1f1,#1b3435));outline:none;}
|
|
271
|
-
.cx-cal-menu-item:focus-visible{box-shadow:inset 0 0 0 var(--cx-size-2px) var(--hfx-color-accent,light-dark(#11776f,#37c9b8));}
|
|
272
|
-
.cx-cal-menu-item[aria-disabled="true"]{color:var(--hfx-color-text-muted,light-dark(#626770,#8f949d));cursor:default;}
|
|
273
256
|
.cx-cal-legend{display:flex;flex-wrap:wrap;align-items:center;gap:var(--cx-size-6px);padding:0 var(--cx-size-12px) var(--cx-size-8px);}
|
|
274
|
-
.cx-cal-src{display:inline-flex;align-items:center;gap:var(--cx-size-6px);min-height:var(--cx-size-28px);padding:0 var(--cx-size-10px);font:inherit;font-size:var(--cx-size-12px);color:var(--hfx-color-text,light-dark(#16181c,#f2f3f5));background:var(--hfx-color-surface,light-dark(#ffffff,#16181c));border:var(--cx-size-1px) solid var(--hfx-color-border,light-dark(#e2e4e7,#272a30));border-radius:var(--hfx-radius-status,999px);cursor:pointer;}
|
|
275
|
-
.cx-cal-src:focus-visible{outline:var(--hfx-focus-width,2px) solid var(--hfx-color-focus-ring,light-dark(#02726a,#37c9b8));outline-offset:var(--hfx-focus-offset,2px);}
|
|
276
257
|
.cx-cal-src-swatch{width:var(--cx-size-10px);height:var(--cx-size-10px);border-radius:50%;background:var(--cx-ev,var(--hfx-color-accent,light-dark(#11776f,#37c9b8)));border:var(--cx-size-2px) solid var(--cx-ev,var(--hfx-color-accent,light-dark(#11776f,#37c9b8)));}
|
|
258
|
+
.cx-cal-src[aria-pressed="true"]{border-color:var(--hfx-color-border,light-dark(#e2e4e7,#272a30));background:var(--hfx-color-surface,light-dark(#ffffff,#16181c));color:var(--hfx-color-text,light-dark(#16181c,#f2f3f5));}
|
|
277
259
|
.cx-cal-src[aria-pressed="false"]{color:var(--hfx-color-text-secondary,light-dark(#4d525b,#b0b4bc));}
|
|
278
260
|
.cx-cal-src[aria-pressed="false"] span{text-decoration:line-through;}
|
|
279
261
|
.cx-cal-src[aria-pressed="false"] .cx-cal-src-swatch{background:transparent;}
|
|
280
|
-
@media (any-pointer:coarse){.cx-cal-src{min-height:var(--cx-size-44px);}
|
|
262
|
+
@media (any-pointer:coarse){.cx-cal-src{min-height:var(--cx-size-44px);}}
|
|
281
263
|
@media (forced-colors:active){
|
|
282
|
-
:is(.cx-cal-create,.cx-cal-ask
|
|
283
|
-
.cx-cal-menu-item:is(:hover,:focus-visible){forced-color-adjust:none;background:Highlight;color:HighlightText;}
|
|
264
|
+
:is(.cx-cal-create,.cx-cal-ask){border-color:CanvasText;}
|
|
284
265
|
.cx-cal-src-swatch{forced-color-adjust:none;border-color:CanvasText;background:CanvasText;}
|
|
285
266
|
.cx-cal-src[aria-pressed="false"] .cx-cal-src-swatch{background:Canvas;}
|
|
286
267
|
}
|
|
287
|
-
@media print{:is(.cx-cal-legend,.cx-cal-
|
|
268
|
+
@media print{:is(.cx-cal-legend,.cx-cal-create,.cx-cal-ask){display:none !important;}}
|