@aceshooting/lyra-ui 18.2.0 → 18.4.0

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.
@@ -129,6 +129,8 @@ export declare function normalizeBucketCount(bucketCount:number):number;
129
129
  export declare function resolveRgb(color:string,fallbackHex:string,ownerDocument?:Document):[number,number,number,number];export type LyraHeatmapCellClickDetail={date:string;value:number;}|{row:number;col:number;value:number;};export type LyraHeatmapMatrixGeometryChangeDetail={padLeft:number;padTop:number;cellSize:number;
130
130
  /** Custom painted bounds; omitted for the default one-pixel separators and square corners. */
131
131
  cellWidth?:number;cellHeight?:number;cellRadius?:number;};export interface LyraHeatmapEventMap{'lr-cell-click':CustomEvent<LyraHeatmapCellClickDetail>;'lr-matrix-geometry-change':CustomEvent<LyraHeatmapMatrixGeometryChangeDetail>;'lr-selection-change':CustomEvent<HeatmapSelectionChangeDetail>;}
132
+ /** The raster snapshot format returned by `LyraHeatmap.exportData()`. */
133
+ export type LyraHeatmapExportFormat='png';
132
134
  /**
133
135
  * `<lr-heatmap>` — a Canvas heatmap with a DPR-aware, resize-aware redraw
134
136
  * loop. Its discriminated `data` property selects one of two projections:
@@ -425,6 +427,14 @@ private resolvedRowLabelWidth;private get matrixPadLeft();
425
427
  * construction rather than by coincidence.
426
428
  */
427
429
  get matrixGeometry():Readonly<LyraHeatmapMatrixGeometryChangeDetail> |undefined;
430
+ /**
431
+ * Returns a PNG data URL for the most recently completed canvas paint. The snapshot includes the
432
+ * painted axes, cells, and canvas overlays, plus frozen label bands when `stickyLabels` is in
433
+ * use; DOM-only legend, tooltip, and accessible-cell overlays are intentionally omitted. An
434
+ * empty string means the component has not completed a paint yet, its canvas has no dimensions,
435
+ * it is waiting for deferred visibility, or the browser could not encode the snapshot.
436
+ */
437
+ exportData(format:LyraHeatmapExportFormat):string;
428
438
  /** The geometry the last `drawMatrix()` pass painted with, frozen and shared with the
429
439
  * `lr-matrix-geometry-change` detail. `undefined` until the first draw, which is what gates
430
440
  * `matrixGeometry` returning a real value only once there is a draw to describe. Also backs the
@@ -1,4 +1,4 @@
1
- var __decorate=function(decorators,target,key,desc){var c=arguments.length,r=c<3?target:desc===null?desc=Object.getOwnPropertyDescriptor(target,key):desc,d;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")r=Reflect.decorate(decorators,target,key,desc);else for(var i=decorators.length-1;i>=0;i--)(d=decorators[i])&&(r=(c<3?d(r):c>3?d(target,key,r):d(target,key))||r);return c>3&&r&&Object.defineProperty(target,key,r),r};import{html,nothing}from"lit";import{property,query,state}from"lit/decorators.js";import{styleMap}from"lit/directives/style-map.js";import{LyraElement}from"../../../internal/lyra-element.js";import{srOnly}from"../../../internal/a11y.js";import{finiteInteger,finiteNumber,finiteRange}from"../../../internal/numbers.js";import{getScratchCtx}from"../../../internal/canvas.js";import{resolveCssLength}from"../../../internal/css-length.js";import{ThemeWatcher}from"../../../internal/theme-watcher.js";import{activeElementIn}from"../../../internal/active-element.js";import{linearAlpha,linearBucket,midpointAlpha,midpointBucket,minMax,sqrtStep}from"./heatmap-scale.js";import{styles}from"./heatmap.styles.js";import{buildCalendarGrid,parseIsoDate,quartileBucket}from"./calendar-grid.js";import{getDateTimeFormat,getNumberFormat}from"../../../internal/intl-cache.js";import{sanitizeCssColor}from"../../../internal/safe-css.js";import{literalSetConverter}from"../../../internal/converters.js";import{devWarnOnce}from"../../../internal/dev-mode-attribute-warning.js";import{acquireAnnouncementSink}from"../../../internal/announcer.js";import{LYRA_DEFAULT_heatmapCalendarCellLabel,LYRA_DEFAULT_heatmapCalendarLabel,LYRA_DEFAULT_heatmapDecorationLimit,LYRA_DEFAULT_heatmapDefaultColLabel,LYRA_DEFAULT_heatmapDefaultRowLabel,LYRA_DEFAULT_heatmapMatrixCellLabel,LYRA_DEFAULT_heatmapMatrixLabel,LYRA_DEFAULT_heatmapNoDataValue,LYRA_DEFAULT_heatmapProjectionLimit,LYRA_DEFAULT_heatmapSelectedCellLabel,LYRA_DEFAULT_heatmapSelectedCount,LYRA_DEFAULT_heatmapValueLabel}from"../../../internal/default-strings.generated.js";const PAD_LEFT=60,PAD_TOP=20,ROW_LABEL_INSET=4,MAX_ROW_LABEL_FRACTION=.4,MAX_COL_LABEL_HEIGHT=240,COL_LABEL_INSET=6,labelExtentConverter={fromAttribute:value=>{if(value===null)return;const trimmed=value.trim();if(trimmed.toLowerCase()==="auto")return"auto";const parsed=Number.parseFloat(trimmed);return Number.isFinite(parsed)&&parsed>=0?parsed:void 0},toAttribute:value=>value===void 0?null:String(value)},STICKY_LABELS=literalSetConverter(["none","rows","cols","both"],"none"),FALLBACK_NO_DATA_FILL="rgba(128,128,128,0.25)",FALLBACK_STICKY_LABEL_BG="#ffffff",RAMP_STEPS=7,FALLBACK_SCALE_LO="#cde2fb",FALLBACK_SCALE_HI="#0969da",FALLBACK_LABEL_FONT="10px system-ui, sans-serif",CAL_PAD_LEFT=28,CAL_WEEKDAY_LABEL_INSET=2,CAL_LABEL_H=16,CAL_CELL=11,CAL_GAP=2,DEFAULT_MATRIX_CELL_SIZE=22,DEFAULT_ACCESSIBLE_TARGET_SIZE_PX=40,DEFAULT_BUCKET_COUNT=5,FIT_MIN_CELL=4,MAX_BUCKET_COUNT=256,MAX_HEATMAP_CELLS=1e4,MAX_HEATMAP_DECORATIONS=256,MAX_ACCESSIBLE_HEATMAP_CELLS=400,RING_LINE_WIDTH=2,FALLBACK_FOCUS_RING_COLOR="#0969da",FALLBACK_ANNOTATION_COLOR="#cf222e",FALLBACK_SELECTED_COLOR="#1a7f37",ARROW_KEYS=new Set(["ArrowUp","ArrowDown","ArrowLeft","ArrowRight"]),MS_PER_DAY=864e5;function isoDateAtOffset(firstWeekStart,dayOffset){return new Date(firstWeekStart.getTime()+dayOffset*MS_PER_DAY).toISOString().slice(0,10)}function legendStopsChanged(value,previous){if(Object.is(value,previous))return!1;if(!Array.isArray(value)||!Array.isArray(previous)||value.length!==previous.length)return!0;for(let index=0;index<value.length;index+=1){if(Object.hasOwn(value,index)!==Object.hasOwn(previous,index))return!0;const next=value[index],before=previous[index];if(!next||!before){if(!Object.is(next,before))return!0;continue}if(!Object.is(next.value,before.value)||!Object.is(next.color,before.color)||!Object.is(next.label,before.label)||!Object.is(next.partOfRamp,before.partOfRamp))return!0}return!1}const HEX_RE=/^([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i,RGB_RE=/^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([\d.]+))?\s*\)/i;function hexToRgb(hex){const clean=hex.trim().replace("#","");if(!HEX_RE.test(clean))return null;const hasAlpha=clean.length===4||clean.length===8,full=clean.length<=4?clean.split("").map(c=>c+c).join(""):clean,num=Number.parseInt(full,16);return hasAlpha?[num>>>24&255,num>>>16&255,num>>>8&255,(num&255)/255]:[num>>16&255,num>>8&255,num&255,1]}function parseRgbString(value){const match=RGB_RE.exec(value);if(!match)return null;const a=match[4]===void 0?1:Number(match[4]);return[Number(match[1]),Number(match[2]),Number(match[3]),a]}function resolveViaPixelReadback(ctx){try{ctx.clearRect(0,0,1,1),ctx.fillRect(0,0,1,1);const[r=0,g=0,b=0,a=0]=ctx.getImageData(0,0,1,1).data;return[r,g,b,a/255]}catch{return null}}function formatRgb([r,g,b,a]){const alpha=Math.min(1,Math.max(0,a));return alpha>=1?`rgb(${r}, ${g}, ${b})`:`rgba(${r}, ${g}, ${b}, ${Math.round(alpha*1e3)/1e3})`}function warnInvalidColor(color){devWarnOnce(`heatmap-invalid-color:${color}`,`<lr-heatmap> could not parse "${color}" (set via --lr-heatmap-scale-lo/-hi) as a CSS color; falling back to the default ramp endpoint.`)}let warnedNoCanvasContext=!1;function warnNoCanvasContext(){warnedNoCanvasContext||(warnedNoCanvasContext=!0,console.warn("<lr-heatmap>: no 2D canvas context is available in this environment; color resolution for non-hex/non-rgb values (e.g. oklch(), color(srgb ...), named colors) will fall back to the given default instead of resolving the requested color."))}function normalizeBucketCount(bucketCount){return finiteInteger(bucketCount,DEFAULT_BUCKET_COUNT,2,MAX_BUCKET_COUNT)}const optionalCellSizeConverter={fromAttribute(value){if(value===null||value.trim()==="")return;const parsed=Number(value);return Number.isFinite(parsed)?parsed:void 0}},DEFAULT_MATRIX_DATA=Object.freeze({kind:"matrix",rowLabels:Object.freeze([]),colLabels:Object.freeze([]),values:Object.freeze([])});function normalizeCellSizeClamp(value){if(!(value==null||!Number.isFinite(value)))return finiteRange(value,FIT_MIN_CELL,FIT_MIN_CELL)}const bucketCountConverter={fromAttribute(value){return value===null?DEFAULT_BUCKET_COUNT:normalizeBucketCount(Number(value))}};function resolveRgb(color,fallbackHex,ownerDocument){const fallback=hexToRgb(fallbackHex)??[0,0,0,1],direct=hexToRgb(color);if(direct)return direct;const ctx=getScratchCtx(ownerDocument);if(!ctx)return warnNoCanvasContext(),fallback;const sentinel="rgb(1, 2, 3)";ctx.fillStyle=sentinel;const sentinelNormalized=ctx.fillStyle;if(ctx.fillStyle=color,ctx.fillStyle===sentinelNormalized&&color.trim()!==sentinel)return warnInvalidColor(color),fallback;const normalized=ctx.fillStyle;return hexToRgb(normalized)??parseRgbString(normalized)??resolveViaPixelReadback(ctx)??fallback}function mixRgb(from,to,t){const clamped=Math.min(1,Math.max(0,t)),r=Math.round(from[0]+(to[0]-from[0])*clamped),g=Math.round(from[1]+(to[1]-from[1])*clamped),b=Math.round(from[2]+(to[2]-from[2])*clamped),a=from[3]+(to[3]-from[3])*clamped;return formatRgb([r,g,b,a])}class LyraHeatmap extends LyraElement{static{this.defaultStrings={...super.defaultStrings,heatmapCalendarCellLabel:LYRA_DEFAULT_heatmapCalendarCellLabel,heatmapCalendarLabel:LYRA_DEFAULT_heatmapCalendarLabel,heatmapDecorationLimit:LYRA_DEFAULT_heatmapDecorationLimit,heatmapDefaultColLabel:LYRA_DEFAULT_heatmapDefaultColLabel,heatmapDefaultRowLabel:LYRA_DEFAULT_heatmapDefaultRowLabel,heatmapMatrixCellLabel:LYRA_DEFAULT_heatmapMatrixCellLabel,heatmapMatrixLabel:LYRA_DEFAULT_heatmapMatrixLabel,heatmapNoDataValue:LYRA_DEFAULT_heatmapNoDataValue,heatmapProjectionLimit:LYRA_DEFAULT_heatmapProjectionLimit,heatmapSelectedCellLabel:LYRA_DEFAULT_heatmapSelectedCellLabel,heatmapSelectedCount:LYRA_DEFAULT_heatmapSelectedCount,heatmapValueLabel:LYRA_DEFAULT_heatmapValueLabel}}static{this.immutableEventDetails=Object.freeze(["lr-selection-change"])}static{this.ownedCollectionProperties=Object.freeze(["data","annotations","legendStops","colorSteps","selectedCells"])}static{this.identityCollectionObjectProperties=Object.freeze(["data"])}static{this.styles=[LyraElement.styles,styles,srOnly]}static get observedAttributes(){return[...new Set([...super.observedAttributes,"role"])]}get effectiveMode(){return this.data.kind}get stickyLabels(){return this._stickyLabels}set stickyLabels(next){const normalized=STICKY_LABELS.normalizeReflected(this,"sticky-labels",next),old=this._stickyLabels;old!==normalized&&(this._stickyLabels=normalized,this.requestUpdate("stickyLabels",old))}get effectiveStickyLabels(){return this.effectiveMode==="matrix"?this._stickyLabels:"none"}get freezesRowLabels(){const sticky=this.effectiveStickyLabels;return sticky==="rows"||sticky==="both"}get freezesColLabels(){const sticky=this.effectiveStickyLabels;return sticky==="cols"||sticky==="both"}get effectiveColLabelRotation(){if(typeof this.colLabelRotation!="number")return 0;const degrees=finiteNumber(this.colLabelRotation,0);return Math.min(90,Math.max(0,degrees))}get matrixPadLeft(){if(this.rowLabelWidth==="auto")return this.resolvedRowLabelWidth;if(typeof this.rowLabelWidth!="number")return PAD_LEFT;const resolved=finiteNumber(this.rowLabelWidth,PAD_LEFT);return resolved>=0?resolved:PAD_LEFT}get matrixGeometry(){if(this.effectiveMode==="matrix")return this.lastPaintedMatrixGeometry}get matrixPadTop(){if(this.colLabelHeight==="auto")return this.resolvedColLabelHeight;if(typeof this.colLabelHeight!="number")return PAD_TOP;const resolved=finiteNumber(this.colLabelHeight,PAD_TOP);return resolved>=0?resolved:PAD_TOP}measureColLabelHeight(cs){const labels=this.matrixColLabels;if(labels.length===0)return PAD_TOP;const ctx=getScratchCtx(this.ownerDocument);if(!ctx)return PAD_TOP;ctx.font=this.labelFont(cs);let widest=0;const interval=finiteInteger(this.colLabelInterval,1,1);for(let index=0;index<labels.length;index+=interval)widest=Math.max(widest,ctx.measureText(labels[index]).width);const radians=this.effectiveColLabelRotation*Math.PI/180,projected=widest*Math.sin(radians);return Math.max(PAD_TOP,Math.min(Math.ceil(projected)+COL_LABEL_INSET,MAX_COL_LABEL_HEIGHT))}measureRowLabelWidth(cs){const labels=this.matrixRowLabels;if(labels.length===0)return PAD_LEFT;const ctx=getScratchCtx(this.ownerDocument);if(!ctx)return PAD_LEFT;ctx.font=this.labelFont(cs);let widest=0;for(const label of labels)widest=Math.max(widest,ctx.measureText(label).width);const hostWidth=this.clientWidth||0,cap=hostWidth>0?hostWidth*MAX_ROW_LABEL_FRACTION:Number.POSITIVE_INFINITY;return Math.min(Math.max(PAD_LEFT,Math.ceil(widest)+ROW_LABEL_INSET*2),cap)}ellipsize(ctx,label,maxWidth){if(maxWidth<=0)return"";if(ctx.measureText(label).width<=maxWidth)return label;const characters=[...label];let kept=characters.length-1;for(;kept>0;){const candidate=`${characters.slice(0,kept).join("")}…`;if(ctx.measureText(candidate).width<=maxWidth)return candidate;kept-=1}return ctx.measureText("…").width<=maxWidth?"…":""}get calendarPadLeft(){const requested=this.calendarWeekdayLabelWidth;return requested==="auto"?this.resolvedCalendarWeekdayLabelWidth:requested??CAL_PAD_LEFT}measureCalendarWeekdayLabelWidth(cs,firstWeekStart){const ctx=getScratchCtx(this.ownerDocument);if(!ctx)return CAL_PAD_LEFT;ctx.font=this.labelFont(cs);let widest=0;for(const label of this.weekdayLabels(firstWeekStart))label&&(widest=Math.max(widest,ctx.measureText(label).width));const hostWidth=this.clientWidth||0,cap=hostWidth>0?Math.max(CAL_PAD_LEFT,hostWidth*MAX_ROW_LABEL_FRACTION):Number.POSITIVE_INFINITY;return Math.min(Math.max(CAL_PAD_LEFT,Math.ceil(widest)+CAL_WEEKDAY_LABEL_INSET*2),cap)}get matrixRowLabels(){return this.cachedMatrixData.rowLabels}get matrixColLabels(){return this.cachedMatrixData.colLabels}get matrixValues(){return this.cachedMatrixData.values}get calendarDays(){return this.data.kind==="calendar"?this.data.days:[]}get calendarData(){return this.data.kind==="calendar"?this.data:void 0}get cellSize(){return this._cellSize??(this.effectiveMode==="calendar"?CAL_CELL:DEFAULT_MATRIX_CELL_SIZE)}set cellSize(value){const oldValue=this._cellSize;this._cellSize=value==null?void 0:finiteRange(value,this.effectiveMode==="calendar"?CAL_CELL:DEFAULT_MATRIX_CELL_SIZE,1),this.requestUpdate("cellSize",oldValue)}get signedDomain(){return this.domain!==void 0||this.midpoint!==void 0}rampAlpha(value,lo,hi){const anchor=this.midpoint;return anchor===void 0?linearAlpha(value,lo,hi):midpointAlpha(value,lo,hi,anchor)}rampBucket(value,lo,hi,steps){const anchor=this.midpoint;return anchor===void 0?linearBucket(value,lo,hi,steps):midpointBucket(value,lo,hi,anchor,steps)}isNoData(value){return Number.isFinite(value)?value<0&&!this.signedDomain:!0}get maxCellSize(){return this._maxCellSize}set maxCellSize(value){const oldValue=this._maxCellSize;this._maxCellSize=normalizeCellSizeClamp(value),this.requestUpdate("maxCellSize",oldValue)}get minCellSize(){return this._minCellSize}set minCellSize(value){const oldValue=this._minCellSize;this._minCellSize=normalizeCellSizeClamp(value),this.requestUpdate("minCellSize",oldValue)}get normalizedFirstDayOfWeek(){return(finiteInteger(this.calendarData?.firstDayOfWeek??0,0)%7+7)%7}get bucketCount(){return this._bucketCount}set bucketCount(value){const oldValue=this._bucketCount;this._bucketCount=normalizeBucketCount(value),this.requestUpdate("bucketCount",oldValue)}toggleRowSelection(row){this.toggleSelectionAxis(row,!0)}toggleColumnSelection(col){this.toggleSelectionAxis(col,!1)}get calendarWeekdayLabelText(){return this.calendarData?.weekdayLabelText}get calendarWeekdayLabelWidth(){const value=this.calendarData?.weekdayLabelWidth;if(value==="auto")return value;if(typeof value!="number")return;const resolved=finiteNumber(value,CAL_PAD_LEFT);return resolved>=0?resolved:void 0}get calendarMonthLabelText(){return this.calendarData?.monthLabelText}get calendarColumnX(){return this.calendarData?.columnX}get calendarRowY(){return this.calendarData?.rowY}constructor(){super(),this.data=DEFAULT_MATRIX_DATA,this._stickyLabels="none",this.resolvedColLabelHeight=PAD_TOP,this.resolvedRowLabelWidth=PAD_LEFT,this.resolvedCalendarWeekdayLabelWidth=CAL_PAD_LEFT,this.withoutLegend=!1,this.scale="linear",this.cellGapX=1,this.cellGapY=1,this.cellRadius=0,this.colLabelInterval=1,this.fitToWidth=!1,this._bucketCount=DEFAULT_BUCKET_COUNT,this.annotations=[],this.selectedCell=null,this.multiple=!1,this.selectedCells=[],this.accessibleCells=!1,this.cachedValueRange=null,this.cachedMatrixData={rowLabels:[],colLabels:[],values:[],truncated:!1},this.cachedCalendarGrid=buildCalendarGrid(this.calendarDays),this.cachedCalendarSortedValues=[],this.cachedCalendarCellsByPos=new Map,this.cachedCalendarCellsByDate=new Map,this.cachedAnnotations=[],this.cachedLegendStops=[],this.cachedColorSteps=[],this.cachedCalendarAnnotationDates=new Set,this.cachedMatrixAnnotationPositions=new Set,this.decorationProjectionTruncated=!1,this.cachedCalendarDateByPos=[],this.cachedAccessiblePositions=[],this.cachedAccessiblePositionsByKey=new Map,this.cachedAccessiblePositionIndexByKey=new Map,this.cachedRamp=null,this.canvasHasContent=!1,this.canvasVisible=!0,this.drawDirty=!1,this.hoverCell=null,this.focusedCell=null,this.liveText="",this.accessibleTargetSizePx=DEFAULT_ACCESSIBLE_TARGET_SIZE_PX,this.restoringAccessibleFocus=!1,this.accessibleFocusGeneration=0,this.authorRole=null,this.authorAriaLabel=null,this.generatedAriaLabel="",this.syncingGeneratedSemantics=!1,this.onDprChange=()=>{this.watchDpr(),this.requestDraw()},this.scheduleDraw=()=>{if(this.drawFrameRequest)return;const owner=this.ownerDocument.defaultView;if(!owner||!this.isConnected)return;const request={owner,handle:0};request.handle=owner.requestAnimationFrame(()=>{this.drawFrameRequest===request&&(this.drawFrameRequest=void 0,this.isConnected&&this.ownerDocument.defaultView===owner&&this.requestDraw())}),this.drawFrameRequest=request},this.selectedPositions=new Map,this.selectionAnchor=null,this.suppressSelectionClick=!1,this.onSelectionPointerDown=event=>{if(!this.multiple||event.button!==0||!event.isPrimary||this.selectionGesture)return;const pos=this.selectionPointerPosition(event);if(!pos)return;event.preventDefault(),this.suppressSelectionClick=!1,this.selectionRangeBase=void 0,this.selectionAnchor=pos,this.focusedCell=pos,this.accessibleCells?this.focusAccessibleCell(pos):this.canvas?.focus();const target=event.currentTarget;this.selectionGesture={pointerId:event.pointerId,target,start:pos,previous:pos,moved:!1,selecting:!this.selectedPositions.has(this.accessibleCellKey(pos)),cells:new Map(this.selectedPositions)};try{target.setPointerCapture(event.pointerId)}catch{}this.paintSelectionTo(pos)},this.onSelectionPointerMove=event=>{if(this.selectionGesture?.pointerId!==event.pointerId)return;const pos=this.selectionPointerPosition(event);pos&&!this.samePos(pos,this.selectionGesture.previous)&&this.paintSelectionTo(pos)},this.onSelectionPointerUp=event=>{const gesture=this.selectionGesture;if(!gesture||gesture.pointerId!==event.pointerId)return;const pos=this.selectionPointerPosition(event);pos&&this.paintSelectionTo(pos),this.cancelSelectionGesture(),this.proposeSelection(gesture.cells,"pointer"),gesture.moved||this.emitCellClick(gesture.start,"pointer",!1)},this.onSelectionPointerCancel=event=>{this.selectionGesture?.pointerId===event.pointerId&&this.cancelSelectionGesture()},this.tooltipSize={inline:0,block:0},this.onPointerMove=e=>{const next=this.hitTest(e.offsetX,e.offsetY);this.samePos(this.hoverCell,next)||(this.hoverCell=next)},this.onPointerLeave=()=>{this.hoverCell=null},this.onCanvasClick=e=>{if(this.consumeSelectionClick(e))return;const pos=this.hitTest(e.offsetX,e.offsetY);pos&&(this.focusedCell=pos,this.announce(pos),this.emitCellClick(pos))},this.onKeyDown=e=>{if(this.selectionKeyDown(e,this.focusedCell))return;const previous=this.focusedCell;if(this.effectiveMode==="calendar"?this.onCalendarKeyDown(e):this.onMatrixKeyDown(e),ARROW_KEYS.has(e.key)&&this.focusedCell){const proposedKeys=this.extendSelection(previous,this.focusedCell,e.shiftKey);this.announce(this.focusedCell,proposedKeys?.has(this.accessibleCellKey(this.focusedCell)))}},this.canvasColorCache=new Map,this.onAccessibleCellFocus=e=>{if(this.restoringAccessibleFocus)return;const key=e.currentTarget.dataset.cellKey,pos=key?this.accessibleCellAtKey(key):null;pos&&(this.samePos(pos,this.focusedCell)||(this.selectionAnchor=pos,this.selectionRangeBase=void 0),this.focusedCell=pos,this.announce(pos))},this.onAccessibleCellClick=e=>{if(this.consumeSelectionClick(e))return;const key=e.currentTarget.dataset.cellKey,pos=key?this.accessibleCellAtKey(key):null;pos&&(this.focusedCell=pos,this.announce(pos),this.emitCellClick(pos,e.detail===0?"keyboard":"pointer"))},this.onAccessibleCellKeyDown=e=>{const key=e.currentTarget.dataset.cellKey,pos=key?this.accessibleCellAtKey(key):null;pos&&(this.selectionKeyDown(e,pos)||ARROW_KEYS.has(e.key)&&(e.preventDefault(),this.focusedCell=pos,this.onKeyDown(e),this.focusAccessibleCell(this.focusedCell)))},new ThemeWatcher(this,()=>this.refreshTheme())}warnOnLegendRampMismatch(){const rampColors=this.cachedColorSteps.map(color=>sanitizeCssColor(color)??color);if(rampColors.length===0)return;const legendColors=this.cachedLegendStops.filter(stop=>!!stop.color&&stop.partOfRamp!==!1).map(stop=>sanitizeCssColor(stop.color??"")??stop.color??"");legendColors.length===0||legendColors.length===rampColors.length&&legendColors.every((color,index)=>color===rampColors[index])||devWarnOnce("lyra-heatmap-legend-ramp-mismatch",`<${this.localName}>: legendStops describes ${legendColors.length} colour(s) that do not match the ${rampColors.length} colorSteps the cells are painted from, so the legend may misdescribe the ramp. Supply legendStops built from the same array as colorSteps, or omit it to keep the built-in gradient key.`)}attributeChangedCallback(name,oldValue,value){super.attributeChangedCallback(name,oldValue,value),!(oldValue===value||this.syncingGeneratedSemantics)&&(name==="role"&&(this.authorRole=value),name==="aria-label"&&(this.authorAriaLabel=value))}connectedCallback(){super.connectedCallback(),this.syncAnnouncementSink(),this.refreshAccessibleTargetSize();const owner=this.ownerDocument.defaultView,ResizeObserverCtor=owner?.ResizeObserver;if(owner&&ResizeObserverCtor){let observer;observer=new ResizeObserverCtor(()=>{!this.isConnected||this.ownerDocument.defaultView!==owner||this.resizeObserver!==observer||this.scheduleDraw()}),this.resizeObserver=observer,observer.observe(this)}const IntersectionObserverCtor=owner?.IntersectionObserver;if(this.canvasVisible=!0,owner&&IntersectionObserverCtor){let observer;observer=new IntersectionObserverCtor(entries=>{if(!this.isConnected||this.ownerDocument.defaultView!==owner||this.intersectionObserver!==observer)return;const entry=entries.find(candidate=>candidate.target===this);!entry||entry.isIntersecting===this.canvasVisible||(this.canvasVisible=entry.isIntersecting,this.canvasVisible&&this.drawDirty&&this.scheduleDraw())}),this.intersectionObserver=observer,observer.observe(this)}this.cachedRamp=null,this.canvasColorCache.clear(),this.watchDpr()}disconnectedCallback(){super.disconnectedCallback(),this.cancelSelectionGesture(),this.selectionAnchor=null,this.selectionRangeBase=void 0,this.accessibleFocusGeneration++,this.pendingAccessibleFocus=void 0,this.pendingAccessibleFocusOrigin=void 0,this.restoringAccessibleFocus=!1,this.releaseAnnouncementSink(),this.hoverCell=null,this.focusedCell=null,this.liveText="",this.canvasHasContent=!1,this.drawDirty=!0,this.resizeObserver?.disconnect(),this.resizeObserver=void 0,this.intersectionObserver?.disconnect(),this.intersectionObserver=void 0,this.canvasVisible=!0,this.clearDprWatcher(),this.cancelDrawFrame()}releaseAnnouncementSink(){this.announcementSink?.release(),this.announcementSink=void 0}syncAnnouncementSink(){if(!this.isConnected){this.releaseAnnouncementSink();return}this.announcementSink?.element.ownerDocument!==this.ownerDocument&&(this.releaseAnnouncementSink(),this.announcementSink=acquireAnnouncementSink("polite",{document:this.ownerDocument,source:this}))}watchDpr(){this.clearDprWatcher();const owner=this.ownerDocument.defaultView;if(!owner||typeof owner.matchMedia!="function")return;const query2=owner.matchMedia(`(resolution: ${owner.devicePixelRatio}dppx)`),listener=()=>{!this.isConnected||this.ownerDocument.defaultView!==owner||this.dprQuery!==query2||this.onDprChange()};this.dprQuery=query2,this.dprChangeListener=listener,query2.addEventListener("change",listener)}clearDprWatcher(){this.dprQuery&&this.dprChangeListener&&this.dprQuery.removeEventListener("change",this.dprChangeListener),this.dprQuery=void 0,this.dprChangeListener=void 0}willUpdate(changed){super.willUpdate(changed),(changed.has("data")||changed.has("domain")||changed.has("midpoint")||!this.hasUpdated)&&this.rebuildCanonicalMatrixData(),(changed.has("annotations")||changed.has("legendStops")||changed.has("colorSteps")||!this.hasUpdated)&&this.rebuildBoundedDecorations();const accessibleModeChanged=changed.has("accessibleCells")&&this.hasUpdated,collectionChanged=changed.has("data")||changed.has("cellInteractive"),activeRenderedControl=collectionChanged||accessibleModeChanged?activeElementIn(this.shadowRoot):null,activeAccessibleCell=activeRenderedControl?.matches('[part="cell"]')?activeRenderedControl:null,renderedAccessibleCells=activeAccessibleCell?.matches('[part="cell"]')?[...this.shadowRoot?.querySelectorAll('[part="cell"]')??[]]:[],accessibleFocusSnapshot=activeAccessibleCell?.matches('[part="cell"]')?{identity:activeAccessibleCell.dataset.cellIdentity,index:renderedAccessibleCells.indexOf(activeAccessibleCell)}:void 0;if(collectionChanged&&(this.focusedCell=null,this.hoverCell=null,this.liveText=""),changed.has("data")||changed.has("locale")||!this.hasUpdated){this.cachedCalendarGrid=buildCalendarGrid(this.calendarDays,this.normalizedFirstDayOfWeek,this.calendarMonthLabelText,this.effectiveLocale),this.cachedCalendarSortedValues=this.cachedCalendarGrid.cells.map(cell=>cell.value).filter(value=>!this.isNoData(value)).sort((a,b)=>a-b),this.cachedCalendarCellsByPos=new Map(this.cachedCalendarGrid.cells.map(cell=>[`${cell.week}:${cell.weekday}`,cell])),this.cachedCalendarCellsByDate=new Map(this.cachedCalendarGrid.cells.map(cell=>[cell.date,cell]));const{firstWeekStart,weekCount}=this.cachedCalendarGrid;this.cachedCalendarDateByPos=Array.from({length:weekCount*7},(_,index)=>isoDateAtOffset(firstWeekStart,index))}if(changed.has("colorSteps")||changed.has("withoutLegend")||!this.hasUpdated){const colorSteps=this.withoutLegend?[]:this.cachedColorSteps.map(sanitizeCssColor);colorSteps.length>=2&&colorSteps.every(color=>color!==void 0)?this.style.setProperty("--lr-heatmap-color-steps-gradient",`linear-gradient(to right, ${colorSteps.join(", ")})`):this.style.removeProperty("--lr-heatmap-color-steps-gradient")}if((changed.has("data")||changed.has("domain")||changed.has("midpoint")||!this.hasUpdated)&&(this.cachedValueRange=this.computeValueRange()),(collectionChanged||!this.hasUpdated)&&this.rebuildAccessiblePositions(),(collectionChanged||accessibleModeChanged||changed.has("multiple"))&&(this.cancelSelectionGesture(),this.selectionAnchor=null,this.selectionRangeBase=void 0,this.proposedSelectionKeys=void 0),(collectionChanged||changed.has("selectedCells")||changed.has("multiple")||!this.hasUpdated)&&(this.rebuildSelectedPositions(),changed.has("selectedCells")&&this.selectionGesture&&this.cancelSelectionGesture(),changed.has("selectedCells")&&this.selectionRangeBase&&(this.proposedSelectionKeys?.size!==this.selectedPositions.size||[...this.selectedPositions.keys()].some(key=>!this.proposedSelectionKeys?.has(key)))&&(this.selectionAnchor=this.focusedCell,this.selectionRangeBase=void 0)),accessibleFocusSnapshot){const positions=this.accessibleCellPositions(),target=(accessibleFocusSnapshot.identity==null?void 0:positions.find(pos=>this.accessibleCellIdentity(pos)===accessibleFocusSnapshot.identity))??positions[Math.min(Math.max(accessibleFocusSnapshot.index,0),positions.length-1)]??null;this.focusedCell=target,this.liveText=target?this.resolveCellText(target):"",this.pendingAccessibleFocus=target??"base",this.pendingAccessibleFocusOrigin=activeAccessibleCell??void 0,this.restoringAccessibleFocus=!0,this.accessibleFocusGeneration++}if(accessibleModeChanged){const previouslyAccessible=changed.get("accessibleCells")===!0;if(previouslyAccessible&&!this.accessibleCells&&activeAccessibleCell){const key=activeAccessibleCell.dataset.cellKey,target=key?this.accessibleCellAtKey(key):null;target&&(this.focusedCell=target,this.liveText=this.resolveCellText(target)),this.pendingAccessibleFocus="canvas",this.pendingAccessibleFocusOrigin=activeAccessibleCell,this.restoringAccessibleFocus=!0,this.accessibleFocusGeneration++}else if(!previouslyAccessible&&this.accessibleCells&&activeRenderedControl?.matches('[part="canvas"]')){const positions=this.accessibleCellPositions(),target=this.focusedCell?positions.find(pos=>this.samePos(pos,this.focusedCell))??positions[0]??null:positions[0]??null;this.focusedCell=target,this.liveText=target?this.resolveCellText(target):"",this.pendingAccessibleFocus=target??"base",this.pendingAccessibleFocusOrigin=activeRenderedControl,this.restoringAccessibleFocus=!0,this.accessibleFocusGeneration++}}const bounds=this.cachedValueRange,range=bounds?`${this.formatNumericValue(bounds[0])}–${this.formatNumericValue(bounds[1])}`:this.localize("heatmapNoDataValue"),valueLabel=this.localizedValueLabel();let label;if(this.effectiveMode==="calendar")label=this.localize("heatmapCalendarLabel",void 0,{days:this.formatCount(this.cachedCalendarGrid.cells.length),label:valueLabel,range});else{const rows=this.matrixRowLabels.length,cols=this.matrixColLabels.length;label=this.localize("heatmapMatrixLabel",void 0,{rows:this.formatCount(rows),cols:this.formatCount(cols),label:valueLabel,range})}const selectedText=this.selectedCellDescription(),generatedAriaLabel=[label,selectedText,this.projectionDescription()].filter(Boolean).join(" ");this.generatedAriaLabel=generatedAriaLabel,this.syncingGeneratedSemantics=!0;try{this.authorRole===null&&this.setAttribute("role","group"),this.authorAriaLabel===null&&this.setAttribute("aria-label",generatedAriaLabel)}finally{this.syncingGeneratedSemantics=!1}}rebuildBoundedDecorations(){this.cachedAnnotations=this.annotations.slice(0,MAX_HEATMAP_DECORATIONS).map(entry=>({...entry})),this.cachedLegendStops=(this.legendStops??[]).slice(0,MAX_HEATMAP_DECORATIONS).map(entry=>({...entry})),this.cachedColorSteps=(this.colorSteps??[]).slice(0,MAX_HEATMAP_DECORATIONS),this.warnOnLegendRampMismatch(),this.cachedCalendarAnnotationDates=new Set(this.cachedAnnotations.flatMap(annotation=>annotation.date==null?[]:[annotation.date])),this.cachedMatrixAnnotationPositions=new Set(this.cachedAnnotations.flatMap(annotation=>annotation.row==null||annotation.col==null?[]:[`${annotation.row}:${annotation.col}`])),this.decorationProjectionTruncated=this.annotations.length>MAX_HEATMAP_DECORATIONS||(this.legendStops?.length??0)>MAX_HEATMAP_DECORATIONS||(this.colorSteps?.length??0)>MAX_HEATMAP_DECORATIONS}get projectionTruncated(){return this.decorationProjectionTruncated||(this.effectiveMode==="calendar"?this.cachedCalendarGrid.truncated:this.cachedMatrixData.truncated)}get cellProjectionTruncated(){return this.effectiveMode==="calendar"?this.cachedCalendarGrid.truncated:this.cachedMatrixData.truncated}projectedCellCount(){return this.effectiveMode==="calendar"?this.cachedCalendarGrid.weekCount*7:this.matrixRowLabels.length*this.matrixColLabels.length}projectionDescription(){const messages=[];return this.cellProjectionTruncated&&messages.push(this.localize("heatmapProjectionLimit",void 0,{count:this.formatCount(this.projectedCellCount())})),this.decorationProjectionTruncated&&messages.push(this.localize("heatmapDecorationLimit",void 0,{count:this.formatCount(MAX_HEATMAP_DECORATIONS)})),messages.join(" ")}rebuildCanonicalMatrixData(){if(this.data.kind!=="matrix"){this.cachedMatrixData={rowLabels:[],colLabels:[],values:[],truncated:!1};return}const colCount=Math.min(this.data.colLabels.length,MAX_HEATMAP_CELLS),rowLimit=colCount===0?Math.min(this.data.rowLabels.length,MAX_HEATMAP_CELLS):Math.floor(MAX_HEATMAP_CELLS/colCount),rowCount=Math.min(this.data.rowLabels.length,rowLimit),rowLabels=this.data.rowLabels.slice(0,rowCount).map(String),colLabels=this.data.colLabels.slice(0,colCount).map(String),source=this.data,values=Array.from({length:rowCount},(_,row)=>Array.from({length:colCount},(_2,col)=>source.values[row]?.[col]??(this.signedDomain?Number.NaN:-1)));this.cachedMatrixData={rowLabels,colLabels,values,truncated:rowCount!==this.data.rowLabels.length||colCount!==this.data.colLabels.length||this.data.values.some((row,index)=>index>=rowCount||row.length>colCount)}}selectedCellDescription(){if(this.multiple){const count=this.currentSelectedPositions.size;return count?this.localize("heatmapSelectedCount",void 0,{count:this.formatCount(count)}):""}if(!this.selectedCell)return"";if(this.effectiveMode==="calendar"){if(this.selectedCell.date==null)return"";const match=this.cachedCalendarCellsByDate.get(this.selectedCell.date);return match?this.localize("heatmapSelectedCellLabel",void 0,{cell:this.calendarCellText({week:match.week,weekday:match.weekday,date:match.date})}):""}const{row,col}=this.selectedCell;return row==null||col==null||row<0||row>=this.matrixRowLabels.length||col<0||col>=this.matrixColLabels.length?"":this.localize("heatmapSelectedCellLabel",void 0,{cell:this.matrixCellText({row,col})})}computeValueRange(){const pinned=this.domain;if(pinned){const[lo,hi]=pinned;if(Number.isFinite(lo)&&Number.isFinite(hi)&&lo!==hi)return lo<hi?[lo,hi]:[hi,lo]}const source=this.effectiveMode==="calendar"?this.cachedCalendarGrid.cells.map(cell=>cell.value):this.matrixValues.flat();return minMax(source.filter(v=>!this.isNoData(v)))}localizedValueLabel(){return this.valueLabel===void 0?this.localize("heatmapValueLabel"):this.valueLabel}formatNumericValue(value){return getNumberFormat(this.effectiveLocale||void 0).format(value)}updated(changed){if(super.updated(changed),this.hoverCell&&this.effectiveStickyLabels!=="none"&&this.scheduleAfterUpdate(()=>this.measureTooltip(),"heatmap-tooltip-metrics"),["data","cellSize","cellGapX","cellGapY","cellRadius","colLabelInterval","maxCellSize","minCellSize","valueLabel","scale","domain","midpoint","fitToWidth","rowLabelWidth","colLabelHeight","colLabelRotation","bucketCount","annotations","focusedCell","colorSteps","cellColor","selectedCell","selectedCells","multiple","selectionPreview","legendStops","accessibleCells","accessibleTargetSizePx","locale","stickyLabels"].some(name=>changed.has(name))){if(changed.has("focusedCell")&&[...changed.keys()].every(key=>key==="focusedCell"||key==="liveText")&&this.repaintFocusRing(changed.get("focusedCell")))return;this.requestDraw()}const pending=this.pendingAccessibleFocus;if(pending===void 0)return;this.pendingAccessibleFocus=void 0;const origin=this.pendingAccessibleFocusOrigin;this.pendingAccessibleFocusOrigin=void 0;const generation=this.accessibleFocusGeneration;this.scheduleAfterUpdate(()=>{try{if(generation!==this.accessibleFocusGeneration||!this.isConnected)return;if(origin){const internalActive=activeElementIn(this.shadowRoot),documentActive=activeElementIn(this.ownerDocument),focusStayedAtOrigin=internalActive===origin,originWasRemovedWithoutReplacement=internalActive===null&&(documentActive===null||documentActive===this||documentActive===this.ownerDocument.body);if(!focusStayedAtOrigin&&!originWasRemovedWithoutReplacement)return}if(pending==="base"){this.shadowRoot?.querySelector('[part="base"]')?.focus();return}if(pending==="canvas"){this.shadowRoot?.querySelector('[part="canvas"]')?.focus();return}const identity=this.accessibleCellIdentity(pending);[...this.shadowRoot?.querySelectorAll('[part="cell"]')??[]].find(candidate=>candidate.dataset.cellIdentity===identity)?.focus()}finally{this.restoringAccessibleFocus=!1}},"heatmap-accessible-focus")}refreshTheme(){this.cachedRamp=null,this.refreshAccessibleTargetSize()||this.requestDraw()}refreshAccessibleTargetSize(){const raw=this.ownerDocument.defaultView?.getComputedStyle(this).getPropertyValue("--lr-icon-button-size").trim()??"",resolved=resolveCssLength(raw,{host:this}),next=resolved!==void 0&&Number.isFinite(resolved)&&resolved>0?resolved:DEFAULT_ACCESSIBLE_TARGET_SIZE_PX;return next===this.accessibleTargetSizePx?!1:(this.accessibleTargetSizePx=next,!0)}scaleEndpoints(cs){const lo=cs.getPropertyValue("--lr-heatmap-scale-lo").trim()||cs.getPropertyValue("--_lr-heatmap-scale-lo").trim()||FALLBACK_SCALE_LO,hi=cs.getPropertyValue("--lr-heatmap-scale-hi").trim()||cs.getPropertyValue("--_lr-heatmap-scale-hi").trim()||FALLBACK_SCALE_HI;return[lo,hi]}labelColor(cs){return cs.getPropertyValue("--lr-color-text-quiet").trim()||"#6b7280"}labelFont(cs){return cs.getPropertyValue("--lr-heatmap-label-font").trim()||cs.getPropertyValue("--_lr-heatmap-label-font").trim()||FALLBACK_LABEL_FONT}stickyLabelBg(cs){const raw=cs.getPropertyValue("--lr-heatmap-sticky-label-bg").trim()||cs.getPropertyValue("--_lr-heatmap-sticky-label-bg").trim()||FALLBACK_STICKY_LABEL_BG;return formatRgb(resolveRgb(raw,FALLBACK_STICKY_LABEL_BG,this.ownerDocument))}noDataFill(cs){return cs.getPropertyValue("--lr-heatmap-no-data-fill").trim()||cs.getPropertyValue("--_lr-heatmap-no-data-fill").trim()||FALLBACK_NO_DATA_FILL}focusRingColor(cs){return cs.getPropertyValue("--lr-heatmap-focus-ring-color").trim()||cs.getPropertyValue("--_lr-heatmap-focus-ring-color").trim()||FALLBACK_FOCUS_RING_COLOR}annotationColor(cs){return cs.getPropertyValue("--lr-heatmap-annotation-color").trim()||cs.getPropertyValue("--_lr-heatmap-annotation-color").trim()||FALLBACK_ANNOTATION_COLOR}selectedColor(cs){return cs.getPropertyValue("--lr-heatmap-selected-color").trim()||cs.getPropertyValue("--_lr-heatmap-selected-color").trim()||FALLBACK_SELECTED_COLOR}strokeCellState(ctx,x,y,size,state2,color){const shape=this.effectiveMode==="matrix"?this.matrixCellShape(size):void 0,width=shape?.custom?shape.w:size,height=shape?.custom?shape.h:size;shape?.custom&&(ctx.save(),ctx.beginPath(),ctx.roundRect(x,y,shape.w,shape.h,shape.radius),ctx.clip());const inset=Math.min(state2==="annotation"?.5:state2==="selected"?3.5:6.5,Math.max(.5,(Math.min(width,height)-RING_LINE_WIDTH-1)/2)),w=Math.max(1,width-inset*2),h=Math.max(1,height-inset*2);ctx.lineWidth=RING_LINE_WIDTH,ctx.strokeStyle=color,ctx.setLineDash?.(state2==="annotation"?[]:state2==="selected"?[4,2]:[1,2]),shape?.custom&&shape.radius>0?(ctx.beginPath(),ctx.roundRect(x+inset,y+inset,w,h,Math.max(0,shape.radius-inset)),ctx.stroke()):ctx.strokeRect(x+inset,y+inset,w,h),ctx.setLineDash?.([]),shape?.custom&&ctx.restore()}isSelectedPos(pos){return this.multiple?this.currentSelectedPositions.has(this.accessibleCellKey(pos)):this.selectedCell?"week"in pos?this.selectedCell.date==null?!1:this.calendarCellAt(pos).date===this.selectedCell.date:this.selectedCell.row===pos.row&&this.selectedCell.col===pos.col:!1}draw(){if(!this.canvasVisible){this.drawDirty=!0;return}this.drawDirty=!1,this.canvasHasContent=!1,this.effectiveMode==="calendar"?this.drawCalendar():this.drawMatrix()}requestDraw(){this.drawDirty=!0,this.canvasVisible&&this.draw()}repaintFocusRing(previous){if(!this.canvasHasContent||!this.canvas)return!1;const current=this.focusedCell;if(this.effectiveMode==="calendar"){if(previous&&!("week"in previous)||current&&!("week"in current))return!1;this.repaintCalendarFocusCell(previous&&"week"in previous?previous:null),current&&(!previous||!this.samePos(previous,current))&&this.repaintCalendarFocusCell(current)}else{if(previous&&!("row"in previous)||current&&!("row"in current))return!1;this.repaintMatrixFocusCell(previous&&"row"in previous?previous:null),current&&(!previous||!this.samePos(previous,current))&&this.repaintMatrixFocusCell(current)}return!0}cancelDrawFrame(){const request=this.drawFrameRequest;request&&request.owner.cancelAnimationFrame(request.handle),this.drawFrameRequest=void 0}resolveColorStep(color,fallback){const safe=sanitizeCssColor(color);if(!safe)return fallback;const scope=this.ownerDocument.createElement("span"),probe=this.ownerDocument.createElement("span");scope.hidden=!0,scope.style.color=fallback,probe.style.color=safe,scope.append(probe),this.renderRoot.append(scope);try{return this.ownerDocument.defaultView?.getComputedStyle(probe).color.trim()||fallback}finally{scope.remove()}}colorRamp(bucketCount,cs){const steps=this.cachedColorSteps;if(steps&&steps.length>=2){const key2=`steps ${steps.join(" ")}`;if(this.cachedRamp?.key===key2)return this.cachedRamp;const resolved=steps.map((color,index)=>this.resolveColorStep(color,index===steps.length-1?FALLBACK_SCALE_HI:FALLBACK_SCALE_LO)),colors2=resolved.map(color=>formatRgb(resolveRgb(color,FALLBACK_SCALE_LO,this.ownerDocument))),loRgb2=resolveRgb(resolved[0],FALLBACK_SCALE_LO,this.ownerDocument),hiRgb2=resolveRgb(resolved[resolved.length-1],FALLBACK_SCALE_HI,this.ownerDocument);return this.cachedRamp={key:key2,colors:colors2,loRgb:loRgb2,hiRgb:hiRgb2},this.cachedRamp}const[scaleLo,scaleHi]=this.scaleEndpoints(cs),normalizedBucketCount=normalizeBucketCount(bucketCount),key=`${scaleLo}\0${scaleHi}\0${normalizedBucketCount}`;if(this.cachedRamp?.key===key)return this.cachedRamp;const loRgb=resolveRgb(scaleLo,FALLBACK_SCALE_LO,this.ownerDocument),hiRgb=resolveRgb(scaleHi,FALLBACK_SCALE_HI,this.ownerDocument),colors=Array.from({length:normalizedBucketCount},(_,i)=>mixRgb(loRgb,hiRgb,i/(normalizedBucketCount-1)));return this.cachedRamp={key,colors,loRgb,hiRgb},this.cachedRamp}calendarCellSize(){const{weekCount}=this.cachedCalendarGrid;let size;if(this.fitToWidth&&weekCount>0){const hostWidth=this.clientWidth||this.calendarPadLeft+weekCount*(this.cellSize+CAL_GAP);size=this.clampFitCellSize((hostWidth-this.calendarPadLeft)/weekCount-CAL_GAP)}else size=this.cellSize;return this.accessibleCells?Math.max(size,this.accessibleTargetSizePx):size}clampFitCellSize(size){const floored=finiteRange(size,FIT_MIN_CELL,Math.max(FIT_MIN_CELL,this.minCellSize??FIT_MIN_CELL));return this.maxCellSize==null?floored:Math.min(floored,this.maxCellSize)}columnXFor(week){return this.calendarColumnPositions()[week]??this.calendarPadLeft}rowYFor(weekday){return this.calendarRowPositions()[weekday]??CAL_LABEL_H}calendarColumnPositions(){const cellSize=this.calendarCellSize(),weekCount=this.cachedCalendarGrid.weekCount,callback=this.calendarColumnX,padLeft=this.calendarPadLeft,cached=this.cachedColumnGeometry;if(cached!==void 0&&cached.callback===callback&&cached.padLeft===padLeft&&cached.cellSize===cellSize&&cached.weekCount===weekCount)return cached.positions;const positions=[];for(let index=0;index<=weekCount;index++){const fallback=index===0?padLeft:positions[index-1]+cellSize+CAL_GAP;let candidate=fallback;if(callback)try{const supplied=callback(index);Number.isFinite(supplied)&&supplied>=0&&(index===0||supplied>=positions[index-1]+cellSize)&&(candidate=supplied)}catch{candidate=fallback}positions.push(candidate)}return this.cachedColumnGeometry={callback,padLeft,cellSize,weekCount,positions},positions}calendarRowPositions(){const cellSize=this.calendarCellSize(),callback=this.calendarRowY,cached=this.cachedRowGeometry;if(cached!==void 0&&cached.callback===callback&&cached.cellSize===cellSize)return cached.positions;const positions=[];for(let index=0;index<=7;index++){const fallback=index===0?CAL_LABEL_H:positions[index-1]+cellSize+CAL_GAP;let candidate=fallback;if(callback)try{const supplied=callback(index);Number.isFinite(supplied)&&supplied>=0&&(index===0||supplied>=positions[index-1]+cellSize)&&(candidate=supplied)}catch{candidate=fallback}positions.push(candidate)}return this.cachedRowGeometry={callback,cellSize,positions},positions}weekAtX(x,weekCount){const positions=this.calendarColumnPositions(),cellSize=this.calendarCellSize();for(let week=0;week<weekCount;week++){const start=positions[week];if(x>=start&&x<start+cellSize)return week}return null}weekdayAtY(y){const positions=this.calendarRowPositions(),cellSize=this.calendarCellSize();for(let weekday=0;weekday<7;weekday++){const start=positions[weekday];if(y>=start&&y<start+cellSize)return weekday}return null}weekdayLabels(firstWeekStart){const formatter=getDateTimeFormat(this.effectiveLocale||void 0,{weekday:"short",timeZone:"UTC"}),labels=["","","","","","",""];for(const weekday of[1,3,5]){const row=(weekday-this.normalizedFirstDayOfWeek+7)%7;labels[row]=this.calendarWeekdayLabelText?.(weekday)??formatter.format(new Date(firstWeekStart.getTime()+row*MS_PER_DAY))}return labels}paintCalendarAxisLabels(ctx,cellSize,cs,firstWeekStart,monthLabels){ctx.fillStyle=this.labelColor(cs),ctx.font=this.labelFont(cs);for(const month of monthLabels)ctx.fillText(month.label,this.columnXFor(month.week),CAL_LABEL_H-4);const available=this.calendarPadLeft-CAL_WEEKDAY_LABEL_INSET*2;this.weekdayLabels(firstWeekStart).forEach((label,weekday)=>{const shown=label?this.ellipsize(ctx,label,available):"";shown&&ctx.fillText(shown,CAL_WEEKDAY_LABEL_INSET,this.rowYFor(weekday)+cellSize-1)})}drawCalendar(){if(!this.canvas)return;const{weekCount,firstWeekStart,monthLabels}=this.cachedCalendarGrid,cs=this.ownerDocument.defaultView?.getComputedStyle(this);if(!cs)return;const previousResolvedWeekdayWidth=this.resolvedCalendarWeekdayLabelWidth;this.calendarWeekdayLabelWidth==="auto"&&(this.resolvedCalendarWeekdayLabelWidth=this.measureCalendarWeekdayLabelWidth(cs,firstWeekStart));const autoGutterChanged=previousResolvedWeekdayWidth!==this.resolvedCalendarWeekdayLabelWidth,cellSize=this.calendarCellSize(),w=this.columnXFor(Math.max(1,weekCount)),h=this.rowYFor(7),dpr=this.ownerDocument.defaultView?.devicePixelRatio||1;this.canvas.width=w*dpr,this.canvas.height=h*dpr,this.canvas.style.width=`${w}px`,this.canvas.style.height=`${h}px`;const ctx=this.canvas.getContext("2d");if(!ctx)return;ctx.scale(dpr,dpr),ctx.clearRect(0,0,w,h);const buckets=normalizeBucketCount(this.bucketCount),ramp=this.colorRamp(buckets,cs).colors,noDataFill=this.noDataFill(cs);this.canvasColorCache.clear();const bounds=this.cachedValueRange,lo=bounds?bounds[0]:0,hi=bounds?bounds[1]:1;for(let week=0;week<weekCount;week++)for(let weekday=0;weekday<7;weekday++){const value=this.calendarValueAt(week,weekday),x=this.columnXFor(week),y=this.rowYFor(weekday),override=this.cellColor?.(this.calendarPos(week,weekday),value);if(override!=null)ctx.fillStyle=this.resolveCanvasColor(override,cs);else if(this.isNoData(value))ctx.fillStyle=noDataFill;else if(this.scale==="sqrt"){const step=sqrtStep(value,hi,ramp.length);ctx.fillStyle=step<0?noDataFill:ramp[step]}else if(this.cachedColorSteps.length>=2){const step=this.rampBucket(value,lo,hi,ramp.length);ctx.fillStyle=ramp[step]}else ctx.fillStyle=ramp[quartileBucket(value,this.cachedCalendarSortedValues,buckets)];ctx.fillRect(x,y,cellSize,cellSize)}if(this.cachedAnnotations.length)for(const ann of this.cachedAnnotations){if(ann.date==null)continue;const match=this.cachedCalendarCellsByDate.get(ann.date);if(!match)continue;const x=this.columnXFor(match.week),y=this.rowYFor(match.weekday);this.strokeCellState(ctx,x,y,cellSize,"annotation",this.annotationColor(cs))}for(const match of this.selectedPaintPositions())if("week"in match){const x=this.columnXFor(match.week),y=this.rowYFor(match.weekday);this.strokeCellState(ctx,x,y,cellSize,"selected",this.selectedColor(cs))}if(this.focusedCell&&"week"in this.focusedCell){const{week,weekday}=this.focusedCell;if(week<weekCount&&weekday<7){const x=this.columnXFor(week),y=this.rowYFor(weekday);this.strokeCellState(ctx,x,y,cellSize,"focus",this.focusRingColor(cs))}}this.paintCalendarAxisLabels(ctx,cellSize,cs,firstWeekStart,monthLabels),this.canvasHasContent=!0,autoGutterChanged&&this.accessibleCells&&this.scheduleAfterUpdate(()=>this.requestUpdate(),"heatmap-calendar-accessible-geometry")}matrixCellSize(cols){let size;if(this.fitToWidth&&cols>0){const padLeft=this.matrixPadLeft,hostWidth=this.clientWidth||padLeft+cols*this.cellSize;size=this.clampFitCellSize((hostWidth-padLeft)/cols)}else size=this.cellSize;if(!this.accessibleCells)return size;const target=this.accessibleTargetSizePx,gap=finiteNumber(this.cellGapX,1)!==1||finiteNumber(this.cellGapY,1)!==1||finiteRange(this.cellRadius,0,0)>0?Math.max(finiteRange(this.cellGapX,1,0,target),finiteRange(this.cellGapY,1,0,target)):0;return Math.max(size,target+gap)}matrixCellShape(size){if(finiteNumber(this.cellGapX,1)===1&&finiteNumber(this.cellGapY,1)===1&&finiteRange(this.cellRadius,0,0)===0)return{w:size-1,h:size-1,radius:0,custom:!1};const minimum=this.accessibleCells?Math.min(size,this.accessibleTargetSizePx):1,maxGap=Math.max(0,size-minimum),w=size-finiteRange(this.cellGapX,1,0,maxGap),h=size-finiteRange(this.cellGapY,1,0,maxGap),radius=finiteRange(this.cellRadius,0,0,Math.min(w,h)/2);return{w,h,radius,custom:w!==size-1||h!==size-1||radius!==0}}fillMatrixCell(ctx,x,y,shape){shape.radius===0?ctx.fillRect(x,y,shape.w,shape.h):(ctx.beginPath(),ctx.roundRect(x,y,shape.w,shape.h,shape.radius),ctx.fill())}paintMatrixCell(ctx,row,col,cellSize,cs,rampData,noDataFill){const value=this.matrixValues[row]?.[col]??Number.NaN,bounds=this.cachedValueRange,lo=bounds?bounds[0]:0,hi=bounds?bounds[1]:1,override=this.cellColor?.({row,col},value);if(override!=null)ctx.fillStyle=this.resolveCanvasColor(override,cs);else if(this.isNoData(value))ctx.fillStyle=noDataFill;else if(this.scale==="sqrt"){const step=sqrtStep(value,hi,rampData.colors.length);ctx.fillStyle=step<0?noDataFill:rampData.colors[step]}else this.cachedColorSteps.length>=2?ctx.fillStyle=rampData.colors[this.rampBucket(value,lo,hi,rampData.colors.length)]:ctx.fillStyle=mixRgb(rampData.loRgb,rampData.hiRgb,this.rampAlpha(value,lo,hi));this.fillMatrixCell(ctx,this.matrixPadLeft+col*cellSize,this.matrixPadTop+row*cellSize,this.matrixCellShape(cellSize))}paintMatrixFocusOverlays(ctx,row,col,cellSize,cs,state2){const x=this.matrixPadLeft+col*cellSize,y=this.matrixPadTop+row*cellSize;state2==="annotation"&&this.cachedMatrixAnnotationPositions.has(`${row}:${col}`)&&this.strokeCellState(ctx,x,y,cellSize,"annotation",this.annotationColor(cs)),state2==="selected"&&this.isSelectedPos({row,col})&&this.strokeCellState(ctx,x,y,cellSize,"selected",this.selectedColor(cs)),state2==="focus"&&this.focusedCell&&"row"in this.focusedCell&&this.focusedCell.row===row&&this.focusedCell.col===col&&this.strokeCellState(ctx,x,y,cellSize,"focus",this.focusRingColor(cs))}focusRepaintBounds(ctx,x,y,cellSize){const padding=RING_LINE_WIDTH+1,dpr=ctx.getTransform().a,left=Math.floor((x-padding)*dpr)/dpr,top=Math.floor((y-padding)*dpr)/dpr,right=Math.ceil((x+cellSize+padding)*dpr)/dpr,bottom=Math.ceil((y+cellSize+padding)*dpr)/dpr;return{left,top,width:right-left,height:bottom-top,radius:Math.ceil((2*padding+1/dpr)/cellSize)}}repaintMatrixFocusCell(pos){if(!pos||!this.canvas)return;const rows=this.matrixRowLabels.length,cols=this.matrixColLabels.length;if(pos.row<0||pos.row>=rows||pos.col<0||pos.col>=cols)return;const cellSize=this.matrixCellSize(cols),x=this.matrixPadLeft+pos.col*cellSize,y=this.matrixPadTop+pos.row*cellSize,ctx=this.canvas.getContext("2d");if(!ctx)return;const cs=this.ownerDocument.defaultView?.getComputedStyle(this);if(!cs)return;const{left,top,width,height,radius}=this.focusRepaintBounds(ctx,x,y,cellSize),firstRow=Math.max(0,pos.row-radius),lastRow=Math.min(rows-1,pos.row+radius),firstCol=Math.max(0,pos.col-radius),lastCol=Math.min(cols-1,pos.col+radius),ramp=this.colorRamp(RAMP_STEPS,cs),noData=this.noDataFill(cs);ctx.save();try{ctx.beginPath(),ctx.rect(left,top,width,height),ctx.clip(),ctx.clearRect(left,top,width,height);for(let row=firstRow;row<=lastRow;row++)for(let col=firstCol;col<=lastCol;col++)this.paintMatrixCell(ctx,row,col,cellSize,cs,ramp,noData);for(const state2 of["annotation","selected","focus"])for(let row=firstRow;row<=lastRow;row++)for(let col=firstCol;col<=lastCol;col++)this.paintMatrixFocusOverlays(ctx,row,col,cellSize,cs,state2)}finally{ctx.restore()}}paintCalendarCell(ctx,week,weekday,cellSize,cs,ramp,noDataFill){const value=this.calendarValueAt(week,weekday),bounds=this.cachedValueRange,lo=bounds?bounds[0]:0,hi=bounds?bounds[1]:1,override=this.cellColor?.(this.calendarPos(week,weekday),value);if(override!=null)ctx.fillStyle=this.resolveCanvasColor(override,cs);else if(this.isNoData(value))ctx.fillStyle=noDataFill;else if(this.scale==="sqrt"){const step=sqrtStep(value,hi,ramp.length);ctx.fillStyle=step<0?noDataFill:ramp[step]}else this.cachedColorSteps.length>=2?ctx.fillStyle=ramp[this.rampBucket(value,lo,hi,ramp.length)]:ctx.fillStyle=ramp[quartileBucket(value,this.cachedCalendarSortedValues,ramp.length)];ctx.fillRect(this.columnXFor(week),this.rowYFor(weekday),cellSize,cellSize)}paintCalendarFocusOverlays(ctx,week,weekday,cellSize,cs,state2){const date=this.calendarDateAt(week,weekday),x=this.columnXFor(week),y=this.rowYFor(weekday);state2==="annotation"&&this.cachedCalendarCellsByDate.has(date)&&this.cachedCalendarAnnotationDates.has(date)&&this.strokeCellState(ctx,x,y,cellSize,"annotation",this.annotationColor(cs)),state2==="selected"&&(this.multiple||this.cachedCalendarCellsByDate.has(date))&&this.isSelectedPos({week,weekday,date})&&this.strokeCellState(ctx,x,y,cellSize,"selected",this.selectedColor(cs)),state2==="focus"&&this.focusedCell&&"week"in this.focusedCell&&this.focusedCell.week===week&&this.focusedCell.weekday===weekday&&this.strokeCellState(ctx,x,y,cellSize,"focus",this.focusRingColor(cs))}repaintCalendarFocusCell(pos){if(!pos||!this.canvas)return;const{weekCount,firstWeekStart}=this.cachedCalendarGrid;if(pos.week<0||pos.week>=weekCount||pos.weekday<0||pos.weekday>=7)return;const cellSize=this.calendarCellSize(),x=this.columnXFor(pos.week),y=this.rowYFor(pos.weekday),ctx=this.canvas.getContext("2d");if(!ctx)return;const cs=this.ownerDocument.defaultView?.getComputedStyle(this);if(!cs)return;const{left,top,width,height,radius}=this.focusRepaintBounds(ctx,x,y,cellSize),firstWeek=Math.max(0,pos.week-radius),lastWeek=Math.min(weekCount-1,pos.week+radius),firstDay=Math.max(0,pos.weekday-radius),lastDay=Math.min(6,pos.weekday+radius),ramp=this.colorRamp(normalizeBucketCount(this.bucketCount),cs).colors,noData=this.noDataFill(cs);ctx.save();try{ctx.beginPath(),ctx.rect(left,top,width,height),ctx.clip(),ctx.clearRect(left,top,width,height);for(let week=firstWeek;week<=lastWeek;week++)for(let day=firstDay;day<=lastDay;day++)this.paintCalendarCell(ctx,week,day,cellSize,cs,ramp,noData);for(const state2 of["annotation","selected","focus"])for(let week=firstWeek;week<=lastWeek;week++)for(let day=firstDay;day<=lastDay;day++)this.paintCalendarFocusOverlays(ctx,week,day,cellSize,cs,state2);this.paintCalendarAxisLabels(ctx,cellSize,cs,firstWeekStart,this.cachedCalendarGrid.monthLabels)}finally{ctx.restore()}}drawMatrix(){if(!this.canvas)return;const rows=this.matrixRowLabels.length,cols=this.matrixColLabels.length;if(this.rowLabelWidth==="auto"||this.colLabelHeight==="auto"){const measureStyle=getComputedStyle(this);this.rowLabelWidth==="auto"&&(this.resolvedRowLabelWidth=this.measureRowLabelWidth(measureStyle)),this.colLabelHeight==="auto"&&(this.resolvedColLabelHeight=this.measureColLabelHeight(measureStyle))}const padLeft=this.matrixPadLeft,padTop=this.matrixPadTop,cellSize=this.matrixCellSize(cols),shape=this.matrixCellShape(cellSize),dimensions=shape.custom?{cellWidth:shape.w,cellHeight:shape.h,cellRadius:shape.radius}:{},previous=this.lastPaintedMatrixGeometry,geometry=previous&&previous.padLeft===padLeft&&previous.padTop===padTop&&previous.cellSize===cellSize&&previous.cellWidth===dimensions.cellWidth&&previous.cellHeight===dimensions.cellHeight&&previous.cellRadius===dimensions.cellRadius?previous:Object.freeze({padLeft,padTop,cellSize,...dimensions});this.lastPaintedMatrixGeometry=geometry;const geometryChanged=geometry!==previous;geometryChanged&&this.emit("lr-matrix-geometry-change",geometry);const w=padLeft+cols*cellSize,h=padTop+rows*cellSize,dpr=this.ownerDocument.defaultView?.devicePixelRatio||1;this.canvas.width=w*dpr,this.canvas.height=h*dpr,this.canvas.style.width=`${w}px`,this.canvas.style.height=`${h}px`;const ctx=this.canvas.getContext("2d");if(!ctx)return;ctx.scale(dpr,dpr),ctx.clearRect(0,0,w,h);const cs=this.ownerDocument.defaultView?.getComputedStyle(this);if(!cs)return;const bounds=this.cachedValueRange,lo=bounds?bounds[0]:0,hi=bounds?bounds[1]:1,rampData=this.colorRamp(RAMP_STEPS,cs),ramp=rampData.colors,{loRgb,hiRgb}=rampData,noDataFill=this.noDataFill(cs);this.canvasColorCache.clear();for(let r=0;r<rows;r++)for(let c=0;c<cols;c++){const v=this.matrixValues[r]?.[c]??Number.NaN,x=padLeft+c*cellSize,y=padTop+r*cellSize,override=this.cellColor?.({row:r,col:c},v);if(override!=null)ctx.fillStyle=this.resolveCanvasColor(override,cs);else if(this.isNoData(v))ctx.fillStyle=noDataFill;else if(this.scale==="sqrt"){const step=sqrtStep(v,hi,ramp.length);ctx.fillStyle=step<0?noDataFill:ramp[step]}else if(this.cachedColorSteps.length>=2){const step=this.rampBucket(v,lo,hi,ramp.length);ctx.fillStyle=ramp[step]}else{const t=this.rampAlpha(v,lo,hi);ctx.fillStyle=mixRgb(loRgb,hiRgb,t)}this.fillMatrixCell(ctx,x,y,shape)}if(this.cachedAnnotations.length)for(const ann of this.cachedAnnotations){if(ann.row==null||ann.col==null||ann.row<0||ann.row>=rows||ann.col<0||ann.col>=cols)continue;const x=padLeft+ann.col*cellSize,y=padTop+ann.row*cellSize;this.strokeCellState(ctx,x,y,cellSize,"annotation",this.annotationColor(cs))}for(const selected of this.selectedPaintPositions()){if(!("row"in selected))continue;const{row,col}=selected;if(row>=0&&row<rows&&col>=0&&col<cols){const x=padLeft+col*cellSize,y=padTop+row*cellSize;this.strokeCellState(ctx,x,y,cellSize,"selected",this.selectedColor(cs))}}if(this.focusedCell&&"row"in this.focusedCell){const{row,col}=this.focusedCell;if(row<rows&&col<cols){const x=padLeft+col*cellSize,y=padTop+row*cellSize;this.strokeCellState(ctx,x,y,cellSize,"focus",this.focusRingColor(cs))}}this.paintMatrixRowLabels(ctx,padLeft,padTop,cellSize,cs),this.paintMatrixColLabels(ctx,padLeft,padTop,cellSize,cs),this.paintFrozenLabelBands(padLeft,padTop,cellSize,w,h,dpr,cs),this.canvasHasContent=!0,geometryChanged&&this.accessibleCells&&this.scheduleAfterUpdate(()=>this.requestUpdate(),"heatmap-matrix-accessible-geometry")}paintMatrixRowLabels(ctx,padLeft,padTop,cellSize,cs){ctx.fillStyle=this.labelColor(cs),ctx.font=this.labelFont(cs);const rowLabelSpace=padLeft-ROW_LABEL_INSET*2;this.matrixRowLabels.forEach((label,r)=>{const shown=this.ellipsize(ctx,label,rowLabelSpace);shown&&ctx.fillText(shown,ROW_LABEL_INSET,padTop+r*cellSize+cellSize/2+3)})}paintMatrixColLabels(ctx,padLeft,padTop,cellSize,cs){ctx.fillStyle=this.labelColor(cs),ctx.font=this.labelFont(cs);const colRotation=this.effectiveColLabelRotation,interval=finiteInteger(this.colLabelInterval,1,1);if(colRotation===0){this.matrixColLabels.forEach((label,c)=>{c%interval===0&&ctx.fillText(label,padLeft+c*cellSize+2,padTop-COL_LABEL_INSET)});return}const radians=colRotation*Math.PI/180,previousAlign=ctx.textAlign;ctx.textAlign="right",this.matrixColLabels.forEach((label,c)=>{c%interval===0&&(ctx.save(),ctx.translate(padLeft+c*cellSize+cellSize/2,padTop-COL_LABEL_INSET),ctx.rotate(radians),ctx.fillText(label,0,0),ctx.restore())}),ctx.textAlign=previousAlign}paintFrozenLabelBands(padLeft,padTop,cellSize,width,height,dpr,cs){if(this.effectiveStickyLabels==="none")return;const backdrop=this.stickyLabelBg(cs),rowBand=this.frozenBandCanvas("row-labels");rowBand&&this.paintFrozenBand(rowBand,padLeft,height,dpr,backdrop,bandCtx=>this.paintMatrixRowLabels(bandCtx,padLeft,padTop,cellSize,cs));const colBand=this.frozenBandCanvas("col-labels");colBand&&this.paintFrozenBand(colBand,width,padTop,dpr,backdrop,bandCtx=>this.paintMatrixColLabels(bandCtx,padLeft,padTop,cellSize,cs))}frozenBandCanvas(part){return this.shadowRoot?.querySelector(`[part="${part}"]`)??null}paintFrozenBand(canvas,width,height,dpr,backdrop,paint){canvas.width=width*dpr,canvas.height=height*dpr,canvas.style.width=`${width}px`,canvas.style.height=`${height}px`;const ctx=canvas.getContext("2d");ctx&&(ctx.scale(dpr,dpr),ctx.clearRect(0,0,width,height),ctx.fillStyle=backdrop,ctx.fillRect(0,0,width,height),paint(ctx))}hitTest(x,y){return this.effectiveMode==="calendar"?this.hitTestCalendar(x,y):this.hitTestMatrix(x,y)}hitTestMatrix(x,y){const rows=this.matrixRowLabels.length,cols=this.matrixColLabels.length;if(rows===0||cols===0)return null;const cellSize=this.matrixCellSize(cols),col=Math.floor((x-this.matrixPadLeft)/cellSize),row=Math.floor((y-this.matrixPadTop)/cellSize);if(row<0||row>=rows||col<0||col>=cols)return null;const shape=this.matrixCellShape(cellSize);if(shape.custom&&(x-this.matrixPadLeft-col*cellSize>=shape.w||y-this.matrixPadTop-row*cellSize>=shape.h))return null;const pos={row,col};return this.isCellInteractive(pos)?pos:null}firstInteractiveMatrixCell(rows,cols){for(let r=0;r<rows;r++)for(let c=0;c<cols;c++)if(this.isCellInteractive({row:r,col:c}))return{row:r,col:c};return null}nextInteractiveMatrixCell(row,col,dRow,dCol,rows,cols){let r=row,c=col;for(;;){const nr=Math.min(rows-1,Math.max(0,r+dRow)),nc=Math.min(cols-1,Math.max(0,c+dCol));if(nr===r&&nc===c)return{row,col};if(r=nr,c=nc,this.isCellInteractive({row:r,col:c}))return{row:r,col:c}}}firstInteractiveCalendarCell(weekCount){for(let week=0;week<weekCount;week++)for(let weekday=0;weekday<7;weekday++){const pos=this.calendarPos(week,weekday);if(this.isCellInteractive(pos))return pos}return null}nextInteractiveCalendarCell(week,weekday,dWeek,dWeekday,weekCount){let w=week,d=weekday;for(;;){const nw=Math.min(weekCount-1,Math.max(0,w+dWeek)),nd=Math.min(6,Math.max(0,d+dWeekday));if(nw===w&&nd===d)return this.calendarPos(week,weekday);w=nw,d=nd;const pos=this.calendarPos(w,d);if(this.isCellInteractive(pos))return pos}}hitTestCalendar(x,y){const{weekCount}=this.cachedCalendarGrid;if(weekCount===0)return null;const week=this.weekAtX(x,weekCount),weekday=this.weekdayAtY(y);if(week===null||weekday===null)return null;const pos=this.calendarPos(week,weekday);return this.isCellInteractive(pos)?pos:null}calendarCellAt(pos){const match=this.cachedCalendarCellsByPos.get(`${pos.week}:${pos.weekday}`);return match?{date:match.date,value:match.value}:{date:this.calendarDateAt(pos.week,pos.weekday),value:this.calendarValueAt(pos.week,pos.weekday)}}calendarValueAt(week,weekday){const match=this.cachedCalendarCellsByPos.get(`${week}:${weekday}`);return match?match.value:this.signedDomain?Number.NaN:-1}calendarDateAt(week,weekday){const index=week*7+weekday;return this.cachedCalendarDateByPos[index]??isoDateAtOffset(this.cachedCalendarGrid.firstWeekStart,index)}calendarPos(week,weekday){return{week,weekday,date:this.calendarDateAt(week,weekday)}}cellRect(pos){if("week"in pos){const cellSize2=this.calendarCellSize();return{x:this.columnXFor(pos.week),y:this.rowYFor(pos.weekday),w:cellSize2,h:cellSize2}}const cellSize=this.matrixCellSize(this.matrixColLabels.length),shape=this.matrixCellShape(cellSize);return{x:this.matrixPadLeft+pos.col*cellSize,y:this.matrixPadTop+pos.row*cellSize,w:shape.w,h:shape.h}}accessibleCellRect(pos){if("week"in pos||!this.lastPaintedMatrixGeometry)return this.cellRect(pos);const{padLeft,padTop,cellSize,cellWidth,cellHeight}=this.lastPaintedMatrixGeometry;return{x:padLeft+pos.col*cellSize,y:padTop+pos.row*cellSize,w:cellWidth??cellSize-1,h:cellHeight??cellSize-1}}defaultCellText(pos){return"week"in pos?this.calendarCellText(pos):this.matrixCellText(pos)}matrixCellText(pos){const rowLabel=this.matrixRowLabels[pos.row]??this.localize("heatmapDefaultRowLabel",void 0,{n:this.formatCount(pos.row+1)}),colLabel=this.matrixColLabels[pos.col]??this.localize("heatmapDefaultColLabel",void 0,{n:this.formatCount(pos.col+1)}),v=this.matrixValues[pos.row]?.[pos.col],valueText=v==null||this.isNoData(v)?this.localize("heatmapNoDataValue"):this.formatNumericValue(v);return this.localize("heatmapMatrixCellLabel",void 0,{row:rowLabel,col:colLabel,value:valueText})}calendarCellText(pos){const{date,value}=this.calendarCellAt(pos),label=parseIsoDate(date).toLocaleString(this.effectiveLocale||void 0,{month:"short",day:"numeric",timeZone:"UTC"}),valueText=this.isNoData(value)?this.localize("heatmapNoDataValue"):this.formatNumericValue(value);return this.localize("heatmapCalendarCellLabel",void 0,{date:label,value:valueText})}valueAt(pos){return"week"in pos?this.calendarCellAt(pos).value:this.matrixValues[pos.row]?.[pos.col]??-1}resolveCellText(pos){return this.cellText?this.cellText(pos,this.valueAt(pos)):this.defaultCellText(pos)}isCellInteractive(pos){return this.cellInteractive?.(pos,this.valueAt(pos))??!0}announce(pos,isSelectedOverride){const text=this.resolveCellText(pos),announcement=isSelectedOverride??this.isSelectedPos(pos)?this.localize("heatmapSelectedCellLabel",void 0,{cell:text}):text;this.liveText=announcement,this.announcementSink?.announce(announcement)}emitCellClick(pos,source="pointer",select=!0){if(this.isCellInteractive(pos))if(this.multiple&&select&&(this.selectionAnchor=pos,this.selectionRangeBase=void 0,this.toggleSelectionPositions([pos],source)),"week"in pos){const{date,value}=this.calendarCellAt(pos);this.emit("lr-cell-click",{date,value})}else{const value=this.matrixValues[pos.row]?.[pos.col]??-1;this.emit("lr-cell-click",{row:pos.row,col:pos.col,value})}}get currentSelectedPositions(){return this.selectionPreview??this.selectedPositions}selectedPaintPositions(){if(this.multiple)return[...this.currentSelectedPositions.values()];const selected=this.selectedCell;if(!selected)return[];if(this.effectiveMode==="calendar"){const match=selected.date?this.cachedCalendarCellsByDate.get(selected.date):void 0;return match?[match]:[]}return selected.row!=null&&selected.col!=null?[{row:selected.row,col:selected.col}]:[]}rebuildSelectedPositions(){const positions=new Map,dates=this.effectiveMode==="calendar"?new Map(this.cachedAccessiblePositions.map(pos=>[this.accessibleCellIdentity(pos),pos])):void 0,input=Array.isArray(this.selectedCells)?this.selectedCells:[];for(const cell of input.slice(0,MAX_HEATMAP_CELLS)){if(!cell||typeof cell!="object")continue;const pos=dates?typeof cell.date=="string"?dates.get(cell.date):void 0:Number.isInteger(cell.row)&&Number.isInteger(cell.col)?this.cachedAccessiblePositionsByKey.get(`matrix-${cell.row}-${cell.col}`):void 0;pos&&positions.set(this.accessibleCellKey(pos),pos)}this.selectedPositions=positions}selectionCoordinates(pos){return"week"in pos?{row:pos.weekday,col:pos.week}:pos}proposeSelection(positions,source){if(positions.size===this.selectedPositions.size&&[...positions.keys()].every(key=>this.selectedPositions.has(key)))return;this.proposedSelectionKeys=new Set(positions.keys());const selectedCells=[...positions.values()].sort((a,b)=>{const first=this.selectionCoordinates(a),second=this.selectionCoordinates(b);return first.row-second.row||first.col-second.col}).map(pos=>"week"in pos?{date:pos.date}:{row:pos.row,col:pos.col});this.emit("lr-selection-change",{selectedCells,source})}toggleSelectionPositions(positions,source){if(!this.multiple||positions.length===0)return;const next=new Map(this.selectedPositions),remove=positions.every(pos=>next.has(this.accessibleCellKey(pos)));for(const pos of positions){const key=this.accessibleCellKey(pos);remove?next.delete(key):next.set(key,pos)}this.proposeSelection(next,source)}toggleSelectionAxis(index,row){!this.multiple||!Number.isInteger(index)||index<0||(this.cancelSelectionGesture(),this.selectionRangeBase=void 0,this.toggleSelectionPositions(this.cachedAccessiblePositions.filter(pos=>{const coordinates=this.selectionCoordinates(pos);return(row?coordinates.row:coordinates.col)===index}),row?"row":"column"))}selectionKeyDown(event,pos){if(!this.multiple)return!1;if(event.key==="Escape"&&this.selectionGesture)return event.preventDefault(),this.cancelSelectionGesture(),!0;if(event.key!==" "||!pos||!(event.shiftKey||event.ctrlKey||event.metaKey))return!1;event.preventDefault();const coordinates=this.selectionCoordinates(pos);return event.ctrlKey||event.metaKey?this.toggleColumnSelection(coordinates.col):this.toggleRowSelection(coordinates.row),!0}extendSelection(previous,next,range){if(!this.multiple)return;if(!range){this.selectionAnchor=next,this.selectionRangeBase=void 0;return}this.selectionAnchor??=previous??next,this.selectionRangeBase??=new Map(this.selectedPositions);const from=this.selectionCoordinates(this.selectionAnchor),to=this.selectionCoordinates(next),selected=new Map(this.selectionRangeBase);for(const pos of this.cachedAccessiblePositions){const{row,col}=this.selectionCoordinates(pos);row>=Math.min(from.row,to.row)&&row<=Math.max(from.row,to.row)&&col>=Math.min(from.col,to.col)&&col<=Math.max(from.col,to.col)&&selected.set(this.accessibleCellKey(pos),pos)}return this.proposeSelection(selected,"keyboard"),new Set(selected.keys())}selectionPointerPosition(event){if(!this.canvas)return null;const rect=this.canvas.getBoundingClientRect();return this.hitTest(event.clientX-rect.left,event.clientY-rect.top)}paintSelectionTo(pos){const gesture=this.selectionGesture;if(!gesture)return;this.samePos(pos,gesture.previous)||(gesture.moved=!0);const from=this.selectionCoordinates(gesture.previous),to=this.selectionCoordinates(pos),steps=Math.max(Math.abs(to.row-from.row),Math.abs(to.col-from.col),1);for(let step=0;step<=steps;step++){const row=Math.round(from.row+(to.row-from.row)*step/steps),col=Math.round(from.col+(to.col-from.col)*step/steps),key=this.effectiveMode==="calendar"?`calendar-${col}-${row}`:`matrix-${row}-${col}`,candidate=this.cachedAccessiblePositionsByKey.get(key);candidate&&(gesture.selecting?gesture.cells.set(key,candidate):gesture.cells.delete(key))}gesture.previous=pos,this.selectionPreview=new Map(gesture.cells)}cancelSelectionGesture(){const gesture=this.selectionGesture;if(this.selectionGesture=void 0,this.selectionPreview=void 0,!!gesture){this.suppressSelectionClick=!0;try{gesture.target.hasPointerCapture(gesture.pointerId)&&gesture.target.releasePointerCapture(gesture.pointerId)}catch{}}}consumeSelectionClick(event){return!this.suppressSelectionClick||event.detail===0?!1:(this.suppressSelectionClick=!1,!0)}get gridScrollport(){return this.shadowRoot?.querySelector('[part="grid"]')??null}measureTooltip(){if(!this.gridScrollport)return;const tooltip=this.shadowRoot?.querySelector('[part="tooltip"]');if(!tooltip||tooltip.hidden)return;const view=this.ownerDocument.defaultView,gap=view?Math.abs(finiteNumber(Number.parseFloat(view.getComputedStyle(tooltip).marginBlockStart),0)):0,inline=tooltip.offsetWidth,block=tooltip.offsetHeight+gap;inline===this.tooltipSize.inline&&block===this.tooltipSize.block||(this.tooltipSize={inline,block},this.requestUpdate())}tooltipAnchor(pos){const rect=this.cellRect(pos),center=rect.x+rect.w/2,port=this.gridScrollport;if(!port)return{style:{left:`${center}px`,top:`${rect.y}px`},below:!1};const{inline,block}=this.tooltipSize,windowStart=port.scrollLeft+(this.freezesRowLabels?this.matrixPadLeft:0),windowEnd=port.scrollLeft+port.clientWidth,windowTop=port.scrollTop+(this.freezesColLabels?this.matrixPadTop:0),windowBottom=port.scrollTop+port.clientHeight,below=rect.y-block<windowTop&&rect.y+rect.h+block<=windowBottom;return{style:{left:`${Math.max(windowStart+inline/2,Math.min(center,windowEnd-inline/2))}px`,top:`${below?rect.y+rect.h:rect.y}px`},below}}scrollCellIntoView(pos){const port=this.gridScrollport;if(!port)return;const rect=this.cellRect(pos),bandInline=this.freezesRowLabels?this.matrixPadLeft:0,bandBlock=this.freezesColLabels?this.matrixPadTop:0,left=Math.min(Math.max(port.scrollLeft,rect.x+rect.w-port.clientWidth),rect.x-bandInline),top=Math.min(Math.max(port.scrollTop,rect.y+rect.h-port.clientHeight),rect.y-bandBlock);left!==port.scrollLeft&&(port.scrollLeft=left),top!==port.scrollTop&&(port.scrollTop=top)}samePos(a,b){return a===b?!0:!a||!b?!1:"week"in a&&"week"in b?a.week===b.week&&a.weekday===b.weekday:"row"in a&&"row"in b?a.row===b.row&&a.col===b.col:!1}onMatrixKeyDown(e){const rows=this.matrixRowLabels.length,cols=this.matrixColLabels.length;if(rows===0||cols===0)return;if(e.key==="Enter"||e.key===" "){e.preventDefault(),this.focusedCell&&this.emitCellClick(this.focusedCell,"keyboard");return}if(!ARROW_KEYS.has(e.key))return;if(e.preventDefault(),!this.focusedCell||!("row"in this.focusedCell)){const next2=this.firstInteractiveMatrixCell(rows,cols);if(!next2)return;this.focusedCell=next2,this.scrollCellIntoView(next2);return}const{row,col}=this.focusedCell;let dRow=0,dCol=0;e.key==="ArrowUp"?dRow=-1:e.key==="ArrowDown"?dRow=1:e.key==="ArrowLeft"?dCol=-1:e.key==="ArrowRight"&&(dCol=1);const next=this.nextInteractiveMatrixCell(row,col,dRow,dCol,rows,cols);this.focusedCell=next,this.scrollCellIntoView(next)}onCalendarKeyDown(e){const{weekCount}=this.cachedCalendarGrid;if(weekCount===0)return;if(e.key==="Enter"||e.key===" "){e.preventDefault(),this.focusedCell&&this.emitCellClick(this.focusedCell,"keyboard");return}if(!ARROW_KEYS.has(e.key))return;if(e.preventDefault(),!this.focusedCell||!("week"in this.focusedCell)){const next2=this.firstInteractiveCalendarCell(weekCount);if(!next2)return;this.focusedCell=next2;return}const{week,weekday}=this.focusedCell;let dWeek=0,dWeekday=0;e.key==="ArrowUp"?dWeekday=-1:e.key==="ArrowDown"?dWeekday=1:e.key==="ArrowLeft"?dWeek=-1:e.key==="ArrowRight"&&(dWeek=1);const next=this.nextInteractiveCalendarCell(week,weekday,dWeek,dWeekday,weekCount);this.focusedCell=next}resolveCanvasColor(value,cs){const cached=this.canvasColorCache.get(value);if(cached!==void 0)return cached;const fallback=this.noDataFill(cs);let candidate=value;if(value.includes("var(")){if(this.colorProbe||(this.colorProbe=this.ownerDocument.createElement("span"),this.colorProbe.style.cssText="position:absolute;width:0;height:0;overflow:hidden;visibility:hidden;pointer-events:none;",this.shadowRoot.appendChild(this.colorProbe)),this.colorProbe.style.color="",this.colorProbe.style.color=value,!this.colorProbe.style.color)return this.canvasColorCache.set(value,fallback),fallback;candidate=this.ownerDocument.defaultView?.getComputedStyle(this.colorProbe).color||fallback}const ctx=getScratchCtx(this.ownerDocument);if(!ctx)return fallback;ctx.fillStyle="rgb(1, 2, 3)";const firstSentinel=ctx.fillStyle;ctx.fillStyle=candidate;let resolved=ctx.fillStyle;if(resolved===firstSentinel){ctx.fillStyle="rgb(4, 5, 6)";const secondSentinel=ctx.fillStyle;ctx.fillStyle=candidate,resolved=ctx.fillStyle,resolved===secondSentinel&&(resolved=fallback)}return this.canvasColorCache.set(value,resolved),resolved}rebuildAccessiblePositions(){const positions=[];if(this.effectiveMode==="calendar"){const{weekCount}=this.cachedCalendarGrid;for(let week=0;week<weekCount;week++)for(let weekday=0;weekday<7;weekday++){const pos=this.calendarPos(week,weekday);this.isCellInteractive(pos)&&positions.push(pos)}}else for(let row=0;row<this.matrixRowLabels.length;row++)for(let col=0;col<this.matrixColLabels.length;col++){const pos={row,col};this.isCellInteractive(pos)&&positions.push(pos)}this.cachedAccessiblePositions=positions,this.cachedAccessiblePositionsByKey=new Map(positions.map(position=>[this.accessibleCellKey(position),position])),this.cachedAccessiblePositionIndexByKey=new Map(positions.map((position,index)=>[this.accessibleCellKey(position),index]))}accessibleCellPositions(){return this.cachedAccessiblePositions}accessibleCellKey(pos){return"week"in pos?`calendar-${pos.week}-${pos.weekday}`:`matrix-${pos.row}-${pos.col}`}accessibleCellIdentity(pos){return"week"in pos?pos.date:this.accessibleCellKey(pos)}accessibleCellAtKey(key){return this.cachedAccessiblePositionsByKey.get(key)??null}focusAccessibleCell(pos){pos&&this.updateComplete.then(()=>{[...this.shadowRoot?.querySelectorAll('[part="cell"]')??[]].find(candidate=>candidate.dataset.cellKey===this.accessibleCellKey(pos))?.focus()})}renderAccessibleCells(){if(!this.accessibleCells)return html``;const positions=this.accessibleCellPositions(),tabStop=this.focusedCell??positions[0]??null,focusIndex=tabStop?this.cachedAccessiblePositionIndexByKey.get(this.accessibleCellKey(tabStop))??0:0,start=Math.max(0,Math.min(Math.max(0,positions.length-MAX_ACCESSIBLE_HEATMAP_CELLS),focusIndex-Math.floor(MAX_ACCESSIBLE_HEATMAP_CELLS/2))),renderedPositions=positions.slice(start,start+MAX_ACCESSIBLE_HEATMAP_CELLS),renderedRows=new Map;for(const pos of renderedPositions){const rowIndex="week"in pos?pos.weekday+1:pos.row+1,row=renderedRows.get(rowIndex);row?row.push(pos):renderedRows.set(rowIndex,[pos])}const rowCount=this.effectiveMode==="calendar"?7:this.matrixRowLabels.length,colCount=this.effectiveMode==="calendar"?this.cachedCalendarGrid.weekCount:this.matrixColLabels.length;return html`
1
+ var __decorate=function(decorators,target,key,desc){var c=arguments.length,r=c<3?target:desc===null?desc=Object.getOwnPropertyDescriptor(target,key):desc,d;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")r=Reflect.decorate(decorators,target,key,desc);else for(var i=decorators.length-1;i>=0;i--)(d=decorators[i])&&(r=(c<3?d(r):c>3?d(target,key,r):d(target,key))||r);return c>3&&r&&Object.defineProperty(target,key,r),r};import{html,nothing}from"lit";import{property,query,state}from"lit/decorators.js";import{styleMap}from"lit/directives/style-map.js";import{LyraElement}from"../../../internal/lyra-element.js";import{srOnly}from"../../../internal/a11y.js";import{finiteInteger,finiteNumber,finiteRange}from"../../../internal/numbers.js";import{getScratchCtx}from"../../../internal/canvas.js";import{resolveCssLength}from"../../../internal/css-length.js";import{ThemeWatcher}from"../../../internal/theme-watcher.js";import{activeElementIn}from"../../../internal/active-element.js";import{linearAlpha,linearBucket,midpointAlpha,midpointBucket,minMax,sqrtStep}from"./heatmap-scale.js";import{styles}from"./heatmap.styles.js";import{buildCalendarGrid,parseIsoDate,quartileBucket}from"./calendar-grid.js";import{getDateTimeFormat,getNumberFormat}from"../../../internal/intl-cache.js";import{sanitizeCssColor}from"../../../internal/safe-css.js";import{literalSetConverter}from"../../../internal/converters.js";import{devWarnOnce}from"../../../internal/dev-mode-attribute-warning.js";import{acquireAnnouncementSink}from"../../../internal/announcer.js";import{LYRA_DEFAULT_heatmapCalendarCellLabel,LYRA_DEFAULT_heatmapCalendarLabel,LYRA_DEFAULT_heatmapDecorationLimit,LYRA_DEFAULT_heatmapDefaultColLabel,LYRA_DEFAULT_heatmapDefaultRowLabel,LYRA_DEFAULT_heatmapMatrixCellLabel,LYRA_DEFAULT_heatmapMatrixLabel,LYRA_DEFAULT_heatmapNoDataValue,LYRA_DEFAULT_heatmapProjectionLimit,LYRA_DEFAULT_heatmapSelectedCellLabel,LYRA_DEFAULT_heatmapSelectedCount,LYRA_DEFAULT_heatmapValueLabel}from"../../../internal/default-strings.generated.js";const PAD_LEFT=60,PAD_TOP=20,ROW_LABEL_INSET=4,MAX_ROW_LABEL_FRACTION=.4,MAX_COL_LABEL_HEIGHT=240,COL_LABEL_INSET=6,labelExtentConverter={fromAttribute:value=>{if(value===null)return;const trimmed=value.trim();if(trimmed.toLowerCase()==="auto")return"auto";const parsed=Number.parseFloat(trimmed);return Number.isFinite(parsed)&&parsed>=0?parsed:void 0},toAttribute:value=>value===void 0?null:String(value)},STICKY_LABELS=literalSetConverter(["none","rows","cols","both"],"none"),FALLBACK_NO_DATA_FILL="rgba(128,128,128,0.25)",FALLBACK_STICKY_LABEL_BG="#ffffff",RAMP_STEPS=7,FALLBACK_SCALE_LO="#cde2fb",FALLBACK_SCALE_HI="#0969da",FALLBACK_LABEL_FONT="10px system-ui, sans-serif",CAL_PAD_LEFT=28,CAL_WEEKDAY_LABEL_INSET=2,CAL_LABEL_H=16,CAL_CELL=11,CAL_GAP=2,DEFAULT_MATRIX_CELL_SIZE=22,DEFAULT_ACCESSIBLE_TARGET_SIZE_PX=40,DEFAULT_BUCKET_COUNT=5,FIT_MIN_CELL=4,MAX_BUCKET_COUNT=256,MAX_HEATMAP_CELLS=1e4,MAX_HEATMAP_DECORATIONS=256,MAX_ACCESSIBLE_HEATMAP_CELLS=400,RING_LINE_WIDTH=2,FALLBACK_FOCUS_RING_COLOR="#0969da",FALLBACK_ANNOTATION_COLOR="#cf222e",FALLBACK_SELECTED_COLOR="#1a7f37",ARROW_KEYS=new Set(["ArrowUp","ArrowDown","ArrowLeft","ArrowRight"]),MS_PER_DAY=864e5;function isoDateAtOffset(firstWeekStart,dayOffset){return new Date(firstWeekStart.getTime()+dayOffset*MS_PER_DAY).toISOString().slice(0,10)}function legendStopsChanged(value,previous){if(Object.is(value,previous))return!1;if(!Array.isArray(value)||!Array.isArray(previous)||value.length!==previous.length)return!0;for(let index=0;index<value.length;index+=1){if(Object.hasOwn(value,index)!==Object.hasOwn(previous,index))return!0;const next=value[index],before=previous[index];if(!next||!before){if(!Object.is(next,before))return!0;continue}if(!Object.is(next.value,before.value)||!Object.is(next.color,before.color)||!Object.is(next.label,before.label)||!Object.is(next.partOfRamp,before.partOfRamp))return!0}return!1}const HEX_RE=/^([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i,RGB_RE=/^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([\d.]+))?\s*\)/i;function hexToRgb(hex){const clean=hex.trim().replace("#","");if(!HEX_RE.test(clean))return null;const hasAlpha=clean.length===4||clean.length===8,full=clean.length<=4?clean.split("").map(c=>c+c).join(""):clean,num=Number.parseInt(full,16);return hasAlpha?[num>>>24&255,num>>>16&255,num>>>8&255,(num&255)/255]:[num>>16&255,num>>8&255,num&255,1]}function parseRgbString(value){const match=RGB_RE.exec(value);if(!match)return null;const a=match[4]===void 0?1:Number(match[4]);return[Number(match[1]),Number(match[2]),Number(match[3]),a]}function resolveViaPixelReadback(ctx){try{ctx.clearRect(0,0,1,1),ctx.fillRect(0,0,1,1);const[r=0,g=0,b=0,a=0]=ctx.getImageData(0,0,1,1).data;return[r,g,b,a/255]}catch{return null}}function formatRgb([r,g,b,a]){const alpha=Math.min(1,Math.max(0,a));return alpha>=1?`rgb(${r}, ${g}, ${b})`:`rgba(${r}, ${g}, ${b}, ${Math.round(alpha*1e3)/1e3})`}function warnInvalidColor(color){devWarnOnce(`heatmap-invalid-color:${color}`,`<lr-heatmap> could not parse "${color}" (set via --lr-heatmap-scale-lo/-hi) as a CSS color; falling back to the default ramp endpoint.`)}let warnedNoCanvasContext=!1;function warnNoCanvasContext(){warnedNoCanvasContext||(warnedNoCanvasContext=!0,console.warn("<lr-heatmap>: no 2D canvas context is available in this environment; color resolution for non-hex/non-rgb values (e.g. oklch(), color(srgb ...), named colors) will fall back to the given default instead of resolving the requested color."))}function normalizeBucketCount(bucketCount){return finiteInteger(bucketCount,DEFAULT_BUCKET_COUNT,2,MAX_BUCKET_COUNT)}const optionalCellSizeConverter={fromAttribute(value){if(value===null||value.trim()==="")return;const parsed=Number(value);return Number.isFinite(parsed)?parsed:void 0}},DEFAULT_MATRIX_DATA=Object.freeze({kind:"matrix",rowLabels:Object.freeze([]),colLabels:Object.freeze([]),values:Object.freeze([])});function normalizeCellSizeClamp(value){if(!(value==null||!Number.isFinite(value)))return finiteRange(value,FIT_MIN_CELL,FIT_MIN_CELL)}const bucketCountConverter={fromAttribute(value){return value===null?DEFAULT_BUCKET_COUNT:normalizeBucketCount(Number(value))}};function resolveRgb(color,fallbackHex,ownerDocument){const fallback=hexToRgb(fallbackHex)??[0,0,0,1],direct=hexToRgb(color);if(direct)return direct;const ctx=getScratchCtx(ownerDocument);if(!ctx)return warnNoCanvasContext(),fallback;const sentinel="rgb(1, 2, 3)";ctx.fillStyle=sentinel;const sentinelNormalized=ctx.fillStyle;if(ctx.fillStyle=color,ctx.fillStyle===sentinelNormalized&&color.trim()!==sentinel)return warnInvalidColor(color),fallback;const normalized=ctx.fillStyle;return hexToRgb(normalized)??parseRgbString(normalized)??resolveViaPixelReadback(ctx)??fallback}function mixRgb(from,to,t){const clamped=Math.min(1,Math.max(0,t)),r=Math.round(from[0]+(to[0]-from[0])*clamped),g=Math.round(from[1]+(to[1]-from[1])*clamped),b=Math.round(from[2]+(to[2]-from[2])*clamped),a=from[3]+(to[3]-from[3])*clamped;return formatRgb([r,g,b,a])}class LyraHeatmap extends LyraElement{static{this.defaultStrings={...super.defaultStrings,heatmapCalendarCellLabel:LYRA_DEFAULT_heatmapCalendarCellLabel,heatmapCalendarLabel:LYRA_DEFAULT_heatmapCalendarLabel,heatmapDecorationLimit:LYRA_DEFAULT_heatmapDecorationLimit,heatmapDefaultColLabel:LYRA_DEFAULT_heatmapDefaultColLabel,heatmapDefaultRowLabel:LYRA_DEFAULT_heatmapDefaultRowLabel,heatmapMatrixCellLabel:LYRA_DEFAULT_heatmapMatrixCellLabel,heatmapMatrixLabel:LYRA_DEFAULT_heatmapMatrixLabel,heatmapNoDataValue:LYRA_DEFAULT_heatmapNoDataValue,heatmapProjectionLimit:LYRA_DEFAULT_heatmapProjectionLimit,heatmapSelectedCellLabel:LYRA_DEFAULT_heatmapSelectedCellLabel,heatmapSelectedCount:LYRA_DEFAULT_heatmapSelectedCount,heatmapValueLabel:LYRA_DEFAULT_heatmapValueLabel}}static{this.immutableEventDetails=Object.freeze(["lr-selection-change"])}static{this.ownedCollectionProperties=Object.freeze(["data","annotations","legendStops","colorSteps","selectedCells"])}static{this.identityCollectionObjectProperties=Object.freeze(["data"])}static{this.styles=[LyraElement.styles,styles,srOnly]}static get observedAttributes(){return[...new Set([...super.observedAttributes,"role"])]}get effectiveMode(){return this.data.kind}get stickyLabels(){return this._stickyLabels}set stickyLabels(next){const normalized=STICKY_LABELS.normalizeReflected(this,"sticky-labels",next),old=this._stickyLabels;old!==normalized&&(this._stickyLabels=normalized,this.requestUpdate("stickyLabels",old))}get effectiveStickyLabels(){return this.effectiveMode==="matrix"?this._stickyLabels:"none"}get freezesRowLabels(){const sticky=this.effectiveStickyLabels;return sticky==="rows"||sticky==="both"}get freezesColLabels(){const sticky=this.effectiveStickyLabels;return sticky==="cols"||sticky==="both"}get effectiveColLabelRotation(){if(typeof this.colLabelRotation!="number")return 0;const degrees=finiteNumber(this.colLabelRotation,0);return Math.min(90,Math.max(0,degrees))}get matrixPadLeft(){if(this.rowLabelWidth==="auto")return this.resolvedRowLabelWidth;if(typeof this.rowLabelWidth!="number")return PAD_LEFT;const resolved=finiteNumber(this.rowLabelWidth,PAD_LEFT);return resolved>=0?resolved:PAD_LEFT}get matrixGeometry(){if(this.effectiveMode==="matrix")return this.lastPaintedMatrixGeometry}exportData(format){if(format!=="png"||!this.canvasHasContent||!this.canvas||this.canvas.width<=0||this.canvas.height<=0)return"";try{const rowBand=this.frozenBandCanvas("row-labels"),colBand=this.frozenBandCanvas("col-labels");if(!rowBand&&!colBand)return this.canvas.toDataURL("image/png");const composite=this.ownerDocument.createElement("canvas");composite.width=this.canvas.width,composite.height=this.canvas.height;const context=composite.getContext("2d");return context?(context.drawImage(this.canvas,0,0),rowBand&&rowBand.width>0&&rowBand.height>0&&context.drawImage(rowBand,0,0),colBand&&colBand.width>0&&colBand.height>0&&context.drawImage(colBand,0,0),composite.toDataURL("image/png")):""}catch{return""}}get matrixPadTop(){if(this.colLabelHeight==="auto")return this.resolvedColLabelHeight;if(typeof this.colLabelHeight!="number")return PAD_TOP;const resolved=finiteNumber(this.colLabelHeight,PAD_TOP);return resolved>=0?resolved:PAD_TOP}measureColLabelHeight(cs){const labels=this.matrixColLabels;if(labels.length===0)return PAD_TOP;const ctx=getScratchCtx(this.ownerDocument);if(!ctx)return PAD_TOP;ctx.font=this.labelFont(cs);let widest=0;const interval=finiteInteger(this.colLabelInterval,1,1);for(let index=0;index<labels.length;index+=interval)widest=Math.max(widest,ctx.measureText(labels[index]).width);const radians=this.effectiveColLabelRotation*Math.PI/180,projected=widest*Math.sin(radians);return Math.max(PAD_TOP,Math.min(Math.ceil(projected)+COL_LABEL_INSET,MAX_COL_LABEL_HEIGHT))}measureRowLabelWidth(cs){const labels=this.matrixRowLabels;if(labels.length===0)return PAD_LEFT;const ctx=getScratchCtx(this.ownerDocument);if(!ctx)return PAD_LEFT;ctx.font=this.labelFont(cs);let widest=0;for(const label of labels)widest=Math.max(widest,ctx.measureText(label).width);const hostWidth=this.clientWidth||0,cap=hostWidth>0?hostWidth*MAX_ROW_LABEL_FRACTION:Number.POSITIVE_INFINITY;return Math.min(Math.max(PAD_LEFT,Math.ceil(widest)+ROW_LABEL_INSET*2),cap)}ellipsize(ctx,label,maxWidth){if(maxWidth<=0)return"";if(ctx.measureText(label).width<=maxWidth)return label;const characters=[...label];let kept=characters.length-1;for(;kept>0;){const candidate=`${characters.slice(0,kept).join("")}…`;if(ctx.measureText(candidate).width<=maxWidth)return candidate;kept-=1}return ctx.measureText("…").width<=maxWidth?"…":""}get calendarPadLeft(){const requested=this.calendarWeekdayLabelWidth;return requested==="auto"?this.resolvedCalendarWeekdayLabelWidth:requested??CAL_PAD_LEFT}measureCalendarWeekdayLabelWidth(cs,firstWeekStart){const ctx=getScratchCtx(this.ownerDocument);if(!ctx)return CAL_PAD_LEFT;ctx.font=this.labelFont(cs);let widest=0;for(const label of this.weekdayLabels(firstWeekStart))label&&(widest=Math.max(widest,ctx.measureText(label).width));const hostWidth=this.clientWidth||0,cap=hostWidth>0?Math.max(CAL_PAD_LEFT,hostWidth*MAX_ROW_LABEL_FRACTION):Number.POSITIVE_INFINITY;return Math.min(Math.max(CAL_PAD_LEFT,Math.ceil(widest)+CAL_WEEKDAY_LABEL_INSET*2),cap)}get matrixRowLabels(){return this.cachedMatrixData.rowLabels}get matrixColLabels(){return this.cachedMatrixData.colLabels}get matrixValues(){return this.cachedMatrixData.values}get calendarDays(){return this.data.kind==="calendar"?this.data.days:[]}get calendarData(){return this.data.kind==="calendar"?this.data:void 0}get cellSize(){return this._cellSize??(this.effectiveMode==="calendar"?CAL_CELL:DEFAULT_MATRIX_CELL_SIZE)}set cellSize(value){const oldValue=this._cellSize;this._cellSize=value==null?void 0:finiteRange(value,this.effectiveMode==="calendar"?CAL_CELL:DEFAULT_MATRIX_CELL_SIZE,1),this.requestUpdate("cellSize",oldValue)}get signedDomain(){return this.domain!==void 0||this.midpoint!==void 0}rampAlpha(value,lo,hi){const anchor=this.midpoint;return anchor===void 0?linearAlpha(value,lo,hi):midpointAlpha(value,lo,hi,anchor)}rampBucket(value,lo,hi,steps){const anchor=this.midpoint;return anchor===void 0?linearBucket(value,lo,hi,steps):midpointBucket(value,lo,hi,anchor,steps)}isNoData(value){return Number.isFinite(value)?value<0&&!this.signedDomain:!0}get maxCellSize(){return this._maxCellSize}set maxCellSize(value){const oldValue=this._maxCellSize;this._maxCellSize=normalizeCellSizeClamp(value),this.requestUpdate("maxCellSize",oldValue)}get minCellSize(){return this._minCellSize}set minCellSize(value){const oldValue=this._minCellSize;this._minCellSize=normalizeCellSizeClamp(value),this.requestUpdate("minCellSize",oldValue)}get normalizedFirstDayOfWeek(){return(finiteInteger(this.calendarData?.firstDayOfWeek??0,0)%7+7)%7}get bucketCount(){return this._bucketCount}set bucketCount(value){const oldValue=this._bucketCount;this._bucketCount=normalizeBucketCount(value),this.requestUpdate("bucketCount",oldValue)}toggleRowSelection(row){this.toggleSelectionAxis(row,!0)}toggleColumnSelection(col){this.toggleSelectionAxis(col,!1)}get calendarWeekdayLabelText(){return this.calendarData?.weekdayLabelText}get calendarWeekdayLabelWidth(){const value=this.calendarData?.weekdayLabelWidth;if(value==="auto")return value;if(typeof value!="number")return;const resolved=finiteNumber(value,CAL_PAD_LEFT);return resolved>=0?resolved:void 0}get calendarMonthLabelText(){return this.calendarData?.monthLabelText}get calendarColumnX(){return this.calendarData?.columnX}get calendarRowY(){return this.calendarData?.rowY}constructor(){super(),this.data=DEFAULT_MATRIX_DATA,this._stickyLabels="none",this.resolvedColLabelHeight=PAD_TOP,this.resolvedRowLabelWidth=PAD_LEFT,this.resolvedCalendarWeekdayLabelWidth=CAL_PAD_LEFT,this.withoutLegend=!1,this.scale="linear",this.cellGapX=1,this.cellGapY=1,this.cellRadius=0,this.colLabelInterval=1,this.fitToWidth=!1,this._bucketCount=DEFAULT_BUCKET_COUNT,this.annotations=[],this.selectedCell=null,this.multiple=!1,this.selectedCells=[],this.accessibleCells=!1,this.cachedValueRange=null,this.cachedMatrixData={rowLabels:[],colLabels:[],values:[],truncated:!1},this.cachedCalendarGrid=buildCalendarGrid(this.calendarDays),this.cachedCalendarSortedValues=[],this.cachedCalendarCellsByPos=new Map,this.cachedCalendarCellsByDate=new Map,this.cachedAnnotations=[],this.cachedLegendStops=[],this.cachedColorSteps=[],this.cachedCalendarAnnotationDates=new Set,this.cachedMatrixAnnotationPositions=new Set,this.decorationProjectionTruncated=!1,this.cachedCalendarDateByPos=[],this.cachedAccessiblePositions=[],this.cachedAccessiblePositionsByKey=new Map,this.cachedAccessiblePositionIndexByKey=new Map,this.cachedRamp=null,this.canvasHasContent=!1,this.canvasVisible=!0,this.drawDirty=!1,this.hoverCell=null,this.focusedCell=null,this.liveText="",this.accessibleTargetSizePx=DEFAULT_ACCESSIBLE_TARGET_SIZE_PX,this.restoringAccessibleFocus=!1,this.accessibleFocusGeneration=0,this.authorRole=null,this.authorAriaLabel=null,this.generatedAriaLabel="",this.syncingGeneratedSemantics=!1,this.onDprChange=()=>{this.watchDpr(),this.requestDraw()},this.scheduleDraw=()=>{if(this.drawFrameRequest)return;const owner=this.ownerDocument.defaultView;if(!owner||!this.isConnected)return;const request={owner,handle:0};request.handle=owner.requestAnimationFrame(()=>{this.drawFrameRequest===request&&(this.drawFrameRequest=void 0,this.isConnected&&this.ownerDocument.defaultView===owner&&this.requestDraw())}),this.drawFrameRequest=request},this.selectedPositions=new Map,this.selectionAnchor=null,this.suppressSelectionClick=!1,this.onSelectionPointerDown=event=>{if(!this.multiple||event.button!==0||!event.isPrimary||this.selectionGesture)return;const pos=this.selectionPointerPosition(event);if(!pos)return;event.preventDefault(),this.suppressSelectionClick=!1,this.selectionRangeBase=void 0,this.selectionAnchor=pos,this.focusedCell=pos,this.accessibleCells?this.focusAccessibleCell(pos):this.canvas?.focus();const target=event.currentTarget;this.selectionGesture={pointerId:event.pointerId,target,start:pos,previous:pos,moved:!1,selecting:!this.selectedPositions.has(this.accessibleCellKey(pos)),cells:new Map(this.selectedPositions)};try{target.setPointerCapture(event.pointerId)}catch{}this.paintSelectionTo(pos)},this.onSelectionPointerMove=event=>{if(this.selectionGesture?.pointerId!==event.pointerId)return;const pos=this.selectionPointerPosition(event);pos&&!this.samePos(pos,this.selectionGesture.previous)&&this.paintSelectionTo(pos)},this.onSelectionPointerUp=event=>{const gesture=this.selectionGesture;if(!gesture||gesture.pointerId!==event.pointerId)return;const pos=this.selectionPointerPosition(event);pos&&this.paintSelectionTo(pos),this.cancelSelectionGesture(),this.proposeSelection(gesture.cells,"pointer"),gesture.moved||this.emitCellClick(gesture.start,"pointer",!1)},this.onSelectionPointerCancel=event=>{this.selectionGesture?.pointerId===event.pointerId&&this.cancelSelectionGesture()},this.tooltipSize={inline:0,block:0},this.onPointerMove=e=>{const next=this.hitTest(e.offsetX,e.offsetY);this.samePos(this.hoverCell,next)||(this.hoverCell=next)},this.onPointerLeave=()=>{this.hoverCell=null},this.onCanvasClick=e=>{if(this.consumeSelectionClick(e))return;const pos=this.hitTest(e.offsetX,e.offsetY);pos&&(this.focusedCell=pos,this.announce(pos),this.emitCellClick(pos))},this.onKeyDown=e=>{if(this.selectionKeyDown(e,this.focusedCell))return;const previous=this.focusedCell;if(this.effectiveMode==="calendar"?this.onCalendarKeyDown(e):this.onMatrixKeyDown(e),ARROW_KEYS.has(e.key)&&this.focusedCell){const proposedKeys=this.extendSelection(previous,this.focusedCell,e.shiftKey);this.announce(this.focusedCell,proposedKeys?.has(this.accessibleCellKey(this.focusedCell)))}},this.canvasColorCache=new Map,this.onAccessibleCellFocus=e=>{if(this.restoringAccessibleFocus)return;const key=e.currentTarget.dataset.cellKey,pos=key?this.accessibleCellAtKey(key):null;pos&&(this.samePos(pos,this.focusedCell)||(this.selectionAnchor=pos,this.selectionRangeBase=void 0),this.focusedCell=pos,this.announce(pos))},this.onAccessibleCellClick=e=>{if(this.consumeSelectionClick(e))return;const key=e.currentTarget.dataset.cellKey,pos=key?this.accessibleCellAtKey(key):null;pos&&(this.focusedCell=pos,this.announce(pos),this.emitCellClick(pos,e.detail===0?"keyboard":"pointer"))},this.onAccessibleCellKeyDown=e=>{const key=e.currentTarget.dataset.cellKey,pos=key?this.accessibleCellAtKey(key):null;pos&&(this.selectionKeyDown(e,pos)||ARROW_KEYS.has(e.key)&&(e.preventDefault(),this.focusedCell=pos,this.onKeyDown(e),this.focusAccessibleCell(this.focusedCell)))},new ThemeWatcher(this,()=>this.refreshTheme())}warnOnLegendRampMismatch(){const rampColors=this.cachedColorSteps.map(color=>sanitizeCssColor(color)??color);if(rampColors.length===0)return;const legendColors=this.cachedLegendStops.filter(stop=>!!stop.color&&stop.partOfRamp!==!1).map(stop=>sanitizeCssColor(stop.color??"")??stop.color??"");legendColors.length===0||legendColors.length===rampColors.length&&legendColors.every((color,index)=>color===rampColors[index])||devWarnOnce("lyra-heatmap-legend-ramp-mismatch",`<${this.localName}>: legendStops describes ${legendColors.length} colour(s) that do not match the ${rampColors.length} colorSteps the cells are painted from, so the legend may misdescribe the ramp. Supply legendStops built from the same array as colorSteps, or omit it to keep the built-in gradient key.`)}attributeChangedCallback(name,oldValue,value){super.attributeChangedCallback(name,oldValue,value),!(oldValue===value||this.syncingGeneratedSemantics)&&(name==="role"&&(this.authorRole=value),name==="aria-label"&&(this.authorAriaLabel=value))}connectedCallback(){super.connectedCallback(),this.syncAnnouncementSink(),this.refreshAccessibleTargetSize();const owner=this.ownerDocument.defaultView,ResizeObserverCtor=owner?.ResizeObserver;if(owner&&ResizeObserverCtor){let observer;observer=new ResizeObserverCtor(()=>{!this.isConnected||this.ownerDocument.defaultView!==owner||this.resizeObserver!==observer||this.scheduleDraw()}),this.resizeObserver=observer,observer.observe(this)}const IntersectionObserverCtor=owner?.IntersectionObserver;if(this.canvasVisible=!0,owner&&IntersectionObserverCtor){let observer;observer=new IntersectionObserverCtor(entries=>{if(!this.isConnected||this.ownerDocument.defaultView!==owner||this.intersectionObserver!==observer)return;const entry=entries.find(candidate=>candidate.target===this);!entry||entry.isIntersecting===this.canvasVisible||(this.canvasVisible=entry.isIntersecting,this.canvasVisible&&this.drawDirty&&this.scheduleDraw())}),this.intersectionObserver=observer,observer.observe(this)}this.cachedRamp=null,this.canvasColorCache.clear(),this.watchDpr()}disconnectedCallback(){super.disconnectedCallback(),this.cancelSelectionGesture(),this.selectionAnchor=null,this.selectionRangeBase=void 0,this.accessibleFocusGeneration++,this.pendingAccessibleFocus=void 0,this.pendingAccessibleFocusOrigin=void 0,this.restoringAccessibleFocus=!1,this.releaseAnnouncementSink(),this.hoverCell=null,this.focusedCell=null,this.liveText="",this.canvasHasContent=!1,this.drawDirty=!0,this.resizeObserver?.disconnect(),this.resizeObserver=void 0,this.intersectionObserver?.disconnect(),this.intersectionObserver=void 0,this.canvasVisible=!0,this.clearDprWatcher(),this.cancelDrawFrame()}releaseAnnouncementSink(){this.announcementSink?.release(),this.announcementSink=void 0}syncAnnouncementSink(){if(!this.isConnected){this.releaseAnnouncementSink();return}this.announcementSink?.element.ownerDocument!==this.ownerDocument&&(this.releaseAnnouncementSink(),this.announcementSink=acquireAnnouncementSink("polite",{document:this.ownerDocument,source:this}))}watchDpr(){this.clearDprWatcher();const owner=this.ownerDocument.defaultView;if(!owner||typeof owner.matchMedia!="function")return;const query2=owner.matchMedia(`(resolution: ${owner.devicePixelRatio}dppx)`),listener=()=>{!this.isConnected||this.ownerDocument.defaultView!==owner||this.dprQuery!==query2||this.onDprChange()};this.dprQuery=query2,this.dprChangeListener=listener,query2.addEventListener("change",listener)}clearDprWatcher(){this.dprQuery&&this.dprChangeListener&&this.dprQuery.removeEventListener("change",this.dprChangeListener),this.dprQuery=void 0,this.dprChangeListener=void 0}willUpdate(changed){super.willUpdate(changed),(changed.has("data")||changed.has("domain")||changed.has("midpoint")||!this.hasUpdated)&&this.rebuildCanonicalMatrixData(),(changed.has("annotations")||changed.has("legendStops")||changed.has("colorSteps")||!this.hasUpdated)&&this.rebuildBoundedDecorations();const accessibleModeChanged=changed.has("accessibleCells")&&this.hasUpdated,collectionChanged=changed.has("data")||changed.has("cellInteractive"),activeRenderedControl=collectionChanged||accessibleModeChanged?activeElementIn(this.shadowRoot):null,activeAccessibleCell=activeRenderedControl?.matches('[part="cell"]')?activeRenderedControl:null,renderedAccessibleCells=activeAccessibleCell?.matches('[part="cell"]')?[...this.shadowRoot?.querySelectorAll('[part="cell"]')??[]]:[],accessibleFocusSnapshot=activeAccessibleCell?.matches('[part="cell"]')?{identity:activeAccessibleCell.dataset.cellIdentity,index:renderedAccessibleCells.indexOf(activeAccessibleCell)}:void 0;if(collectionChanged&&(this.focusedCell=null,this.hoverCell=null,this.liveText=""),changed.has("data")||changed.has("locale")||!this.hasUpdated){this.cachedCalendarGrid=buildCalendarGrid(this.calendarDays,this.normalizedFirstDayOfWeek,this.calendarMonthLabelText,this.effectiveLocale),this.cachedCalendarSortedValues=this.cachedCalendarGrid.cells.map(cell=>cell.value).filter(value=>!this.isNoData(value)).sort((a,b)=>a-b),this.cachedCalendarCellsByPos=new Map(this.cachedCalendarGrid.cells.map(cell=>[`${cell.week}:${cell.weekday}`,cell])),this.cachedCalendarCellsByDate=new Map(this.cachedCalendarGrid.cells.map(cell=>[cell.date,cell]));const{firstWeekStart,weekCount}=this.cachedCalendarGrid;this.cachedCalendarDateByPos=Array.from({length:weekCount*7},(_,index)=>isoDateAtOffset(firstWeekStart,index))}if(changed.has("colorSteps")||changed.has("withoutLegend")||!this.hasUpdated){const colorSteps=this.withoutLegend?[]:this.cachedColorSteps.map(sanitizeCssColor);colorSteps.length>=2&&colorSteps.every(color=>color!==void 0)?this.style.setProperty("--lr-heatmap-color-steps-gradient",`linear-gradient(to right, ${colorSteps.join(", ")})`):this.style.removeProperty("--lr-heatmap-color-steps-gradient")}if((changed.has("data")||changed.has("domain")||changed.has("midpoint")||!this.hasUpdated)&&(this.cachedValueRange=this.computeValueRange()),(collectionChanged||!this.hasUpdated)&&this.rebuildAccessiblePositions(),(collectionChanged||accessibleModeChanged||changed.has("multiple"))&&(this.cancelSelectionGesture(),this.selectionAnchor=null,this.selectionRangeBase=void 0,this.proposedSelectionKeys=void 0),(collectionChanged||changed.has("selectedCells")||changed.has("multiple")||!this.hasUpdated)&&(this.rebuildSelectedPositions(),changed.has("selectedCells")&&this.selectionGesture&&this.cancelSelectionGesture(),changed.has("selectedCells")&&this.selectionRangeBase&&(this.proposedSelectionKeys?.size!==this.selectedPositions.size||[...this.selectedPositions.keys()].some(key=>!this.proposedSelectionKeys?.has(key)))&&(this.selectionAnchor=this.focusedCell,this.selectionRangeBase=void 0)),accessibleFocusSnapshot){const positions=this.accessibleCellPositions(),target=(accessibleFocusSnapshot.identity==null?void 0:positions.find(pos=>this.accessibleCellIdentity(pos)===accessibleFocusSnapshot.identity))??positions[Math.min(Math.max(accessibleFocusSnapshot.index,0),positions.length-1)]??null;this.focusedCell=target,this.liveText=target?this.resolveCellText(target):"",this.pendingAccessibleFocus=target??"base",this.pendingAccessibleFocusOrigin=activeAccessibleCell??void 0,this.restoringAccessibleFocus=!0,this.accessibleFocusGeneration++}if(accessibleModeChanged){const previouslyAccessible=changed.get("accessibleCells")===!0;if(previouslyAccessible&&!this.accessibleCells&&activeAccessibleCell){const key=activeAccessibleCell.dataset.cellKey,target=key?this.accessibleCellAtKey(key):null;target&&(this.focusedCell=target,this.liveText=this.resolveCellText(target)),this.pendingAccessibleFocus="canvas",this.pendingAccessibleFocusOrigin=activeAccessibleCell,this.restoringAccessibleFocus=!0,this.accessibleFocusGeneration++}else if(!previouslyAccessible&&this.accessibleCells&&activeRenderedControl?.matches('[part="canvas"]')){const positions=this.accessibleCellPositions(),target=this.focusedCell?positions.find(pos=>this.samePos(pos,this.focusedCell))??positions[0]??null:positions[0]??null;this.focusedCell=target,this.liveText=target?this.resolveCellText(target):"",this.pendingAccessibleFocus=target??"base",this.pendingAccessibleFocusOrigin=activeRenderedControl,this.restoringAccessibleFocus=!0,this.accessibleFocusGeneration++}}const bounds=this.cachedValueRange,range=bounds?`${this.formatNumericValue(bounds[0])}–${this.formatNumericValue(bounds[1])}`:this.localize("heatmapNoDataValue"),valueLabel=this.localizedValueLabel();let label;if(this.effectiveMode==="calendar")label=this.localize("heatmapCalendarLabel",void 0,{days:this.formatCount(this.cachedCalendarGrid.cells.length),label:valueLabel,range});else{const rows=this.matrixRowLabels.length,cols=this.matrixColLabels.length;label=this.localize("heatmapMatrixLabel",void 0,{rows:this.formatCount(rows),cols:this.formatCount(cols),label:valueLabel,range})}const selectedText=this.selectedCellDescription(),generatedAriaLabel=[label,selectedText,this.projectionDescription()].filter(Boolean).join(" ");this.generatedAriaLabel=generatedAriaLabel,this.syncingGeneratedSemantics=!0;try{this.authorRole===null&&this.setAttribute("role","group"),this.authorAriaLabel===null&&this.setAttribute("aria-label",generatedAriaLabel)}finally{this.syncingGeneratedSemantics=!1}}rebuildBoundedDecorations(){this.cachedAnnotations=this.annotations.slice(0,MAX_HEATMAP_DECORATIONS).map(entry=>({...entry})),this.cachedLegendStops=(this.legendStops??[]).slice(0,MAX_HEATMAP_DECORATIONS).map(entry=>({...entry})),this.cachedColorSteps=(this.colorSteps??[]).slice(0,MAX_HEATMAP_DECORATIONS),this.warnOnLegendRampMismatch(),this.cachedCalendarAnnotationDates=new Set(this.cachedAnnotations.flatMap(annotation=>annotation.date==null?[]:[annotation.date])),this.cachedMatrixAnnotationPositions=new Set(this.cachedAnnotations.flatMap(annotation=>annotation.row==null||annotation.col==null?[]:[`${annotation.row}:${annotation.col}`])),this.decorationProjectionTruncated=this.annotations.length>MAX_HEATMAP_DECORATIONS||(this.legendStops?.length??0)>MAX_HEATMAP_DECORATIONS||(this.colorSteps?.length??0)>MAX_HEATMAP_DECORATIONS}get projectionTruncated(){return this.decorationProjectionTruncated||(this.effectiveMode==="calendar"?this.cachedCalendarGrid.truncated:this.cachedMatrixData.truncated)}get cellProjectionTruncated(){return this.effectiveMode==="calendar"?this.cachedCalendarGrid.truncated:this.cachedMatrixData.truncated}projectedCellCount(){return this.effectiveMode==="calendar"?this.cachedCalendarGrid.weekCount*7:this.matrixRowLabels.length*this.matrixColLabels.length}projectionDescription(){const messages=[];return this.cellProjectionTruncated&&messages.push(this.localize("heatmapProjectionLimit",void 0,{count:this.formatCount(this.projectedCellCount())})),this.decorationProjectionTruncated&&messages.push(this.localize("heatmapDecorationLimit",void 0,{count:this.formatCount(MAX_HEATMAP_DECORATIONS)})),messages.join(" ")}rebuildCanonicalMatrixData(){if(this.data.kind!=="matrix"){this.cachedMatrixData={rowLabels:[],colLabels:[],values:[],truncated:!1};return}const colCount=Math.min(this.data.colLabels.length,MAX_HEATMAP_CELLS),rowLimit=colCount===0?Math.min(this.data.rowLabels.length,MAX_HEATMAP_CELLS):Math.floor(MAX_HEATMAP_CELLS/colCount),rowCount=Math.min(this.data.rowLabels.length,rowLimit),rowLabels=this.data.rowLabels.slice(0,rowCount).map(String),colLabels=this.data.colLabels.slice(0,colCount).map(String),source=this.data,values=Array.from({length:rowCount},(_,row)=>Array.from({length:colCount},(_2,col)=>source.values[row]?.[col]??(this.signedDomain?Number.NaN:-1)));this.cachedMatrixData={rowLabels,colLabels,values,truncated:rowCount!==this.data.rowLabels.length||colCount!==this.data.colLabels.length||this.data.values.some((row,index)=>index>=rowCount||row.length>colCount)}}selectedCellDescription(){if(this.multiple){const count=this.currentSelectedPositions.size;return count?this.localize("heatmapSelectedCount",void 0,{count:this.formatCount(count)}):""}if(!this.selectedCell)return"";if(this.effectiveMode==="calendar"){if(this.selectedCell.date==null)return"";const match=this.cachedCalendarCellsByDate.get(this.selectedCell.date);return match?this.localize("heatmapSelectedCellLabel",void 0,{cell:this.calendarCellText({week:match.week,weekday:match.weekday,date:match.date})}):""}const{row,col}=this.selectedCell;return row==null||col==null||row<0||row>=this.matrixRowLabels.length||col<0||col>=this.matrixColLabels.length?"":this.localize("heatmapSelectedCellLabel",void 0,{cell:this.matrixCellText({row,col})})}computeValueRange(){const pinned=this.domain;if(pinned){const[lo,hi]=pinned;if(Number.isFinite(lo)&&Number.isFinite(hi)&&lo!==hi)return lo<hi?[lo,hi]:[hi,lo]}const source=this.effectiveMode==="calendar"?this.cachedCalendarGrid.cells.map(cell=>cell.value):this.matrixValues.flat();return minMax(source.filter(v=>!this.isNoData(v)))}localizedValueLabel(){return this.valueLabel===void 0?this.localize("heatmapValueLabel"):this.valueLabel}formatNumericValue(value){return getNumberFormat(this.effectiveLocale||void 0).format(value)}updated(changed){if(super.updated(changed),this.hoverCell&&this.effectiveStickyLabels!=="none"&&this.scheduleAfterUpdate(()=>this.measureTooltip(),"heatmap-tooltip-metrics"),["data","cellSize","cellGapX","cellGapY","cellRadius","colLabelInterval","maxCellSize","minCellSize","valueLabel","scale","domain","midpoint","fitToWidth","rowLabelWidth","colLabelHeight","colLabelRotation","bucketCount","annotations","focusedCell","colorSteps","cellColor","selectedCell","selectedCells","multiple","selectionPreview","legendStops","accessibleCells","accessibleTargetSizePx","locale","stickyLabels"].some(name=>changed.has(name))){if(changed.has("focusedCell")&&[...changed.keys()].every(key=>key==="focusedCell"||key==="liveText")&&this.repaintFocusRing(changed.get("focusedCell")))return;this.requestDraw()}const pending=this.pendingAccessibleFocus;if(pending===void 0)return;this.pendingAccessibleFocus=void 0;const origin=this.pendingAccessibleFocusOrigin;this.pendingAccessibleFocusOrigin=void 0;const generation=this.accessibleFocusGeneration;this.scheduleAfterUpdate(()=>{try{if(generation!==this.accessibleFocusGeneration||!this.isConnected)return;if(origin){const internalActive=activeElementIn(this.shadowRoot),documentActive=activeElementIn(this.ownerDocument),focusStayedAtOrigin=internalActive===origin,originWasRemovedWithoutReplacement=internalActive===null&&(documentActive===null||documentActive===this||documentActive===this.ownerDocument.body);if(!focusStayedAtOrigin&&!originWasRemovedWithoutReplacement)return}if(pending==="base"){this.shadowRoot?.querySelector('[part="base"]')?.focus();return}if(pending==="canvas"){this.shadowRoot?.querySelector('[part="canvas"]')?.focus();return}const identity=this.accessibleCellIdentity(pending);[...this.shadowRoot?.querySelectorAll('[part="cell"]')??[]].find(candidate=>candidate.dataset.cellIdentity===identity)?.focus()}finally{this.restoringAccessibleFocus=!1}},"heatmap-accessible-focus")}refreshTheme(){this.cachedRamp=null,this.refreshAccessibleTargetSize()||this.requestDraw()}refreshAccessibleTargetSize(){const raw=this.ownerDocument.defaultView?.getComputedStyle(this).getPropertyValue("--lr-icon-button-size").trim()??"",resolved=resolveCssLength(raw,{host:this}),next=resolved!==void 0&&Number.isFinite(resolved)&&resolved>0?resolved:DEFAULT_ACCESSIBLE_TARGET_SIZE_PX;return next===this.accessibleTargetSizePx?!1:(this.accessibleTargetSizePx=next,!0)}scaleEndpoints(cs){const lo=cs.getPropertyValue("--lr-heatmap-scale-lo").trim()||cs.getPropertyValue("--_lr-heatmap-scale-lo").trim()||FALLBACK_SCALE_LO,hi=cs.getPropertyValue("--lr-heatmap-scale-hi").trim()||cs.getPropertyValue("--_lr-heatmap-scale-hi").trim()||FALLBACK_SCALE_HI;return[lo,hi]}labelColor(cs){return cs.getPropertyValue("--lr-color-text-quiet").trim()||"#6b7280"}labelFont(cs){return cs.getPropertyValue("--lr-heatmap-label-font").trim()||cs.getPropertyValue("--_lr-heatmap-label-font").trim()||FALLBACK_LABEL_FONT}stickyLabelBg(cs){const raw=cs.getPropertyValue("--lr-heatmap-sticky-label-bg").trim()||cs.getPropertyValue("--_lr-heatmap-sticky-label-bg").trim()||FALLBACK_STICKY_LABEL_BG;return formatRgb(resolveRgb(raw,FALLBACK_STICKY_LABEL_BG,this.ownerDocument))}noDataFill(cs){return cs.getPropertyValue("--lr-heatmap-no-data-fill").trim()||cs.getPropertyValue("--_lr-heatmap-no-data-fill").trim()||FALLBACK_NO_DATA_FILL}focusRingColor(cs){return cs.getPropertyValue("--lr-heatmap-focus-ring-color").trim()||cs.getPropertyValue("--_lr-heatmap-focus-ring-color").trim()||FALLBACK_FOCUS_RING_COLOR}annotationColor(cs){return cs.getPropertyValue("--lr-heatmap-annotation-color").trim()||cs.getPropertyValue("--_lr-heatmap-annotation-color").trim()||FALLBACK_ANNOTATION_COLOR}selectedColor(cs){return cs.getPropertyValue("--lr-heatmap-selected-color").trim()||cs.getPropertyValue("--_lr-heatmap-selected-color").trim()||FALLBACK_SELECTED_COLOR}strokeCellState(ctx,x,y,size,state2,color){const shape=this.effectiveMode==="matrix"?this.matrixCellShape(size):void 0,width=shape?.custom?shape.w:size,height=shape?.custom?shape.h:size;shape?.custom&&(ctx.save(),ctx.beginPath(),ctx.roundRect(x,y,shape.w,shape.h,shape.radius),ctx.clip());const inset=Math.min(state2==="annotation"?.5:state2==="selected"?3.5:6.5,Math.max(.5,(Math.min(width,height)-RING_LINE_WIDTH-1)/2)),w=Math.max(1,width-inset*2),h=Math.max(1,height-inset*2);ctx.lineWidth=RING_LINE_WIDTH,ctx.strokeStyle=color,ctx.setLineDash?.(state2==="annotation"?[]:state2==="selected"?[4,2]:[1,2]),shape?.custom&&shape.radius>0?(ctx.beginPath(),ctx.roundRect(x+inset,y+inset,w,h,Math.max(0,shape.radius-inset)),ctx.stroke()):ctx.strokeRect(x+inset,y+inset,w,h),ctx.setLineDash?.([]),shape?.custom&&ctx.restore()}isSelectedPos(pos){return this.multiple?this.currentSelectedPositions.has(this.accessibleCellKey(pos)):this.selectedCell?"week"in pos?this.selectedCell.date==null?!1:this.calendarCellAt(pos).date===this.selectedCell.date:this.selectedCell.row===pos.row&&this.selectedCell.col===pos.col:!1}draw(){if(!this.canvasVisible){this.drawDirty=!0;return}this.drawDirty=!1,this.canvasHasContent=!1,this.effectiveMode==="calendar"?this.drawCalendar():this.drawMatrix()}requestDraw(){this.drawDirty=!0,this.canvasVisible&&this.draw()}repaintFocusRing(previous){if(!this.canvasHasContent||!this.canvas)return!1;const current=this.focusedCell;if(this.effectiveMode==="calendar"){if(previous&&!("week"in previous)||current&&!("week"in current))return!1;this.repaintCalendarFocusCell(previous&&"week"in previous?previous:null),current&&(!previous||!this.samePos(previous,current))&&this.repaintCalendarFocusCell(current)}else{if(previous&&!("row"in previous)||current&&!("row"in current))return!1;this.repaintMatrixFocusCell(previous&&"row"in previous?previous:null),current&&(!previous||!this.samePos(previous,current))&&this.repaintMatrixFocusCell(current)}return!0}cancelDrawFrame(){const request=this.drawFrameRequest;request&&request.owner.cancelAnimationFrame(request.handle),this.drawFrameRequest=void 0}resolveColorStep(color,fallback){const safe=sanitizeCssColor(color);if(!safe)return fallback;const scope=this.ownerDocument.createElement("span"),probe=this.ownerDocument.createElement("span");scope.hidden=!0,scope.style.color=fallback,probe.style.color=safe,scope.append(probe),this.renderRoot.append(scope);try{return this.ownerDocument.defaultView?.getComputedStyle(probe).color.trim()||fallback}finally{scope.remove()}}colorRamp(bucketCount,cs){const steps=this.cachedColorSteps;if(steps&&steps.length>=2){const key2=`steps ${steps.join(" ")}`;if(this.cachedRamp?.key===key2)return this.cachedRamp;const resolved=steps.map((color,index)=>this.resolveColorStep(color,index===steps.length-1?FALLBACK_SCALE_HI:FALLBACK_SCALE_LO)),colors2=resolved.map(color=>formatRgb(resolveRgb(color,FALLBACK_SCALE_LO,this.ownerDocument))),loRgb2=resolveRgb(resolved[0],FALLBACK_SCALE_LO,this.ownerDocument),hiRgb2=resolveRgb(resolved[resolved.length-1],FALLBACK_SCALE_HI,this.ownerDocument);return this.cachedRamp={key:key2,colors:colors2,loRgb:loRgb2,hiRgb:hiRgb2},this.cachedRamp}const[scaleLo,scaleHi]=this.scaleEndpoints(cs),normalizedBucketCount=normalizeBucketCount(bucketCount),key=`${scaleLo}\0${scaleHi}\0${normalizedBucketCount}`;if(this.cachedRamp?.key===key)return this.cachedRamp;const loRgb=resolveRgb(scaleLo,FALLBACK_SCALE_LO,this.ownerDocument),hiRgb=resolveRgb(scaleHi,FALLBACK_SCALE_HI,this.ownerDocument),colors=Array.from({length:normalizedBucketCount},(_,i)=>mixRgb(loRgb,hiRgb,i/(normalizedBucketCount-1)));return this.cachedRamp={key,colors,loRgb,hiRgb},this.cachedRamp}calendarCellSize(){const{weekCount}=this.cachedCalendarGrid;let size;if(this.fitToWidth&&weekCount>0){const hostWidth=this.clientWidth||this.calendarPadLeft+weekCount*(this.cellSize+CAL_GAP);size=this.clampFitCellSize((hostWidth-this.calendarPadLeft)/weekCount-CAL_GAP)}else size=this.cellSize;return this.accessibleCells?Math.max(size,this.accessibleTargetSizePx):size}clampFitCellSize(size){const floored=finiteRange(size,FIT_MIN_CELL,Math.max(FIT_MIN_CELL,this.minCellSize??FIT_MIN_CELL));return this.maxCellSize==null?floored:Math.min(floored,this.maxCellSize)}columnXFor(week){return this.calendarColumnPositions()[week]??this.calendarPadLeft}rowYFor(weekday){return this.calendarRowPositions()[weekday]??CAL_LABEL_H}calendarColumnPositions(){const cellSize=this.calendarCellSize(),weekCount=this.cachedCalendarGrid.weekCount,callback=this.calendarColumnX,padLeft=this.calendarPadLeft,cached=this.cachedColumnGeometry;if(cached!==void 0&&cached.callback===callback&&cached.padLeft===padLeft&&cached.cellSize===cellSize&&cached.weekCount===weekCount)return cached.positions;const positions=[];for(let index=0;index<=weekCount;index++){const fallback=index===0?padLeft:positions[index-1]+cellSize+CAL_GAP;let candidate=fallback;if(callback)try{const supplied=callback(index);Number.isFinite(supplied)&&supplied>=0&&(index===0||supplied>=positions[index-1]+cellSize)&&(candidate=supplied)}catch{candidate=fallback}positions.push(candidate)}return this.cachedColumnGeometry={callback,padLeft,cellSize,weekCount,positions},positions}calendarRowPositions(){const cellSize=this.calendarCellSize(),callback=this.calendarRowY,cached=this.cachedRowGeometry;if(cached!==void 0&&cached.callback===callback&&cached.cellSize===cellSize)return cached.positions;const positions=[];for(let index=0;index<=7;index++){const fallback=index===0?CAL_LABEL_H:positions[index-1]+cellSize+CAL_GAP;let candidate=fallback;if(callback)try{const supplied=callback(index);Number.isFinite(supplied)&&supplied>=0&&(index===0||supplied>=positions[index-1]+cellSize)&&(candidate=supplied)}catch{candidate=fallback}positions.push(candidate)}return this.cachedRowGeometry={callback,cellSize,positions},positions}weekAtX(x,weekCount){const positions=this.calendarColumnPositions(),cellSize=this.calendarCellSize();for(let week=0;week<weekCount;week++){const start=positions[week];if(x>=start&&x<start+cellSize)return week}return null}weekdayAtY(y){const positions=this.calendarRowPositions(),cellSize=this.calendarCellSize();for(let weekday=0;weekday<7;weekday++){const start=positions[weekday];if(y>=start&&y<start+cellSize)return weekday}return null}weekdayLabels(firstWeekStart){const formatter=getDateTimeFormat(this.effectiveLocale||void 0,{weekday:"short",timeZone:"UTC"}),labels=["","","","","","",""];for(const weekday of[1,3,5]){const row=(weekday-this.normalizedFirstDayOfWeek+7)%7;labels[row]=this.calendarWeekdayLabelText?.(weekday)??formatter.format(new Date(firstWeekStart.getTime()+row*MS_PER_DAY))}return labels}paintCalendarAxisLabels(ctx,cellSize,cs,firstWeekStart,monthLabels){ctx.fillStyle=this.labelColor(cs),ctx.font=this.labelFont(cs);for(const month of monthLabels)ctx.fillText(month.label,this.columnXFor(month.week),CAL_LABEL_H-4);const available=this.calendarPadLeft-CAL_WEEKDAY_LABEL_INSET*2;this.weekdayLabels(firstWeekStart).forEach((label,weekday)=>{const shown=label?this.ellipsize(ctx,label,available):"";shown&&ctx.fillText(shown,CAL_WEEKDAY_LABEL_INSET,this.rowYFor(weekday)+cellSize-1)})}drawCalendar(){if(!this.canvas)return;const{weekCount,firstWeekStart,monthLabels}=this.cachedCalendarGrid,cs=this.ownerDocument.defaultView?.getComputedStyle(this);if(!cs)return;const previousResolvedWeekdayWidth=this.resolvedCalendarWeekdayLabelWidth;this.calendarWeekdayLabelWidth==="auto"&&(this.resolvedCalendarWeekdayLabelWidth=this.measureCalendarWeekdayLabelWidth(cs,firstWeekStart));const autoGutterChanged=previousResolvedWeekdayWidth!==this.resolvedCalendarWeekdayLabelWidth,cellSize=this.calendarCellSize(),w=this.columnXFor(Math.max(1,weekCount)),h=this.rowYFor(7),dpr=this.ownerDocument.defaultView?.devicePixelRatio||1;this.canvas.width=w*dpr,this.canvas.height=h*dpr,this.canvas.style.width=`${w}px`,this.canvas.style.height=`${h}px`;const ctx=this.canvas.getContext("2d");if(!ctx)return;ctx.scale(dpr,dpr),ctx.clearRect(0,0,w,h);const buckets=normalizeBucketCount(this.bucketCount),ramp=this.colorRamp(buckets,cs).colors,noDataFill=this.noDataFill(cs);this.canvasColorCache.clear();const bounds=this.cachedValueRange,lo=bounds?bounds[0]:0,hi=bounds?bounds[1]:1;for(let week=0;week<weekCount;week++)for(let weekday=0;weekday<7;weekday++){const value=this.calendarValueAt(week,weekday),x=this.columnXFor(week),y=this.rowYFor(weekday),override=this.cellColor?.(this.calendarPos(week,weekday),value);if(override!=null)ctx.fillStyle=this.resolveCanvasColor(override,cs);else if(this.isNoData(value))ctx.fillStyle=noDataFill;else if(this.scale==="sqrt"){const step=sqrtStep(value,hi,ramp.length);ctx.fillStyle=step<0?noDataFill:ramp[step]}else if(this.cachedColorSteps.length>=2){const step=this.rampBucket(value,lo,hi,ramp.length);ctx.fillStyle=ramp[step]}else ctx.fillStyle=ramp[quartileBucket(value,this.cachedCalendarSortedValues,buckets)];ctx.fillRect(x,y,cellSize,cellSize)}if(this.cachedAnnotations.length)for(const ann of this.cachedAnnotations){if(ann.date==null)continue;const match=this.cachedCalendarCellsByDate.get(ann.date);if(!match)continue;const x=this.columnXFor(match.week),y=this.rowYFor(match.weekday);this.strokeCellState(ctx,x,y,cellSize,"annotation",this.annotationColor(cs))}for(const match of this.selectedPaintPositions())if("week"in match){const x=this.columnXFor(match.week),y=this.rowYFor(match.weekday);this.strokeCellState(ctx,x,y,cellSize,"selected",this.selectedColor(cs))}if(this.focusedCell&&"week"in this.focusedCell){const{week,weekday}=this.focusedCell;if(week<weekCount&&weekday<7){const x=this.columnXFor(week),y=this.rowYFor(weekday);this.strokeCellState(ctx,x,y,cellSize,"focus",this.focusRingColor(cs))}}this.paintCalendarAxisLabels(ctx,cellSize,cs,firstWeekStart,monthLabels),this.canvasHasContent=!0,autoGutterChanged&&this.accessibleCells&&this.scheduleAfterUpdate(()=>this.requestUpdate(),"heatmap-calendar-accessible-geometry")}matrixCellSize(cols){let size;if(this.fitToWidth&&cols>0){const padLeft=this.matrixPadLeft,hostWidth=this.clientWidth||padLeft+cols*this.cellSize;size=this.clampFitCellSize((hostWidth-padLeft)/cols)}else size=this.cellSize;if(!this.accessibleCells)return size;const target=this.accessibleTargetSizePx,gap=finiteNumber(this.cellGapX,1)!==1||finiteNumber(this.cellGapY,1)!==1||finiteRange(this.cellRadius,0,0)>0?Math.max(finiteRange(this.cellGapX,1,0,target),finiteRange(this.cellGapY,1,0,target)):0;return Math.max(size,target+gap)}matrixCellShape(size){if(finiteNumber(this.cellGapX,1)===1&&finiteNumber(this.cellGapY,1)===1&&finiteRange(this.cellRadius,0,0)===0)return{w:size-1,h:size-1,radius:0,custom:!1};const minimum=this.accessibleCells?Math.min(size,this.accessibleTargetSizePx):1,maxGap=Math.max(0,size-minimum),w=size-finiteRange(this.cellGapX,1,0,maxGap),h=size-finiteRange(this.cellGapY,1,0,maxGap),radius=finiteRange(this.cellRadius,0,0,Math.min(w,h)/2);return{w,h,radius,custom:w!==size-1||h!==size-1||radius!==0}}fillMatrixCell(ctx,x,y,shape){shape.radius===0?ctx.fillRect(x,y,shape.w,shape.h):(ctx.beginPath(),ctx.roundRect(x,y,shape.w,shape.h,shape.radius),ctx.fill())}paintMatrixCell(ctx,row,col,cellSize,cs,rampData,noDataFill){const value=this.matrixValues[row]?.[col]??Number.NaN,bounds=this.cachedValueRange,lo=bounds?bounds[0]:0,hi=bounds?bounds[1]:1,override=this.cellColor?.({row,col},value);if(override!=null)ctx.fillStyle=this.resolveCanvasColor(override,cs);else if(this.isNoData(value))ctx.fillStyle=noDataFill;else if(this.scale==="sqrt"){const step=sqrtStep(value,hi,rampData.colors.length);ctx.fillStyle=step<0?noDataFill:rampData.colors[step]}else this.cachedColorSteps.length>=2?ctx.fillStyle=rampData.colors[this.rampBucket(value,lo,hi,rampData.colors.length)]:ctx.fillStyle=mixRgb(rampData.loRgb,rampData.hiRgb,this.rampAlpha(value,lo,hi));this.fillMatrixCell(ctx,this.matrixPadLeft+col*cellSize,this.matrixPadTop+row*cellSize,this.matrixCellShape(cellSize))}paintMatrixFocusOverlays(ctx,row,col,cellSize,cs,state2){const x=this.matrixPadLeft+col*cellSize,y=this.matrixPadTop+row*cellSize;state2==="annotation"&&this.cachedMatrixAnnotationPositions.has(`${row}:${col}`)&&this.strokeCellState(ctx,x,y,cellSize,"annotation",this.annotationColor(cs)),state2==="selected"&&this.isSelectedPos({row,col})&&this.strokeCellState(ctx,x,y,cellSize,"selected",this.selectedColor(cs)),state2==="focus"&&this.focusedCell&&"row"in this.focusedCell&&this.focusedCell.row===row&&this.focusedCell.col===col&&this.strokeCellState(ctx,x,y,cellSize,"focus",this.focusRingColor(cs))}focusRepaintBounds(ctx,x,y,cellSize){const padding=RING_LINE_WIDTH+1,dpr=ctx.getTransform().a,left=Math.floor((x-padding)*dpr)/dpr,top=Math.floor((y-padding)*dpr)/dpr,right=Math.ceil((x+cellSize+padding)*dpr)/dpr,bottom=Math.ceil((y+cellSize+padding)*dpr)/dpr;return{left,top,width:right-left,height:bottom-top,radius:Math.ceil((2*padding+1/dpr)/cellSize)}}repaintMatrixFocusCell(pos){if(!pos||!this.canvas)return;const rows=this.matrixRowLabels.length,cols=this.matrixColLabels.length;if(pos.row<0||pos.row>=rows||pos.col<0||pos.col>=cols)return;const cellSize=this.matrixCellSize(cols),x=this.matrixPadLeft+pos.col*cellSize,y=this.matrixPadTop+pos.row*cellSize,ctx=this.canvas.getContext("2d");if(!ctx)return;const cs=this.ownerDocument.defaultView?.getComputedStyle(this);if(!cs)return;const{left,top,width,height,radius}=this.focusRepaintBounds(ctx,x,y,cellSize),firstRow=Math.max(0,pos.row-radius),lastRow=Math.min(rows-1,pos.row+radius),firstCol=Math.max(0,pos.col-radius),lastCol=Math.min(cols-1,pos.col+radius),ramp=this.colorRamp(RAMP_STEPS,cs),noData=this.noDataFill(cs);ctx.save();try{ctx.beginPath(),ctx.rect(left,top,width,height),ctx.clip(),ctx.clearRect(left,top,width,height);for(let row=firstRow;row<=lastRow;row++)for(let col=firstCol;col<=lastCol;col++)this.paintMatrixCell(ctx,row,col,cellSize,cs,ramp,noData);for(const state2 of["annotation","selected","focus"])for(let row=firstRow;row<=lastRow;row++)for(let col=firstCol;col<=lastCol;col++)this.paintMatrixFocusOverlays(ctx,row,col,cellSize,cs,state2)}finally{ctx.restore()}}paintCalendarCell(ctx,week,weekday,cellSize,cs,ramp,noDataFill){const value=this.calendarValueAt(week,weekday),bounds=this.cachedValueRange,lo=bounds?bounds[0]:0,hi=bounds?bounds[1]:1,override=this.cellColor?.(this.calendarPos(week,weekday),value);if(override!=null)ctx.fillStyle=this.resolveCanvasColor(override,cs);else if(this.isNoData(value))ctx.fillStyle=noDataFill;else if(this.scale==="sqrt"){const step=sqrtStep(value,hi,ramp.length);ctx.fillStyle=step<0?noDataFill:ramp[step]}else this.cachedColorSteps.length>=2?ctx.fillStyle=ramp[this.rampBucket(value,lo,hi,ramp.length)]:ctx.fillStyle=ramp[quartileBucket(value,this.cachedCalendarSortedValues,ramp.length)];ctx.fillRect(this.columnXFor(week),this.rowYFor(weekday),cellSize,cellSize)}paintCalendarFocusOverlays(ctx,week,weekday,cellSize,cs,state2){const date=this.calendarDateAt(week,weekday),x=this.columnXFor(week),y=this.rowYFor(weekday);state2==="annotation"&&this.cachedCalendarCellsByDate.has(date)&&this.cachedCalendarAnnotationDates.has(date)&&this.strokeCellState(ctx,x,y,cellSize,"annotation",this.annotationColor(cs)),state2==="selected"&&(this.multiple||this.cachedCalendarCellsByDate.has(date))&&this.isSelectedPos({week,weekday,date})&&this.strokeCellState(ctx,x,y,cellSize,"selected",this.selectedColor(cs)),state2==="focus"&&this.focusedCell&&"week"in this.focusedCell&&this.focusedCell.week===week&&this.focusedCell.weekday===weekday&&this.strokeCellState(ctx,x,y,cellSize,"focus",this.focusRingColor(cs))}repaintCalendarFocusCell(pos){if(!pos||!this.canvas)return;const{weekCount,firstWeekStart}=this.cachedCalendarGrid;if(pos.week<0||pos.week>=weekCount||pos.weekday<0||pos.weekday>=7)return;const cellSize=this.calendarCellSize(),x=this.columnXFor(pos.week),y=this.rowYFor(pos.weekday),ctx=this.canvas.getContext("2d");if(!ctx)return;const cs=this.ownerDocument.defaultView?.getComputedStyle(this);if(!cs)return;const{left,top,width,height,radius}=this.focusRepaintBounds(ctx,x,y,cellSize),firstWeek=Math.max(0,pos.week-radius),lastWeek=Math.min(weekCount-1,pos.week+radius),firstDay=Math.max(0,pos.weekday-radius),lastDay=Math.min(6,pos.weekday+radius),ramp=this.colorRamp(normalizeBucketCount(this.bucketCount),cs).colors,noData=this.noDataFill(cs);ctx.save();try{ctx.beginPath(),ctx.rect(left,top,width,height),ctx.clip(),ctx.clearRect(left,top,width,height);for(let week=firstWeek;week<=lastWeek;week++)for(let day=firstDay;day<=lastDay;day++)this.paintCalendarCell(ctx,week,day,cellSize,cs,ramp,noData);for(const state2 of["annotation","selected","focus"])for(let week=firstWeek;week<=lastWeek;week++)for(let day=firstDay;day<=lastDay;day++)this.paintCalendarFocusOverlays(ctx,week,day,cellSize,cs,state2);this.paintCalendarAxisLabels(ctx,cellSize,cs,firstWeekStart,this.cachedCalendarGrid.monthLabels)}finally{ctx.restore()}}drawMatrix(){if(!this.canvas)return;const rows=this.matrixRowLabels.length,cols=this.matrixColLabels.length;if(this.rowLabelWidth==="auto"||this.colLabelHeight==="auto"){const measureStyle=getComputedStyle(this);this.rowLabelWidth==="auto"&&(this.resolvedRowLabelWidth=this.measureRowLabelWidth(measureStyle)),this.colLabelHeight==="auto"&&(this.resolvedColLabelHeight=this.measureColLabelHeight(measureStyle))}const padLeft=this.matrixPadLeft,padTop=this.matrixPadTop,cellSize=this.matrixCellSize(cols),shape=this.matrixCellShape(cellSize),dimensions=shape.custom?{cellWidth:shape.w,cellHeight:shape.h,cellRadius:shape.radius}:{},previous=this.lastPaintedMatrixGeometry,geometry=previous&&previous.padLeft===padLeft&&previous.padTop===padTop&&previous.cellSize===cellSize&&previous.cellWidth===dimensions.cellWidth&&previous.cellHeight===dimensions.cellHeight&&previous.cellRadius===dimensions.cellRadius?previous:Object.freeze({padLeft,padTop,cellSize,...dimensions});this.lastPaintedMatrixGeometry=geometry;const geometryChanged=geometry!==previous;geometryChanged&&this.emit("lr-matrix-geometry-change",geometry);const w=padLeft+cols*cellSize,h=padTop+rows*cellSize,dpr=this.ownerDocument.defaultView?.devicePixelRatio||1;this.canvas.width=w*dpr,this.canvas.height=h*dpr,this.canvas.style.width=`${w}px`,this.canvas.style.height=`${h}px`;const ctx=this.canvas.getContext("2d");if(!ctx)return;ctx.scale(dpr,dpr),ctx.clearRect(0,0,w,h);const cs=this.ownerDocument.defaultView?.getComputedStyle(this);if(!cs)return;const bounds=this.cachedValueRange,lo=bounds?bounds[0]:0,hi=bounds?bounds[1]:1,rampData=this.colorRamp(RAMP_STEPS,cs),ramp=rampData.colors,{loRgb,hiRgb}=rampData,noDataFill=this.noDataFill(cs);this.canvasColorCache.clear();for(let r=0;r<rows;r++)for(let c=0;c<cols;c++){const v=this.matrixValues[r]?.[c]??Number.NaN,x=padLeft+c*cellSize,y=padTop+r*cellSize,override=this.cellColor?.({row:r,col:c},v);if(override!=null)ctx.fillStyle=this.resolveCanvasColor(override,cs);else if(this.isNoData(v))ctx.fillStyle=noDataFill;else if(this.scale==="sqrt"){const step=sqrtStep(v,hi,ramp.length);ctx.fillStyle=step<0?noDataFill:ramp[step]}else if(this.cachedColorSteps.length>=2){const step=this.rampBucket(v,lo,hi,ramp.length);ctx.fillStyle=ramp[step]}else{const t=this.rampAlpha(v,lo,hi);ctx.fillStyle=mixRgb(loRgb,hiRgb,t)}this.fillMatrixCell(ctx,x,y,shape)}if(this.cachedAnnotations.length)for(const ann of this.cachedAnnotations){if(ann.row==null||ann.col==null||ann.row<0||ann.row>=rows||ann.col<0||ann.col>=cols)continue;const x=padLeft+ann.col*cellSize,y=padTop+ann.row*cellSize;this.strokeCellState(ctx,x,y,cellSize,"annotation",this.annotationColor(cs))}for(const selected of this.selectedPaintPositions()){if(!("row"in selected))continue;const{row,col}=selected;if(row>=0&&row<rows&&col>=0&&col<cols){const x=padLeft+col*cellSize,y=padTop+row*cellSize;this.strokeCellState(ctx,x,y,cellSize,"selected",this.selectedColor(cs))}}if(this.focusedCell&&"row"in this.focusedCell){const{row,col}=this.focusedCell;if(row<rows&&col<cols){const x=padLeft+col*cellSize,y=padTop+row*cellSize;this.strokeCellState(ctx,x,y,cellSize,"focus",this.focusRingColor(cs))}}this.paintMatrixRowLabels(ctx,padLeft,padTop,cellSize,cs),this.paintMatrixColLabels(ctx,padLeft,padTop,cellSize,cs),this.paintFrozenLabelBands(padLeft,padTop,cellSize,w,h,dpr,cs),this.canvasHasContent=!0,geometryChanged&&this.accessibleCells&&this.scheduleAfterUpdate(()=>this.requestUpdate(),"heatmap-matrix-accessible-geometry")}paintMatrixRowLabels(ctx,padLeft,padTop,cellSize,cs){ctx.fillStyle=this.labelColor(cs),ctx.font=this.labelFont(cs);const rowLabelSpace=padLeft-ROW_LABEL_INSET*2;this.matrixRowLabels.forEach((label,r)=>{const shown=this.ellipsize(ctx,label,rowLabelSpace);shown&&ctx.fillText(shown,ROW_LABEL_INSET,padTop+r*cellSize+cellSize/2+3)})}paintMatrixColLabels(ctx,padLeft,padTop,cellSize,cs){ctx.fillStyle=this.labelColor(cs),ctx.font=this.labelFont(cs);const colRotation=this.effectiveColLabelRotation,interval=finiteInteger(this.colLabelInterval,1,1);if(colRotation===0){this.matrixColLabels.forEach((label,c)=>{c%interval===0&&ctx.fillText(label,padLeft+c*cellSize+2,padTop-COL_LABEL_INSET)});return}const radians=colRotation*Math.PI/180,previousAlign=ctx.textAlign;ctx.textAlign="right",this.matrixColLabels.forEach((label,c)=>{c%interval===0&&(ctx.save(),ctx.translate(padLeft+c*cellSize+cellSize/2,padTop-COL_LABEL_INSET),ctx.rotate(radians),ctx.fillText(label,0,0),ctx.restore())}),ctx.textAlign=previousAlign}paintFrozenLabelBands(padLeft,padTop,cellSize,width,height,dpr,cs){if(this.effectiveStickyLabels==="none")return;const backdrop=this.stickyLabelBg(cs),rowBand=this.frozenBandCanvas("row-labels");rowBand&&this.paintFrozenBand(rowBand,padLeft,height,dpr,backdrop,bandCtx=>this.paintMatrixRowLabels(bandCtx,padLeft,padTop,cellSize,cs));const colBand=this.frozenBandCanvas("col-labels");colBand&&this.paintFrozenBand(colBand,width,padTop,dpr,backdrop,bandCtx=>this.paintMatrixColLabels(bandCtx,padLeft,padTop,cellSize,cs))}frozenBandCanvas(part){return this.shadowRoot?.querySelector(`[part="${part}"]`)??null}paintFrozenBand(canvas,width,height,dpr,backdrop,paint){canvas.width=width*dpr,canvas.height=height*dpr,canvas.style.width=`${width}px`,canvas.style.height=`${height}px`;const ctx=canvas.getContext("2d");ctx&&(ctx.scale(dpr,dpr),ctx.clearRect(0,0,width,height),ctx.fillStyle=backdrop,ctx.fillRect(0,0,width,height),paint(ctx))}hitTest(x,y){return this.effectiveMode==="calendar"?this.hitTestCalendar(x,y):this.hitTestMatrix(x,y)}hitTestMatrix(x,y){const rows=this.matrixRowLabels.length,cols=this.matrixColLabels.length;if(rows===0||cols===0)return null;const cellSize=this.matrixCellSize(cols),col=Math.floor((x-this.matrixPadLeft)/cellSize),row=Math.floor((y-this.matrixPadTop)/cellSize);if(row<0||row>=rows||col<0||col>=cols)return null;const shape=this.matrixCellShape(cellSize);if(shape.custom&&(x-this.matrixPadLeft-col*cellSize>=shape.w||y-this.matrixPadTop-row*cellSize>=shape.h))return null;const pos={row,col};return this.isCellInteractive(pos)?pos:null}firstInteractiveMatrixCell(rows,cols){for(let r=0;r<rows;r++)for(let c=0;c<cols;c++)if(this.isCellInteractive({row:r,col:c}))return{row:r,col:c};return null}nextInteractiveMatrixCell(row,col,dRow,dCol,rows,cols){let r=row,c=col;for(;;){const nr=Math.min(rows-1,Math.max(0,r+dRow)),nc=Math.min(cols-1,Math.max(0,c+dCol));if(nr===r&&nc===c)return{row,col};if(r=nr,c=nc,this.isCellInteractive({row:r,col:c}))return{row:r,col:c}}}firstInteractiveCalendarCell(weekCount){for(let week=0;week<weekCount;week++)for(let weekday=0;weekday<7;weekday++){const pos=this.calendarPos(week,weekday);if(this.isCellInteractive(pos))return pos}return null}nextInteractiveCalendarCell(week,weekday,dWeek,dWeekday,weekCount){let w=week,d=weekday;for(;;){const nw=Math.min(weekCount-1,Math.max(0,w+dWeek)),nd=Math.min(6,Math.max(0,d+dWeekday));if(nw===w&&nd===d)return this.calendarPos(week,weekday);w=nw,d=nd;const pos=this.calendarPos(w,d);if(this.isCellInteractive(pos))return pos}}hitTestCalendar(x,y){const{weekCount}=this.cachedCalendarGrid;if(weekCount===0)return null;const week=this.weekAtX(x,weekCount),weekday=this.weekdayAtY(y);if(week===null||weekday===null)return null;const pos=this.calendarPos(week,weekday);return this.isCellInteractive(pos)?pos:null}calendarCellAt(pos){const match=this.cachedCalendarCellsByPos.get(`${pos.week}:${pos.weekday}`);return match?{date:match.date,value:match.value}:{date:this.calendarDateAt(pos.week,pos.weekday),value:this.calendarValueAt(pos.week,pos.weekday)}}calendarValueAt(week,weekday){const match=this.cachedCalendarCellsByPos.get(`${week}:${weekday}`);return match?match.value:this.signedDomain?Number.NaN:-1}calendarDateAt(week,weekday){const index=week*7+weekday;return this.cachedCalendarDateByPos[index]??isoDateAtOffset(this.cachedCalendarGrid.firstWeekStart,index)}calendarPos(week,weekday){return{week,weekday,date:this.calendarDateAt(week,weekday)}}cellRect(pos){if("week"in pos){const cellSize2=this.calendarCellSize();return{x:this.columnXFor(pos.week),y:this.rowYFor(pos.weekday),w:cellSize2,h:cellSize2}}const cellSize=this.matrixCellSize(this.matrixColLabels.length),shape=this.matrixCellShape(cellSize);return{x:this.matrixPadLeft+pos.col*cellSize,y:this.matrixPadTop+pos.row*cellSize,w:shape.w,h:shape.h}}accessibleCellRect(pos){if("week"in pos||!this.lastPaintedMatrixGeometry)return this.cellRect(pos);const{padLeft,padTop,cellSize,cellWidth,cellHeight}=this.lastPaintedMatrixGeometry;return{x:padLeft+pos.col*cellSize,y:padTop+pos.row*cellSize,w:cellWidth??cellSize-1,h:cellHeight??cellSize-1}}defaultCellText(pos){return"week"in pos?this.calendarCellText(pos):this.matrixCellText(pos)}matrixCellText(pos){const rowLabel=this.matrixRowLabels[pos.row]??this.localize("heatmapDefaultRowLabel",void 0,{n:this.formatCount(pos.row+1)}),colLabel=this.matrixColLabels[pos.col]??this.localize("heatmapDefaultColLabel",void 0,{n:this.formatCount(pos.col+1)}),v=this.matrixValues[pos.row]?.[pos.col],valueText=v==null||this.isNoData(v)?this.localize("heatmapNoDataValue"):this.formatNumericValue(v);return this.localize("heatmapMatrixCellLabel",void 0,{row:rowLabel,col:colLabel,value:valueText})}calendarCellText(pos){const{date,value}=this.calendarCellAt(pos),label=parseIsoDate(date).toLocaleString(this.effectiveLocale||void 0,{month:"short",day:"numeric",timeZone:"UTC"}),valueText=this.isNoData(value)?this.localize("heatmapNoDataValue"):this.formatNumericValue(value);return this.localize("heatmapCalendarCellLabel",void 0,{date:label,value:valueText})}valueAt(pos){return"week"in pos?this.calendarCellAt(pos).value:this.matrixValues[pos.row]?.[pos.col]??-1}resolveCellText(pos){return this.cellText?this.cellText(pos,this.valueAt(pos)):this.defaultCellText(pos)}isCellInteractive(pos){return this.cellInteractive?.(pos,this.valueAt(pos))??!0}announce(pos,isSelectedOverride){const text=this.resolveCellText(pos),announcement=isSelectedOverride??this.isSelectedPos(pos)?this.localize("heatmapSelectedCellLabel",void 0,{cell:text}):text;this.liveText=announcement,this.announcementSink?.announce(announcement)}emitCellClick(pos,source="pointer",select=!0){if(this.isCellInteractive(pos))if(this.multiple&&select&&(this.selectionAnchor=pos,this.selectionRangeBase=void 0,this.toggleSelectionPositions([pos],source)),"week"in pos){const{date,value}=this.calendarCellAt(pos);this.emit("lr-cell-click",{date,value})}else{const value=this.matrixValues[pos.row]?.[pos.col]??-1;this.emit("lr-cell-click",{row:pos.row,col:pos.col,value})}}get currentSelectedPositions(){return this.selectionPreview??this.selectedPositions}selectedPaintPositions(){if(this.multiple)return[...this.currentSelectedPositions.values()];const selected=this.selectedCell;if(!selected)return[];if(this.effectiveMode==="calendar"){const match=selected.date?this.cachedCalendarCellsByDate.get(selected.date):void 0;return match?[match]:[]}return selected.row!=null&&selected.col!=null?[{row:selected.row,col:selected.col}]:[]}rebuildSelectedPositions(){const positions=new Map,dates=this.effectiveMode==="calendar"?new Map(this.cachedAccessiblePositions.map(pos=>[this.accessibleCellIdentity(pos),pos])):void 0,input=Array.isArray(this.selectedCells)?this.selectedCells:[];for(const cell of input.slice(0,MAX_HEATMAP_CELLS)){if(!cell||typeof cell!="object")continue;const pos=dates?typeof cell.date=="string"?dates.get(cell.date):void 0:Number.isInteger(cell.row)&&Number.isInteger(cell.col)?this.cachedAccessiblePositionsByKey.get(`matrix-${cell.row}-${cell.col}`):void 0;pos&&positions.set(this.accessibleCellKey(pos),pos)}this.selectedPositions=positions}selectionCoordinates(pos){return"week"in pos?{row:pos.weekday,col:pos.week}:pos}proposeSelection(positions,source){if(positions.size===this.selectedPositions.size&&[...positions.keys()].every(key=>this.selectedPositions.has(key)))return;this.proposedSelectionKeys=new Set(positions.keys());const selectedCells=[...positions.values()].sort((a,b)=>{const first=this.selectionCoordinates(a),second=this.selectionCoordinates(b);return first.row-second.row||first.col-second.col}).map(pos=>"week"in pos?{date:pos.date}:{row:pos.row,col:pos.col});this.emit("lr-selection-change",{selectedCells,source})}toggleSelectionPositions(positions,source){if(!this.multiple||positions.length===0)return;const next=new Map(this.selectedPositions),remove=positions.every(pos=>next.has(this.accessibleCellKey(pos)));for(const pos of positions){const key=this.accessibleCellKey(pos);remove?next.delete(key):next.set(key,pos)}this.proposeSelection(next,source)}toggleSelectionAxis(index,row){!this.multiple||!Number.isInteger(index)||index<0||(this.cancelSelectionGesture(),this.selectionRangeBase=void 0,this.toggleSelectionPositions(this.cachedAccessiblePositions.filter(pos=>{const coordinates=this.selectionCoordinates(pos);return(row?coordinates.row:coordinates.col)===index}),row?"row":"column"))}selectionKeyDown(event,pos){if(!this.multiple)return!1;if(event.key==="Escape"&&this.selectionGesture)return event.preventDefault(),this.cancelSelectionGesture(),!0;if(event.key!==" "||!pos||!(event.shiftKey||event.ctrlKey||event.metaKey))return!1;event.preventDefault();const coordinates=this.selectionCoordinates(pos);return event.ctrlKey||event.metaKey?this.toggleColumnSelection(coordinates.col):this.toggleRowSelection(coordinates.row),!0}extendSelection(previous,next,range){if(!this.multiple)return;if(!range){this.selectionAnchor=next,this.selectionRangeBase=void 0;return}this.selectionAnchor??=previous??next,this.selectionRangeBase??=new Map(this.selectedPositions);const from=this.selectionCoordinates(this.selectionAnchor),to=this.selectionCoordinates(next),selected=new Map(this.selectionRangeBase);for(const pos of this.cachedAccessiblePositions){const{row,col}=this.selectionCoordinates(pos);row>=Math.min(from.row,to.row)&&row<=Math.max(from.row,to.row)&&col>=Math.min(from.col,to.col)&&col<=Math.max(from.col,to.col)&&selected.set(this.accessibleCellKey(pos),pos)}return this.proposeSelection(selected,"keyboard"),new Set(selected.keys())}selectionPointerPosition(event){if(!this.canvas)return null;const rect=this.canvas.getBoundingClientRect();return this.hitTest(event.clientX-rect.left,event.clientY-rect.top)}paintSelectionTo(pos){const gesture=this.selectionGesture;if(!gesture)return;this.samePos(pos,gesture.previous)||(gesture.moved=!0);const from=this.selectionCoordinates(gesture.previous),to=this.selectionCoordinates(pos),steps=Math.max(Math.abs(to.row-from.row),Math.abs(to.col-from.col),1);for(let step=0;step<=steps;step++){const row=Math.round(from.row+(to.row-from.row)*step/steps),col=Math.round(from.col+(to.col-from.col)*step/steps),key=this.effectiveMode==="calendar"?`calendar-${col}-${row}`:`matrix-${row}-${col}`,candidate=this.cachedAccessiblePositionsByKey.get(key);candidate&&(gesture.selecting?gesture.cells.set(key,candidate):gesture.cells.delete(key))}gesture.previous=pos,this.selectionPreview=new Map(gesture.cells)}cancelSelectionGesture(){const gesture=this.selectionGesture;if(this.selectionGesture=void 0,this.selectionPreview=void 0,!!gesture){this.suppressSelectionClick=!0;try{gesture.target.hasPointerCapture(gesture.pointerId)&&gesture.target.releasePointerCapture(gesture.pointerId)}catch{}}}consumeSelectionClick(event){return!this.suppressSelectionClick||event.detail===0?!1:(this.suppressSelectionClick=!1,!0)}get gridScrollport(){return this.shadowRoot?.querySelector('[part="grid"]')??null}measureTooltip(){if(!this.gridScrollport)return;const tooltip=this.shadowRoot?.querySelector('[part="tooltip"]');if(!tooltip||tooltip.hidden)return;const view=this.ownerDocument.defaultView,gap=view?Math.abs(finiteNumber(Number.parseFloat(view.getComputedStyle(tooltip).marginBlockStart),0)):0,inline=tooltip.offsetWidth,block=tooltip.offsetHeight+gap;inline===this.tooltipSize.inline&&block===this.tooltipSize.block||(this.tooltipSize={inline,block},this.requestUpdate())}tooltipAnchor(pos){const rect=this.cellRect(pos),center=rect.x+rect.w/2,port=this.gridScrollport;if(!port)return{style:{left:`${center}px`,top:`${rect.y}px`},below:!1};const{inline,block}=this.tooltipSize,windowStart=port.scrollLeft+(this.freezesRowLabels?this.matrixPadLeft:0),windowEnd=port.scrollLeft+port.clientWidth,windowTop=port.scrollTop+(this.freezesColLabels?this.matrixPadTop:0),windowBottom=port.scrollTop+port.clientHeight,below=rect.y-block<windowTop&&rect.y+rect.h+block<=windowBottom;return{style:{left:`${Math.max(windowStart+inline/2,Math.min(center,windowEnd-inline/2))}px`,top:`${below?rect.y+rect.h:rect.y}px`},below}}scrollCellIntoView(pos){const port=this.gridScrollport;if(!port)return;const rect=this.cellRect(pos),bandInline=this.freezesRowLabels?this.matrixPadLeft:0,bandBlock=this.freezesColLabels?this.matrixPadTop:0,left=Math.min(Math.max(port.scrollLeft,rect.x+rect.w-port.clientWidth),rect.x-bandInline),top=Math.min(Math.max(port.scrollTop,rect.y+rect.h-port.clientHeight),rect.y-bandBlock);left!==port.scrollLeft&&(port.scrollLeft=left),top!==port.scrollTop&&(port.scrollTop=top)}samePos(a,b){return a===b?!0:!a||!b?!1:"week"in a&&"week"in b?a.week===b.week&&a.weekday===b.weekday:"row"in a&&"row"in b?a.row===b.row&&a.col===b.col:!1}onMatrixKeyDown(e){const rows=this.matrixRowLabels.length,cols=this.matrixColLabels.length;if(rows===0||cols===0)return;if(e.key==="Enter"||e.key===" "){e.preventDefault(),this.focusedCell&&this.emitCellClick(this.focusedCell,"keyboard");return}if(!ARROW_KEYS.has(e.key))return;if(e.preventDefault(),!this.focusedCell||!("row"in this.focusedCell)){const next2=this.firstInteractiveMatrixCell(rows,cols);if(!next2)return;this.focusedCell=next2,this.scrollCellIntoView(next2);return}const{row,col}=this.focusedCell;let dRow=0,dCol=0;e.key==="ArrowUp"?dRow=-1:e.key==="ArrowDown"?dRow=1:e.key==="ArrowLeft"?dCol=-1:e.key==="ArrowRight"&&(dCol=1);const next=this.nextInteractiveMatrixCell(row,col,dRow,dCol,rows,cols);this.focusedCell=next,this.scrollCellIntoView(next)}onCalendarKeyDown(e){const{weekCount}=this.cachedCalendarGrid;if(weekCount===0)return;if(e.key==="Enter"||e.key===" "){e.preventDefault(),this.focusedCell&&this.emitCellClick(this.focusedCell,"keyboard");return}if(!ARROW_KEYS.has(e.key))return;if(e.preventDefault(),!this.focusedCell||!("week"in this.focusedCell)){const next2=this.firstInteractiveCalendarCell(weekCount);if(!next2)return;this.focusedCell=next2;return}const{week,weekday}=this.focusedCell;let dWeek=0,dWeekday=0;e.key==="ArrowUp"?dWeekday=-1:e.key==="ArrowDown"?dWeekday=1:e.key==="ArrowLeft"?dWeek=-1:e.key==="ArrowRight"&&(dWeek=1);const next=this.nextInteractiveCalendarCell(week,weekday,dWeek,dWeekday,weekCount);this.focusedCell=next}resolveCanvasColor(value,cs){const cached=this.canvasColorCache.get(value);if(cached!==void 0)return cached;const fallback=this.noDataFill(cs);let candidate=value;if(value.includes("var(")){if(this.colorProbe||(this.colorProbe=this.ownerDocument.createElement("span"),this.colorProbe.style.cssText="position:absolute;width:0;height:0;overflow:hidden;visibility:hidden;pointer-events:none;",this.shadowRoot.appendChild(this.colorProbe)),this.colorProbe.style.color="",this.colorProbe.style.color=value,!this.colorProbe.style.color)return this.canvasColorCache.set(value,fallback),fallback;candidate=this.ownerDocument.defaultView?.getComputedStyle(this.colorProbe).color||fallback}const ctx=getScratchCtx(this.ownerDocument);if(!ctx)return fallback;ctx.fillStyle="rgb(1, 2, 3)";const firstSentinel=ctx.fillStyle;ctx.fillStyle=candidate;let resolved=ctx.fillStyle;if(resolved===firstSentinel){ctx.fillStyle="rgb(4, 5, 6)";const secondSentinel=ctx.fillStyle;ctx.fillStyle=candidate,resolved=ctx.fillStyle,resolved===secondSentinel&&(resolved=fallback)}return this.canvasColorCache.set(value,resolved),resolved}rebuildAccessiblePositions(){const positions=[];if(this.effectiveMode==="calendar"){const{weekCount}=this.cachedCalendarGrid;for(let week=0;week<weekCount;week++)for(let weekday=0;weekday<7;weekday++){const pos=this.calendarPos(week,weekday);this.isCellInteractive(pos)&&positions.push(pos)}}else for(let row=0;row<this.matrixRowLabels.length;row++)for(let col=0;col<this.matrixColLabels.length;col++){const pos={row,col};this.isCellInteractive(pos)&&positions.push(pos)}this.cachedAccessiblePositions=positions,this.cachedAccessiblePositionsByKey=new Map(positions.map(position=>[this.accessibleCellKey(position),position])),this.cachedAccessiblePositionIndexByKey=new Map(positions.map((position,index)=>[this.accessibleCellKey(position),index]))}accessibleCellPositions(){return this.cachedAccessiblePositions}accessibleCellKey(pos){return"week"in pos?`calendar-${pos.week}-${pos.weekday}`:`matrix-${pos.row}-${pos.col}`}accessibleCellIdentity(pos){return"week"in pos?pos.date:this.accessibleCellKey(pos)}accessibleCellAtKey(key){return this.cachedAccessiblePositionsByKey.get(key)??null}focusAccessibleCell(pos){pos&&this.updateComplete.then(()=>{[...this.shadowRoot?.querySelectorAll('[part="cell"]')??[]].find(candidate=>candidate.dataset.cellKey===this.accessibleCellKey(pos))?.focus()})}renderAccessibleCells(){if(!this.accessibleCells)return html``;const positions=this.accessibleCellPositions(),tabStop=this.focusedCell??positions[0]??null,focusIndex=tabStop?this.cachedAccessiblePositionIndexByKey.get(this.accessibleCellKey(tabStop))??0:0,start=Math.max(0,Math.min(Math.max(0,positions.length-MAX_ACCESSIBLE_HEATMAP_CELLS),focusIndex-Math.floor(MAX_ACCESSIBLE_HEATMAP_CELLS/2))),renderedPositions=positions.slice(start,start+MAX_ACCESSIBLE_HEATMAP_CELLS),renderedRows=new Map;for(const pos of renderedPositions){const rowIndex="week"in pos?pos.weekday+1:pos.row+1,row=renderedRows.get(rowIndex);row?row.push(pos):renderedRows.set(rowIndex,[pos])}const rowCount=this.effectiveMode==="calendar"?7:this.matrixRowLabels.length,colCount=this.effectiveMode==="calendar"?this.cachedCalendarGrid.weekCount:this.matrixColLabels.length;return html`
2
2
  <div
3
3
  part="cells"
4
4
  role="grid"
@@ -1,4 +1,4 @@
1
- var __decorate=function(decorators,target,key,desc){var c=arguments.length,r=c<3?target:desc===null?desc=Object.getOwnPropertyDescriptor(target,key):desc,d;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")r=Reflect.decorate(decorators,target,key,desc);else for(var i=decorators.length-1;i>=0;i--)(d=decorators[i])&&(r=(c<3?d(r):c>3?d(target,key,r):d(target,key))||r);return c>3&&r&&Object.defineProperty(target,key,r),r};import{html,nothing}from"lit";import{property,query,state}from"lit/decorators.js";import{styleMap}from"lit/directives/style-map.js";import{keyed}from"lit/directives/keyed.js";import{LyraElement}from"../../../internal/lyra-element.js";import{DocumentAnchorTarget}from"../../../internal/anchor-target.js";import{safeMediaSrc}from"../../../internal/safe-url.js";import{hostAriaLabel,srOnly}from"../../../internal/a11y.js";import{finiteNumber}from"../../../internal/numbers.js";import{chevronIcon}from"../../../internal/icons.js";import{getNumberFormat}from"../../../internal/intl-cache.js";import{styles}from"./image-viewer.styles.js";import{sanitizePercentRect}from"../../../internal/safe-css.js";import{acquireAnnouncementSink}from"../../../internal/announcer.js";import{LYRA_DEFAULT_anchorJumped,LYRA_DEFAULT_anchorJumpedToPage,LYRA_DEFAULT_anchorNotFound,LYRA_DEFAULT_documentPreviewEmpty,LYRA_DEFAULT_documentPreviewTypeImage,LYRA_DEFAULT_imageViewerAnnotate,LYRA_DEFAULT_imageViewerAnnotationAdded,LYRA_DEFAULT_imageViewerAnnotationBoxPosition,LYRA_DEFAULT_imageViewerAnnotationCancelled,LYRA_DEFAULT_imageViewerAnnotationHint,LYRA_DEFAULT_imageViewerFailedToLoad,LYRA_DEFAULT_imageViewerFitActual,LYRA_DEFAULT_imageViewerFitContain,LYRA_DEFAULT_imageViewerFitLabel,LYRA_DEFAULT_imageViewerFitWidth,LYRA_DEFAULT_imageViewerHighlightsLabel,LYRA_DEFAULT_imageViewerLabel,LYRA_DEFAULT_imageViewerRotate,LYRA_DEFAULT_imageViewerUnlabeledHighlight}from"../../../internal/default-strings.generated.js";const MIN_REGION_PERCENT=2,ARROW_STEP_PERCENT=2,IMAGE_VIEWER_HIGHLIGHT_LIMIT=200,IMAGE_FITS=new Set(["contain","width","actual"]);function normalizeImageFit(value){return IMAGE_FITS.has(value)?value:"contain"}function normalizeImageRotation(value){const degrees=typeof value=="number"?finiteNumber(value,0):0;return(Math.round(degrees/90)%4+4)%4*90}function normalizeImageRegionRect(value){const rect=sanitizePercentRect(value);if(!(!rect||rect.x<0||rect.y<0||rect.width<=0||rect.height<=0||rect.x+rect.width>100||rect.y+rect.height>100))return rect}function normalizeHighlightTone(value){return value==="success"||value==="warning"||value==="danger"||value==="neutral"?value:"accent"}function clamp(value,min,max){return Math.min(max,Math.max(min,value))}function screenPercentToImagePercent(px,py,rotation){switch(rotation){case 90:return{x:py,y:100-px};case 180:return{x:100-px,y:100-py};case 270:return{x:100-py,y:px};default:return{x:px,y:py}}}class LyraImageViewerBase extends LyraElement{}class LyraImageViewer extends DocumentAnchorTarget(LyraImageViewerBase){constructor(){super(...arguments),this.src="",this.name="",this._fit="contain",this.zoom=1,this.minZoom=.5,this.maxZoom=4,this.zoomStep=.25,this._rotation=0,this.annotatable=!1,this.anchorKinds=["region"],this.loadState={kind:"idle"},this.draft=null,this.revealTarget=null,this.highlightFocusId=null,this.mediaLayoutSize=null,this.zoomIn=()=>this.frameEl?.zoomIn(),this.zoomOut=()=>this.frameEl?.zoomOut(),this.resetZoom=()=>this.frameEl?.resetZoom(),this.onImgLoad=event=>{const img=event.target;img===this.shadowRoot?.querySelector('[part="image"]')&&(this.loadState={kind:"loaded"},this.emit("lr-load",{naturalWidth:img.naturalWidth,naturalHeight:img.naturalHeight}))},this.onImgError=event=>{event.target===this.shadowRoot?.querySelector('[part="image"]')&&(this.cancelPointerDraft(),this.revealTarget=null,this.loadState={kind:"error"},this.announceLoadError(),this.emit("lr-render-error",{error:new Error("The image failed to load.")}))},this.onFrameZoomChange=event=>{this.zoom=event.detail.zoom},this.toggleAnnotatable=()=>{this.hasOperableContent&&(this.annotatable=!this.annotatable)},this.onFitChange=event=>{this.fit=event.target.value},this.onWrapperKeyDown=event=>{if(event.target===event.currentTarget&&!(!this.annotatable||!this.hasOperableContent)){if(!this.draft){event.key==="Enter"&&(event.preventDefault(),this.draft={x:37.5,y:37.5,width:25,height:25},this.announceDraftPosition());return}switch(event.key){case"ArrowLeft":event.preventDefault(),event.shiftKey?this.draft={...this.draft,width:clamp(this.draft.width-ARROW_STEP_PERCENT,MIN_REGION_PERCENT,100-this.draft.x)}:this.draft={...this.draft,x:clamp(this.draft.x-ARROW_STEP_PERCENT,0,100-this.draft.width)};break;case"ArrowRight":event.preventDefault(),event.shiftKey?this.draft={...this.draft,width:clamp(this.draft.width+ARROW_STEP_PERCENT,MIN_REGION_PERCENT,100-this.draft.x)}:this.draft={...this.draft,x:clamp(this.draft.x+ARROW_STEP_PERCENT,0,100-this.draft.width)};break;case"ArrowUp":event.preventDefault(),event.shiftKey?this.draft={...this.draft,height:clamp(this.draft.height-ARROW_STEP_PERCENT,MIN_REGION_PERCENT,100-this.draft.y)}:this.draft={...this.draft,y:clamp(this.draft.y-ARROW_STEP_PERCENT,0,100-this.draft.height)};break;case"ArrowDown":event.preventDefault(),event.shiftKey?this.draft={...this.draft,height:clamp(this.draft.height+ARROW_STEP_PERCENT,MIN_REGION_PERCENT,100-this.draft.y)}:this.draft={...this.draft,y:clamp(this.draft.y+ARROW_STEP_PERCENT,0,100-this.draft.height)};break;case"Enter":event.preventDefault(),this.commitDraft();return;case"Escape":event.preventDefault(),this.draft=null,this.liveRegion?.announce(this.localize("imageViewerAnnotationCancelled"),{force:!0});return;default:return}this.announceDraftPosition()}},this.pointerDraftId=null,this.pointerOrigin=null,this.onWrapperPointerDown=event=>{if(!this.annotatable||!this.hasOperableContent||!this.wrapperEl||!event.isPrimary||event.button!==0||this.pointerDraftId!==null)return;const rect=this.wrapperEl.getBoundingClientRect(),px=clamp((event.clientX-rect.left)/rect.width*100,0,100),py=clamp((event.clientY-rect.top)/rect.height*100,0,100),origin=screenPercentToImagePercent(px,py,this.safeRotation);this.pointerOrigin=origin,this.pointerDraftId=event.pointerId;try{this.wrapperEl.setPointerCapture(event.pointerId)}catch{}this.draft={x:origin.x,y:origin.y,width:0,height:0},event.preventDefault()},this.onWrapperPointerMove=event=>{if(this.pointerDraftId!==event.pointerId||!this.pointerOrigin||!this.wrapperEl)return;const rect=this.wrapperEl.getBoundingClientRect(),px=clamp((event.clientX-rect.left)/rect.width*100,0,100),py=clamp((event.clientY-rect.top)/rect.height*100,0,100),point=screenPercentToImagePercent(px,py,this.safeRotation),x=Math.min(this.pointerOrigin.x,point.x),y=Math.min(this.pointerOrigin.y,point.y),width=Math.abs(point.x-this.pointerOrigin.x),height=Math.abs(point.y-this.pointerOrigin.y);this.draft={x,y,width,height}},this.onWrapperPointerUp=event=>{if(this.pointerDraftId!==event.pointerId)return;const draft=this.draft;this.cancelPointerDraft(event.pointerId),draft&&draft.width>=MIN_REGION_PERCENT&&draft.height>=MIN_REGION_PERCENT&&(this.draft=draft,this.commitDraft())}}static{this.defaultStrings={...super.defaultStrings,anchorJumped:LYRA_DEFAULT_anchorJumped,anchorJumpedToPage:LYRA_DEFAULT_anchorJumpedToPage,anchorNotFound:LYRA_DEFAULT_anchorNotFound,documentPreviewEmpty:LYRA_DEFAULT_documentPreviewEmpty,documentPreviewTypeImage:LYRA_DEFAULT_documentPreviewTypeImage,imageViewerAnnotate:LYRA_DEFAULT_imageViewerAnnotate,imageViewerAnnotationAdded:LYRA_DEFAULT_imageViewerAnnotationAdded,imageViewerAnnotationBoxPosition:LYRA_DEFAULT_imageViewerAnnotationBoxPosition,imageViewerAnnotationCancelled:LYRA_DEFAULT_imageViewerAnnotationCancelled,imageViewerAnnotationHint:LYRA_DEFAULT_imageViewerAnnotationHint,imageViewerFailedToLoad:LYRA_DEFAULT_imageViewerFailedToLoad,imageViewerFitActual:LYRA_DEFAULT_imageViewerFitActual,imageViewerFitContain:LYRA_DEFAULT_imageViewerFitContain,imageViewerFitLabel:LYRA_DEFAULT_imageViewerFitLabel,imageViewerFitWidth:LYRA_DEFAULT_imageViewerFitWidth,imageViewerHighlightsLabel:LYRA_DEFAULT_imageViewerHighlightsLabel,imageViewerLabel:LYRA_DEFAULT_imageViewerLabel,imageViewerRotate:LYRA_DEFAULT_imageViewerRotate,imageViewerUnlabeledHighlight:LYRA_DEFAULT_imageViewerUnlabeledHighlight}}static{this.styles=[LyraElement.styles,styles,srOnly]}static{this.immutableEventDetails=Object.freeze(["lr-annotation-create"])}get fit(){return this._fit}set fit(value){const old=this._fit;this._fit=normalizeImageFit(value),this.requestUpdate("fit",old)}get rotation(){return this._rotation}set rotation(value){const old=this._rotation;this._rotation=normalizeImageRotation(value),this.requestUpdate("rotation",old)}get safeRotation(){return this.rotation}get hasOperableContent(){return this.loadState.kind==="loaded"}willUpdate(changed){if(super.willUpdate(changed),changed.has("src")){this.cancelPointerDraft(),this.revealTarget=null,this.mediaLayoutSize=null;const safeSrc=this.src?safeMediaSrc(this.src):null;this.loadState=safeSrc?{kind:"loading"}:this.src?{kind:"error"}:{kind:"idle"},this.hasUpdated&&this.src&&!safeSrc&&this.announceLoadError()}changed.has("annotatable")&&(!this.annotatable||!this.hasOperableContent)&&this.cancelPointerDraft()}updated(changed){super.updated(changed),changed.has("rotation")&&changed.get("rotation")!==void 0&&this.emit("lr-rotation-change",{rotation:this.safeRotation}),changed.has("fit")&&changed.get("fit")!==void 0&&this.emit("lr-fit-change",{fit:this.fit}),(changed.has("annotatable")||changed.has("loadState"))&&this.annotatable&&this.hasOperableContent&&(changed.has("loadState")||changed.get("annotatable")!==void 0)&&this.liveRegion?.announce(this.localize("imageViewerAnnotationHint"),{force:!0}),this.syncGeometryObserver()}rotate(){this.rotation=(this.safeRotation+90)%360}async applyAnchor(anchor){if(anchor.kind!=="region"||!this.hasOperableContent)return!1;const rect=normalizeImageRegionRect(anchor.rect);if(!rect)return!1;this.revealTarget=rect,await this.updateComplete;const target=this.shadowRoot?.querySelector("[data-reveal-target]"),viewport=this.frameEl?.shadowRoot?.querySelector('[part="viewport"]');if(!target||!viewport||target.getClientRects().length===0)return!1;target.scrollIntoView({block:"center",inline:"center"}),await new Promise(resolve=>{const view=this.ownerDocument.defaultView;view?view.requestAnimationFrame(()=>resolve()):resolve()});const targetRect=target.getBoundingClientRect(),viewportRect=viewport.getBoundingClientRect();return targetRect.right>viewportRect.left&&targetRect.left<viewportRect.right&&targetRect.bottom>viewportRect.top&&targetRect.top<viewportRect.bottom}connectedCallback(){super.connectedCallback(),this.syncErrorAnnouncementSink()}adoptedCallback(){super.adoptedCallback(),this.disconnectGeometryObserver(),this.releaseErrorAnnouncementSink(),this.syncErrorAnnouncementSink(),this.scheduleAfterUpdate(()=>this.syncGeometryObserver())}disconnectGeometryObserver(){this.geometryObserver?.disconnect(),this.geometryObserver=void 0,this.observedWrapper=void 0,this.geometryFrame!==void 0&&this.geometryFrameOwner?.cancelAnimationFrame(this.geometryFrame),this.geometryFrame=void 0,this.geometryFrameOwner=void 0}updateMediaLayoutSize(width,height){!Number.isFinite(width)||!Number.isFinite(height)||width<=0||height<=0||this.mediaLayoutSize?.width===width&&this.mediaLayoutSize.height===height||(this.mediaLayoutSize={width,height})}scheduleMediaLayoutSize(width,height){const view=this.ownerDocument.defaultView;if(!view){this.updateMediaLayoutSize(width,height);return}this.geometryFrame!==void 0&&this.geometryFrameOwner?.cancelAnimationFrame(this.geometryFrame),this.geometryFrameOwner=view,this.geometryFrame=view.requestAnimationFrame(()=>{this.geometryFrame=void 0,this.geometryFrameOwner=void 0,this.updateMediaLayoutSize(Math.round(width*100)/100,Math.round(height*100)/100)})}syncGeometryObserver(){const wrapper=this.wrapperEl;if(wrapper===this.observedWrapper||(this.disconnectGeometryObserver(),!wrapper))return;this.observedWrapper=wrapper,this.scheduleMediaLayoutSize(wrapper.offsetWidth,wrapper.offsetHeight);const ResizeObserverConstructor=this.ownerDocument.defaultView?.ResizeObserver;ResizeObserverConstructor&&(this.geometryObserver=new ResizeObserverConstructor(entries=>{const entry=entries.find(candidate=>candidate.target===this.observedWrapper);entry&&this.scheduleMediaLayoutSize(entry.contentRect.width,entry.contentRect.height)}),this.geometryObserver.observe(wrapper))}syncErrorAnnouncementSink(){this.isConnected&&this.errorAnnouncementSink?.element.ownerDocument!==this.ownerDocument&&(this.releaseErrorAnnouncementSink(),this.errorAnnouncementSink=acquireAnnouncementSink("assertive",{document:this.ownerDocument,source:this}))}releaseErrorAnnouncementSink(){this.errorAnnouncementSink?.release(),this.errorAnnouncementSink=void 0}announceLoadError(){this.errorAnnouncementSink?.announce(this.localize("imageViewerFailedToLoad"))}onHighlightActivate(id){this.activeHighlightId=id,this.emit("lr-highlight-activate",{highlightId:id})}announceDraftPosition(){if(!this.draft)return;const formatter=getNumberFormat(this.effectiveLocale,{maximumFractionDigits:0,useGrouping:!1});this.liveRegion?.announce(this.localize("imageViewerAnnotationBoxPosition",void 0,{x:formatter.format(Math.round(this.draft.x)),y:formatter.format(Math.round(this.draft.y)),width:formatter.format(Math.round(this.draft.width)),height:formatter.format(Math.round(this.draft.height))}))}commitDraft(){if(!this.draft)return;const rect={x:this.draft.x,y:this.draft.y,width:this.draft.width,height:this.draft.height};this.draft=null,this.emit("lr-annotation-create",{anchor:{kind:"region",rect}}),this.liveRegion?.announce(this.localize("imageViewerAnnotationAdded"),{force:!0})}cancelPointerDraft(pointerId=this.pointerDraftId,releaseCapture=!0){if(pointerId!=null&&this.pointerDraftId!==pointerId)return;const wrapper=this.wrapperEl,capturedPointerId=this.pointerDraftId;if(this.pointerDraftId=null,this.pointerOrigin=null,this.draft=null,releaseCapture&&wrapper&&capturedPointerId!=null)try{wrapper.releasePointerCapture(capturedPointerId)}catch{}}canonicalRegionHighlights(){const ids=new Set,result=[];for(const highlight of this.highlights){if(!highlight||typeof highlight.id!="string"||highlight.id.trim().length===0||ids.has(highlight.id)||highlight.anchor.kind!=="region")continue;const rect=normalizeImageRegionRect(highlight.anchor.rect);rect&&(ids.add(highlight.id),result.push({highlight,rect}))}return result}boundedRegionHighlights(){const all=this.canonicalRegionHighlights();if(all.length<=IMAGE_VIEWER_HIGHLIGHT_LIMIT)return{all,visible:all};const visible=all.slice(0,IMAGE_VIEWER_HIGHLIGHT_LIMIT),active=this.activeHighlightId?all.find(entry=>entry.highlight.id===this.activeHighlightId):void 0;return active&&!visible.includes(active)&&(visible[visible.length-1]=active),{all,visible}}onHighlightFocus(id){this.highlightFocusId=id}onHighlightKeyDown(event,id){const buttons=[...this.shadowRoot.querySelectorAll('[part="highlight"]')];if(buttons.length<2)return;const current=buttons.findIndex(button=>button.dataset.highlightId===id),rtl=this.effectiveDirection==="rtl";let next=current;if(event.key==="Home")next=0;else if(event.key==="End")next=buttons.length-1;else if(event.key==="ArrowDown"||event.key===(rtl?"ArrowLeft":"ArrowRight"))next=(current+1)%buttons.length;else if(event.key==="ArrowUp"||event.key===(rtl?"ArrowRight":"ArrowLeft"))next=(current-1+buttons.length)%buttons.length;else return;event.preventDefault();const target=buttons[next];this.highlightFocusId=target.dataset.highlightId??null,target.focus(),this.requestUpdate()}renderHighlights(){if(!this.hasOperableContent)return nothing;const{all:regionHighlights,visible}=this.boundedRegionHighlights();if(!regionHighlights.length)return nothing;const formatter=getNumberFormat(this.effectiveLocale,{maximumFractionDigits:0,useGrouping:!1}),preferredFocusId=visible.some(({highlight})=>highlight.id===this.highlightFocusId)?this.highlightFocusId:visible.some(({highlight})=>highlight.id===this.activeHighlightId)?this.activeHighlightId:visible[0]?.highlight.id??null;return html`<div
1
+ var __decorate=function(decorators,target,key,desc){var c=arguments.length,r=c<3?target:desc===null?desc=Object.getOwnPropertyDescriptor(target,key):desc,d;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")r=Reflect.decorate(decorators,target,key,desc);else for(var i=decorators.length-1;i>=0;i--)(d=decorators[i])&&(r=(c<3?d(r):c>3?d(target,key,r):d(target,key))||r);return c>3&&r&&Object.defineProperty(target,key,r),r};import{html,nothing}from"lit";import{property,query,state}from"lit/decorators.js";import{styleMap}from"lit/directives/style-map.js";import{keyed}from"lit/directives/keyed.js";import{LyraElement}from"../../../internal/lyra-element.js";import{DocumentAnchorTarget}from"../../../internal/anchor-target.js";import{safeMediaSrc}from"../../../internal/safe-url.js";import{hostAriaLabel,srOnly}from"../../../internal/a11y.js";import{finiteNumber}from"../../../internal/numbers.js";import{chevronIcon}from"../../../internal/icons.js";import{getNumberFormat}from"../../../internal/intl-cache.js";import{styles}from"./image-viewer.styles.js";import{sanitizePercentRect}from"../../../internal/safe-css.js";import{acquireAnnouncementSink}from"../../../internal/announcer.js";import{normalizeImageFit}from"../../../internal/image-fit.js";import{LYRA_DEFAULT_anchorJumped,LYRA_DEFAULT_anchorJumpedToPage,LYRA_DEFAULT_anchorNotFound,LYRA_DEFAULT_documentPreviewEmpty,LYRA_DEFAULT_documentPreviewTypeImage,LYRA_DEFAULT_imageViewerAnnotate,LYRA_DEFAULT_imageViewerAnnotationAdded,LYRA_DEFAULT_imageViewerAnnotationBoxPosition,LYRA_DEFAULT_imageViewerAnnotationCancelled,LYRA_DEFAULT_imageViewerAnnotationHint,LYRA_DEFAULT_imageViewerFailedToLoad,LYRA_DEFAULT_imageViewerFitActual,LYRA_DEFAULT_imageViewerFitContain,LYRA_DEFAULT_imageViewerFitLabel,LYRA_DEFAULT_imageViewerFitWidth,LYRA_DEFAULT_imageViewerHighlightsLabel,LYRA_DEFAULT_imageViewerLabel,LYRA_DEFAULT_imageViewerRotate,LYRA_DEFAULT_imageViewerUnlabeledHighlight}from"../../../internal/default-strings.generated.js";const MIN_REGION_PERCENT=2,ARROW_STEP_PERCENT=2,IMAGE_VIEWER_HIGHLIGHT_LIMIT=200;function normalizeImageRotation(value){const degrees=typeof value=="number"?finiteNumber(value,0):0;return(Math.round(degrees/90)%4+4)%4*90}function normalizeImageRegionRect(value){const rect=sanitizePercentRect(value);if(!(!rect||rect.x<0||rect.y<0||rect.width<=0||rect.height<=0||rect.x+rect.width>100||rect.y+rect.height>100))return rect}function normalizeHighlightTone(value){return value==="success"||value==="warning"||value==="danger"||value==="neutral"?value:"accent"}function clamp(value,min,max){return Math.min(max,Math.max(min,value))}function screenPercentToImagePercent(px,py,rotation){switch(rotation){case 90:return{x:py,y:100-px};case 180:return{x:100-px,y:100-py};case 270:return{x:100-py,y:px};default:return{x:px,y:py}}}class LyraImageViewerBase extends LyraElement{}class LyraImageViewer extends DocumentAnchorTarget(LyraImageViewerBase){constructor(){super(...arguments),this.src="",this.name="",this._fit="contain",this.zoom=1,this.minZoom=.5,this.maxZoom=4,this.zoomStep=.25,this._rotation=0,this.annotatable=!1,this.anchorKinds=["region"],this.loadState={kind:"idle"},this.draft=null,this.revealTarget=null,this.highlightFocusId=null,this.mediaLayoutSize=null,this.zoomIn=()=>this.frameEl?.zoomIn(),this.zoomOut=()=>this.frameEl?.zoomOut(),this.resetZoom=()=>this.frameEl?.resetZoom(),this.onImgLoad=event=>{const img=event.target;img===this.shadowRoot?.querySelector('[part="image"]')&&(this.loadState={kind:"loaded"},this.emit("lr-load",{naturalWidth:img.naturalWidth,naturalHeight:img.naturalHeight}))},this.onImgError=event=>{event.target===this.shadowRoot?.querySelector('[part="image"]')&&(this.cancelPointerDraft(),this.revealTarget=null,this.loadState={kind:"error"},this.announceLoadError(),this.emit("lr-render-error",{error:new Error("The image failed to load.")}))},this.onFrameZoomChange=event=>{this.zoom=event.detail.zoom},this.toggleAnnotatable=()=>{this.hasOperableContent&&(this.annotatable=!this.annotatable)},this.onFitChange=event=>{this.fit=event.target.value},this.onWrapperKeyDown=event=>{if(event.target===event.currentTarget&&!(!this.annotatable||!this.hasOperableContent)){if(!this.draft){event.key==="Enter"&&(event.preventDefault(),this.draft={x:37.5,y:37.5,width:25,height:25},this.announceDraftPosition());return}switch(event.key){case"ArrowLeft":event.preventDefault(),event.shiftKey?this.draft={...this.draft,width:clamp(this.draft.width-ARROW_STEP_PERCENT,MIN_REGION_PERCENT,100-this.draft.x)}:this.draft={...this.draft,x:clamp(this.draft.x-ARROW_STEP_PERCENT,0,100-this.draft.width)};break;case"ArrowRight":event.preventDefault(),event.shiftKey?this.draft={...this.draft,width:clamp(this.draft.width+ARROW_STEP_PERCENT,MIN_REGION_PERCENT,100-this.draft.x)}:this.draft={...this.draft,x:clamp(this.draft.x+ARROW_STEP_PERCENT,0,100-this.draft.width)};break;case"ArrowUp":event.preventDefault(),event.shiftKey?this.draft={...this.draft,height:clamp(this.draft.height-ARROW_STEP_PERCENT,MIN_REGION_PERCENT,100-this.draft.y)}:this.draft={...this.draft,y:clamp(this.draft.y-ARROW_STEP_PERCENT,0,100-this.draft.height)};break;case"ArrowDown":event.preventDefault(),event.shiftKey?this.draft={...this.draft,height:clamp(this.draft.height+ARROW_STEP_PERCENT,MIN_REGION_PERCENT,100-this.draft.y)}:this.draft={...this.draft,y:clamp(this.draft.y+ARROW_STEP_PERCENT,0,100-this.draft.height)};break;case"Enter":event.preventDefault(),this.commitDraft();return;case"Escape":event.preventDefault(),this.draft=null,this.liveRegion?.announce(this.localize("imageViewerAnnotationCancelled"),{force:!0});return;default:return}this.announceDraftPosition()}},this.pointerDraftId=null,this.pointerOrigin=null,this.onWrapperPointerDown=event=>{if(!this.annotatable||!this.hasOperableContent||!this.wrapperEl||!event.isPrimary||event.button!==0||this.pointerDraftId!==null)return;const rect=this.wrapperEl.getBoundingClientRect(),px=clamp((event.clientX-rect.left)/rect.width*100,0,100),py=clamp((event.clientY-rect.top)/rect.height*100,0,100),origin=screenPercentToImagePercent(px,py,this.safeRotation);this.pointerOrigin=origin,this.pointerDraftId=event.pointerId;try{this.wrapperEl.setPointerCapture(event.pointerId)}catch{}this.draft={x:origin.x,y:origin.y,width:0,height:0},event.preventDefault()},this.onWrapperPointerMove=event=>{if(this.pointerDraftId!==event.pointerId||!this.pointerOrigin||!this.wrapperEl)return;const rect=this.wrapperEl.getBoundingClientRect(),px=clamp((event.clientX-rect.left)/rect.width*100,0,100),py=clamp((event.clientY-rect.top)/rect.height*100,0,100),point=screenPercentToImagePercent(px,py,this.safeRotation),x=Math.min(this.pointerOrigin.x,point.x),y=Math.min(this.pointerOrigin.y,point.y),width=Math.abs(point.x-this.pointerOrigin.x),height=Math.abs(point.y-this.pointerOrigin.y);this.draft={x,y,width,height}},this.onWrapperPointerUp=event=>{if(this.pointerDraftId!==event.pointerId)return;const draft=this.draft;this.cancelPointerDraft(event.pointerId),draft&&draft.width>=MIN_REGION_PERCENT&&draft.height>=MIN_REGION_PERCENT&&(this.draft=draft,this.commitDraft())}}static{this.defaultStrings={...super.defaultStrings,anchorJumped:LYRA_DEFAULT_anchorJumped,anchorJumpedToPage:LYRA_DEFAULT_anchorJumpedToPage,anchorNotFound:LYRA_DEFAULT_anchorNotFound,documentPreviewEmpty:LYRA_DEFAULT_documentPreviewEmpty,documentPreviewTypeImage:LYRA_DEFAULT_documentPreviewTypeImage,imageViewerAnnotate:LYRA_DEFAULT_imageViewerAnnotate,imageViewerAnnotationAdded:LYRA_DEFAULT_imageViewerAnnotationAdded,imageViewerAnnotationBoxPosition:LYRA_DEFAULT_imageViewerAnnotationBoxPosition,imageViewerAnnotationCancelled:LYRA_DEFAULT_imageViewerAnnotationCancelled,imageViewerAnnotationHint:LYRA_DEFAULT_imageViewerAnnotationHint,imageViewerFailedToLoad:LYRA_DEFAULT_imageViewerFailedToLoad,imageViewerFitActual:LYRA_DEFAULT_imageViewerFitActual,imageViewerFitContain:LYRA_DEFAULT_imageViewerFitContain,imageViewerFitLabel:LYRA_DEFAULT_imageViewerFitLabel,imageViewerFitWidth:LYRA_DEFAULT_imageViewerFitWidth,imageViewerHighlightsLabel:LYRA_DEFAULT_imageViewerHighlightsLabel,imageViewerLabel:LYRA_DEFAULT_imageViewerLabel,imageViewerRotate:LYRA_DEFAULT_imageViewerRotate,imageViewerUnlabeledHighlight:LYRA_DEFAULT_imageViewerUnlabeledHighlight}}static{this.styles=[LyraElement.styles,styles,srOnly]}static{this.immutableEventDetails=Object.freeze(["lr-annotation-create"])}get fit(){return this._fit}set fit(value){const old=this._fit;this._fit=normalizeImageFit(value),this.requestUpdate("fit",old)}get rotation(){return this._rotation}set rotation(value){const old=this._rotation;this._rotation=normalizeImageRotation(value),this.requestUpdate("rotation",old)}get safeRotation(){return this.rotation}get hasOperableContent(){return this.loadState.kind==="loaded"}willUpdate(changed){if(super.willUpdate(changed),changed.has("src")){this.cancelPointerDraft(),this.revealTarget=null,this.mediaLayoutSize=null;const safeSrc=this.src?safeMediaSrc(this.src):null;this.loadState=safeSrc?{kind:"loading"}:this.src?{kind:"error"}:{kind:"idle"},this.hasUpdated&&this.src&&!safeSrc&&this.announceLoadError()}changed.has("annotatable")&&(!this.annotatable||!this.hasOperableContent)&&this.cancelPointerDraft()}updated(changed){super.updated(changed),changed.has("rotation")&&changed.get("rotation")!==void 0&&this.emit("lr-rotation-change",{rotation:this.safeRotation}),changed.has("fit")&&changed.get("fit")!==void 0&&this.emit("lr-fit-change",{fit:this.fit}),(changed.has("annotatable")||changed.has("loadState"))&&this.annotatable&&this.hasOperableContent&&(changed.has("loadState")||changed.get("annotatable")!==void 0)&&this.liveRegion?.announce(this.localize("imageViewerAnnotationHint"),{force:!0}),this.syncGeometryObserver()}rotate(){this.rotation=(this.safeRotation+90)%360}async applyAnchor(anchor){if(anchor.kind!=="region"||!this.hasOperableContent)return!1;const rect=normalizeImageRegionRect(anchor.rect);if(!rect)return!1;this.revealTarget=rect,await this.updateComplete;const target=this.shadowRoot?.querySelector("[data-reveal-target]"),viewport=this.frameEl?.shadowRoot?.querySelector('[part="viewport"]');if(!target||!viewport||target.getClientRects().length===0)return!1;target.scrollIntoView({block:"center",inline:"center"}),await new Promise(resolve=>{const view=this.ownerDocument.defaultView;view?view.requestAnimationFrame(()=>resolve()):resolve()});const targetRect=target.getBoundingClientRect(),viewportRect=viewport.getBoundingClientRect();return targetRect.right>viewportRect.left&&targetRect.left<viewportRect.right&&targetRect.bottom>viewportRect.top&&targetRect.top<viewportRect.bottom}connectedCallback(){super.connectedCallback(),this.syncErrorAnnouncementSink()}adoptedCallback(){super.adoptedCallback(),this.disconnectGeometryObserver(),this.releaseErrorAnnouncementSink(),this.syncErrorAnnouncementSink(),this.scheduleAfterUpdate(()=>this.syncGeometryObserver())}disconnectGeometryObserver(){this.geometryObserver?.disconnect(),this.geometryObserver=void 0,this.observedWrapper=void 0,this.geometryFrame!==void 0&&this.geometryFrameOwner?.cancelAnimationFrame(this.geometryFrame),this.geometryFrame=void 0,this.geometryFrameOwner=void 0}updateMediaLayoutSize(width,height){!Number.isFinite(width)||!Number.isFinite(height)||width<=0||height<=0||this.mediaLayoutSize?.width===width&&this.mediaLayoutSize.height===height||(this.mediaLayoutSize={width,height})}scheduleMediaLayoutSize(width,height){const view=this.ownerDocument.defaultView;if(!view){this.updateMediaLayoutSize(width,height);return}this.geometryFrame!==void 0&&this.geometryFrameOwner?.cancelAnimationFrame(this.geometryFrame),this.geometryFrameOwner=view,this.geometryFrame=view.requestAnimationFrame(()=>{this.geometryFrame=void 0,this.geometryFrameOwner=void 0,this.updateMediaLayoutSize(Math.round(width*100)/100,Math.round(height*100)/100)})}syncGeometryObserver(){const wrapper=this.wrapperEl;if(wrapper===this.observedWrapper||(this.disconnectGeometryObserver(),!wrapper))return;this.observedWrapper=wrapper,this.scheduleMediaLayoutSize(wrapper.offsetWidth,wrapper.offsetHeight);const ResizeObserverConstructor=this.ownerDocument.defaultView?.ResizeObserver;ResizeObserverConstructor&&(this.geometryObserver=new ResizeObserverConstructor(entries=>{const entry=entries.find(candidate=>candidate.target===this.observedWrapper);entry&&this.scheduleMediaLayoutSize(entry.contentRect.width,entry.contentRect.height)}),this.geometryObserver.observe(wrapper))}syncErrorAnnouncementSink(){this.isConnected&&this.errorAnnouncementSink?.element.ownerDocument!==this.ownerDocument&&(this.releaseErrorAnnouncementSink(),this.errorAnnouncementSink=acquireAnnouncementSink("assertive",{document:this.ownerDocument,source:this}))}releaseErrorAnnouncementSink(){this.errorAnnouncementSink?.release(),this.errorAnnouncementSink=void 0}announceLoadError(){this.errorAnnouncementSink?.announce(this.localize("imageViewerFailedToLoad"))}onHighlightActivate(id){this.activeHighlightId=id,this.emit("lr-highlight-activate",{highlightId:id})}announceDraftPosition(){if(!this.draft)return;const formatter=getNumberFormat(this.effectiveLocale,{maximumFractionDigits:0,useGrouping:!1});this.liveRegion?.announce(this.localize("imageViewerAnnotationBoxPosition",void 0,{x:formatter.format(Math.round(this.draft.x)),y:formatter.format(Math.round(this.draft.y)),width:formatter.format(Math.round(this.draft.width)),height:formatter.format(Math.round(this.draft.height))}))}commitDraft(){if(!this.draft)return;const rect={x:this.draft.x,y:this.draft.y,width:this.draft.width,height:this.draft.height};this.draft=null,this.emit("lr-annotation-create",{anchor:{kind:"region",rect}}),this.liveRegion?.announce(this.localize("imageViewerAnnotationAdded"),{force:!0})}cancelPointerDraft(pointerId=this.pointerDraftId,releaseCapture=!0){if(pointerId!=null&&this.pointerDraftId!==pointerId)return;const wrapper=this.wrapperEl,capturedPointerId=this.pointerDraftId;if(this.pointerDraftId=null,this.pointerOrigin=null,this.draft=null,releaseCapture&&wrapper&&capturedPointerId!=null)try{wrapper.releasePointerCapture(capturedPointerId)}catch{}}canonicalRegionHighlights(){const ids=new Set,result=[];for(const highlight of this.highlights){if(!highlight||typeof highlight.id!="string"||highlight.id.trim().length===0||ids.has(highlight.id)||highlight.anchor.kind!=="region")continue;const rect=normalizeImageRegionRect(highlight.anchor.rect);rect&&(ids.add(highlight.id),result.push({highlight,rect}))}return result}boundedRegionHighlights(){const all=this.canonicalRegionHighlights();if(all.length<=IMAGE_VIEWER_HIGHLIGHT_LIMIT)return{all,visible:all};const visible=all.slice(0,IMAGE_VIEWER_HIGHLIGHT_LIMIT),active=this.activeHighlightId?all.find(entry=>entry.highlight.id===this.activeHighlightId):void 0;return active&&!visible.includes(active)&&(visible[visible.length-1]=active),{all,visible}}onHighlightFocus(id){this.highlightFocusId=id}onHighlightKeyDown(event,id){const buttons=[...this.shadowRoot.querySelectorAll('[part="highlight"]')];if(buttons.length<2)return;const current=buttons.findIndex(button=>button.dataset.highlightId===id),rtl=this.effectiveDirection==="rtl";let next=current;if(event.key==="Home")next=0;else if(event.key==="End")next=buttons.length-1;else if(event.key==="ArrowDown"||event.key===(rtl?"ArrowLeft":"ArrowRight"))next=(current+1)%buttons.length;else if(event.key==="ArrowUp"||event.key===(rtl?"ArrowRight":"ArrowLeft"))next=(current-1+buttons.length)%buttons.length;else return;event.preventDefault();const target=buttons[next];this.highlightFocusId=target.dataset.highlightId??null,target.focus(),this.requestUpdate()}renderHighlights(){if(!this.hasOperableContent)return nothing;const{all:regionHighlights,visible}=this.boundedRegionHighlights();if(!regionHighlights.length)return nothing;const formatter=getNumberFormat(this.effectiveLocale,{maximumFractionDigits:0,useGrouping:!1}),preferredFocusId=visible.some(({highlight})=>highlight.id===this.highlightFocusId)?this.highlightFocusId:visible.some(({highlight})=>highlight.id===this.activeHighlightId)?this.activeHighlightId:visible[0]?.highlight.id??null;return html`<div
2
2
  part="highlight-layer"
3
3
  role="group"
4
4
  aria-label=${this.localize("imageViewerHighlightsLabel")}
@@ -1,4 +1,4 @@
1
- import{type TemplateResult,type PropertyValues}from'lit';import{LyraElement}from'../../../internal/lyra-element.js';import'../pan-zoom/pan-zoom.class.js';
1
+ import{type TemplateResult,type PropertyValues}from'lit';import{LyraElement}from'../../../internal/lyra-element.js';import{type LyraImageFit}from'../../../internal/image-fit.js';import'../pan-zoom/pan-zoom.class.js';
2
2
  /** One image in the set `<lr-lightbox>` browses. `alt`/`caption` are caller-supplied data
3
3
  * (like a filename), not routed through `localize()` -- only the component's own chrome
4
4
  * strings are. */
@@ -128,7 +128,7 @@ export interface LyraLightboxHideDetail{source:Element;}export interface LyraLig
128
128
  export declare class LyraLightbox extends LyraElement<LyraLightboxEventMap>{static styles:import("lit").CSSResultGroup[];private _open;
129
129
  /** Whether the lightbox is open. Post-render writes run the same cancelable lifecycle as
130
130
  * `show()`/`hide()`/`close()`; initial markup is state and emits nothing. */
131
- get open():boolean;set open(next:boolean);private _images;
131
+ get open():boolean;set open(next:boolean);private _images;private _fit;
132
132
  /** The ordered, bounded, immutable set of images being browsed. Assign a new collection to
133
133
  * update it; malformed records are omitted and at most 10,000 candidates are inspected. */
134
134
  get images():readonly LyraLightboxImage[];set images(value:readonly LyraLightboxImage[]);
@@ -151,6 +151,11 @@ lightDismiss:boolean;
151
151
  * reflected: nothing styles or queries `[show-counter]`, so the serializing half of a
152
152
  * reflecting converter would be dead code on a modal that already churns attributes. */
153
153
  showCounter:boolean;
154
+ /** Base image sizing policy, using the same vocabulary as `<lr-image-viewer>`. `actual`
155
+ * preserves the current natural-size behavior; `contain` fits the complete image inside the
156
+ * available stage and `width` fills its inline size. Fit recalculates from layout when the
157
+ * stage allocation changes. Explicit user zoom remains in effect until navigation or a reset. */
158
+ get fit():LyraImageFit;set fit(value:LyraImageFit);
154
159
  /** Passed through to the embedded `<lr-pan-zoom>` as `.minZoom`. Same default as
155
160
  * `<lr-pan-zoom>` itself. */
156
161
  minZoom:number;