@aceshooting/lyra-ui 11.0.0 → 11.2.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.
Files changed (135) hide show
  1. package/CHANGELOG.md +151 -0
  2. package/README.md +8 -0
  3. package/custom-elements.json +1 -1
  4. package/dist/components/agent-tools/activity-feed/activity-feed.class.js +1 -1
  5. package/dist/components/agent-tools/agent-eval-dashboard/agent-eval-dashboard.class.js +1 -1
  6. package/dist/components/agent-tools/agent-run/agent-run.class.js +1 -1
  7. package/dist/components/agent-tools/agent-trace/agent-trace.class.js +1 -1
  8. package/dist/components/agent-tools/browser-frame/browser-frame.class.js +1 -1
  9. package/dist/components/agent-tools/commit-card/commit-card.class.js +1 -1
  10. package/dist/components/agent-tools/span-waterfall/span-waterfall.class.js +1 -1
  11. package/dist/components/agent-tools/task-list/task-list.class.js +2 -2
  12. package/dist/components/agent-tools/test-results/test-results.class.js +1 -1
  13. package/dist/components/agent-tools/thinking-panel/thinking-panel.class.js +1 -1
  14. package/dist/components/agent-tools/tool-call-chip/tool-call-chip.class.js +2 -2
  15. package/dist/components/agent-tools/tool-param-form/tool-param-form.class.d.ts +1 -0
  16. package/dist/components/agent-tools/tool-param-form/tool-param-form.class.js +1 -1
  17. package/dist/components/agent-tools/tool-result-dialog/tool-result-dialog.class.js +2 -2
  18. package/dist/components/agent-tools/trace-tree/trace-tree.class.js +2 -2
  19. package/dist/components/charts/chart/bar-chart.class.js +1 -1
  20. package/dist/components/charts/chart/bubble-chart.class.js +1 -1
  21. package/dist/components/charts/chart/chart.class.js +1 -1
  22. package/dist/components/charts/chart/doughnut-chart.class.js +1 -1
  23. package/dist/components/charts/chart/histogram.class.js +1 -1
  24. package/dist/components/charts/chart/line-chart.class.js +1 -1
  25. package/dist/components/charts/chart/lite-chart.class.d.ts +32 -0
  26. package/dist/components/charts/chart/lite-chart.class.js +17 -4
  27. package/dist/components/charts/chart/lite-chart.styles.js +29 -0
  28. package/dist/components/charts/chart/pie-chart.class.js +1 -1
  29. package/dist/components/charts/chart/polar-area-chart.class.js +1 -1
  30. package/dist/components/charts/chart/radar-chart.class.js +1 -1
  31. package/dist/components/charts/chart/scatter-chart.class.js +1 -1
  32. package/dist/components/conversation/chat-message/chat-message.class.js +2 -2
  33. package/dist/components/conversation/chat-viewport/chat-viewport.class.js +1 -1
  34. package/dist/components/conversation/model-select/model-select.class.d.ts +1 -0
  35. package/dist/components/conversation/model-select/model-select.class.js +1 -1
  36. package/dist/components/conversation/usage-badge/usage-badge.class.js +1 -1
  37. package/dist/components/conversation/voice-picker/voice-picker.class.d.ts +1 -0
  38. package/dist/components/conversation/voice-picker/voice-picker.class.js +1 -1
  39. package/dist/components/data/graph-query-builder/graph-query-builder.class.d.ts +1 -0
  40. package/dist/components/data/graph-query-builder/graph-query-builder.class.js +1 -1
  41. package/dist/components/data/heatmap/heatmap.class.d.ts +36 -1
  42. package/dist/components/data/heatmap/heatmap.class.js +1 -1
  43. package/dist/components/data/table/table.class.d.ts +19 -0
  44. package/dist/components/data/table/table.class.js +3 -3
  45. package/dist/components/forms/checkbox/checkbox.class.d.ts +1 -0
  46. package/dist/components/forms/checkbox/checkbox.class.js +1 -1
  47. package/dist/components/forms/checkbox-group/checkbox-group.class.d.ts +1 -0
  48. package/dist/components/forms/checkbox-group/checkbox-group.class.js +1 -1
  49. package/dist/components/forms/combobox/combobox.class.d.ts +1 -0
  50. package/dist/components/forms/combobox/combobox.class.js +1 -1
  51. package/dist/components/forms/date-picker/date-input.class.d.ts +12 -1
  52. package/dist/components/forms/date-picker/date-input.class.js +4 -2
  53. package/dist/components/forms/date-picker/date-picker.class.d.ts +30 -4
  54. package/dist/components/forms/date-picker/date-picker.class.js +4 -4
  55. package/dist/components/forms/locale-picker/locale-picker.class.d.ts +1 -0
  56. package/dist/components/forms/locale-picker/locale-picker.class.js +1 -1
  57. package/dist/components/forms/radio/radio-group.class.d.ts +1 -0
  58. package/dist/components/forms/radio/radio-group.class.js +1 -1
  59. package/dist/components/forms/radio/radio.class.d.ts +1 -0
  60. package/dist/components/forms/radio/radio.class.js +1 -1
  61. package/dist/components/forms/rubric-form/rubric-form.class.d.ts +1 -0
  62. package/dist/components/forms/rubric-form/rubric-form.class.js +1 -1
  63. package/dist/components/forms/select/select.class.d.ts +1 -0
  64. package/dist/components/forms/select/select.class.js +1 -1
  65. package/dist/components/forms/slider/slider.class.d.ts +1 -0
  66. package/dist/components/forms/slider/slider.class.js +1 -1
  67. package/dist/components/forms/switch/switch.class.d.ts +1 -0
  68. package/dist/components/forms/switch/switch.class.js +1 -1
  69. package/dist/components/forms/time-range/time-range.class.d.ts +1 -0
  70. package/dist/components/forms/time-range/time-range.class.js +1 -1
  71. package/dist/components/forms/token-input/token-input.class.d.ts +1 -0
  72. package/dist/components/forms/token-input/token-input.class.js +1 -1
  73. package/dist/components/media/attachment-chip/attachment-chip.class.js +2 -2
  74. package/dist/components/media/attachment-trigger/attachment-trigger.class.js +2 -2
  75. package/dist/components/media/file-icon/file-icon.class.js +1 -1
  76. package/dist/components/media/file-input/file-input.class.d.ts +1 -0
  77. package/dist/components/media/file-input/file-input.class.js +1 -1
  78. package/dist/components/media/flag/flag-peer-bulk.d.ts +12 -0
  79. package/dist/components/media/flag/flag-peer-bulk.js +1 -0
  80. package/dist/components/media/flag/flag.class.d.ts +28 -0
  81. package/dist/components/media/flag/flag.class.js +2 -2
  82. package/dist/components/retrieval/citation-badge/citation-badge.class.js +1 -1
  83. package/dist/components/retrieval/claim-evidence/claim-evidence.class.js +1 -1
  84. package/dist/components/retrieval/grounding-summary/grounding-summary.class.js +2 -2
  85. package/dist/components/retrieval/retrieval-trace/retrieval-trace.class.js +1 -1
  86. package/dist/components/viewers/archive-viewer/archive-viewer.class.js +1 -1
  87. package/dist/components/viewers/contact-viewer/contact-viewer.class.js +1 -1
  88. package/dist/components/viewers/document-compare/document-compare.class.js +1 -1
  89. package/dist/components/viewers/ebook-viewer/ebook-viewer.class.js +1 -1
  90. package/dist/components/viewers/email-viewer/email-viewer.class.js +2 -2
  91. package/dist/components/viewers/pdf-viewer/pdf-viewer.class.js +1 -1
  92. package/dist/custom-elements-jsx.d.ts +5 -3
  93. package/dist/events.d.ts +7 -0
  94. package/dist/internal/canvas.js +1 -1
  95. package/dist/internal/form-associated.d.ts +1 -0
  96. package/dist/internal/form-associated.js +1 -1
  97. package/dist/internal/form-control-labels.js +1 -1
  98. package/dist/internal/lyra-element.js +1 -1
  99. package/dist/internal/package-metadata.d.ts +1 -1
  100. package/dist/internal/package-metadata.js +1 -1
  101. package/dist/lyra.d.ts +1 -1
  102. package/dist/svelte.d.ts +5 -3
  103. package/dist/theme.css +32 -0
  104. package/dist/vue.d.ts +5 -3
  105. package/llms/components/lr-agent-eval-dashboard.md +1 -1
  106. package/llms/components/lr-agent-workspace.md +1 -1
  107. package/llms/components/lr-box-plot.md +2 -2
  108. package/llms/components/lr-chart.md +1 -1
  109. package/llms/components/lr-chunk-inspector.md +1 -1
  110. package/llms/components/lr-combobox.md +3 -3
  111. package/llms/components/lr-date-input.md +22 -6
  112. package/llms/components/lr-date-picker.md +21 -5
  113. package/llms/components/lr-entity-dossier.md +1 -1
  114. package/llms/components/lr-eval-run.md +1 -1
  115. package/llms/components/lr-flag.md +24 -1
  116. package/llms/components/lr-grounding-summary.md +1 -1
  117. package/llms/components/lr-heatmap.md +18 -6
  118. package/llms/components/lr-lite-chart.md +19 -3
  119. package/llms/components/lr-map.md +2 -2
  120. package/llms/components/lr-memory-panel.md +1 -1
  121. package/llms/components/lr-option.md +3 -3
  122. package/llms/components/lr-popover.md +1 -1
  123. package/llms/components/lr-provenance-panel.md +1 -1
  124. package/llms/components/lr-rag-answer.md +1 -1
  125. package/llms/components/lr-rag-eval-dashboard.md +1 -1
  126. package/llms/components/lr-retrieval-results.md +1 -1
  127. package/llms/components/lr-retrieval-trace.md +1 -1
  128. package/llms/peers.md +10 -10
  129. package/llms/shared.md +19 -0
  130. package/llms/tokens.md +12 -0
  131. package/llms-full.txt +109 -21
  132. package/package.json +6 -6
  133. package/vscode-css-data.json +14 -0
  134. package/vscode-html-data.json +17 -3
  135. package/web-types.json +30 -4
@@ -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,state}from"lit/decorators.js";import{LyraElement}from"../../../internal/lyra-element.js";import{closeIcon}from"../../../internal/icons.js";import{AnchoredValidityController,VALIDITY_ANCHOR}from"../../../internal/anchored-validity.js";import{syncValidityStates}from"../../../internal/custom-states.js";import{finiteInteger}from"../../../internal/numbers.js";import{getNumberFormat}from"../../../internal/intl-cache.js";import{nextId}from"../../../internal/a11y.js";import{deepActiveElementIn}from"../../../internal/active-element.js";import{styles}from"./graph-query-builder.styles.js";import{attachInternalsSafely}from"../../../internal/element-internals.js";import{getFormOwner,installCustomErrorProperty,isBarredFromValidation,setFormOwner}from"../../../internal/form-associated.js";import{installInvalidEventAlias}from"../../../internal/invalid-event-alias.js";import{LYRA_DEFAULT_fieldRequired,LYRA_DEFAULT_graphQueryBuilderLabel,LYRA_DEFAULT_graphQueryDeleteWithContext,LYRA_DEFAULT_graphQueryDirectionLabel,LYRA_DEFAULT_graphQueryEndLabel,LYRA_DEFAULT_graphQueryHopRangeInvalid,LYRA_DEFAULT_graphQueryLoadWithContext,LYRA_DEFAULT_graphQueryMaxHopsLabel,LYRA_DEFAULT_graphQueryMinHopsLabel,LYRA_DEFAULT_graphQueryNodeTypeLabel,LYRA_DEFAULT_graphQueryRelationshipTypeLabel,LYRA_DEFAULT_graphQueryRun,LYRA_DEFAULT_graphQuerySaveButton,LYRA_DEFAULT_graphQuerySaveNameLabel,LYRA_DEFAULT_graphQuerySavedQueriesLabel,LYRA_DEFAULT_graphQueryStartLabel,LYRA_DEFAULT_neighborDirectionBoth,LYRA_DEFAULT_neighborDirectionIn,LYRA_DEFAULT_neighborDirectionOut,LYRA_DEFAULT_noData,LYRA_DEFAULT_select}from"../../../internal/default-strings.generated.js";const MAX_TYPES=500,MAX_SAVED_QUERIES=200,MAX_TEXT=256,EMPTY_STRINGS=Object.freeze([]),EMPTY_VALUE=Object.freeze({startId:"",endId:"",relationshipTypes:EMPTY_STRINGS,nodeTypes:EMPTY_STRINGS,direction:"both",minHops:1,maxHops:1}),EMPTY_OPTIONS=Object.freeze([]),EMPTY_SAVED=Object.freeze([]);function ownValue(record,key){try{const descriptor=Object.getOwnPropertyDescriptor(record,key);return descriptor&&"value"in descriptor?descriptor.value:void 0}catch{return}}function boundedString(value){return typeof value=="string"?value.slice(0,MAX_TEXT):""}function stringArray(value){return Array.isArray(value)?Object.freeze([...new Set(value.slice(0,MAX_TYPES).filter(entry=>typeof entry=="string").map(entry=>boundedString(entry)).filter(Boolean))]):EMPTY_STRINGS}function normalizeGraphQuery(value){const record=value!==null&&typeof value=="object"&&!Array.isArray(value)?value:EMPTY_VALUE,direction=ownValue(record,"direction");return Object.freeze({startId:boundedString(ownValue(record,"startId")),endId:boundedString(ownValue(record,"endId")),relationshipTypes:stringArray(ownValue(record,"relationshipTypes")),nodeTypes:stringArray(ownValue(record,"nodeTypes")),direction:direction==="out"||direction==="in"||direction==="both"?direction:"both",minHops:finiteInteger(typeof ownValue(record,"minHops")=="number"?ownValue(record,"minHops"):EMPTY_VALUE.minHops,EMPTY_VALUE.minHops,1,20),maxHops:finiteInteger(typeof ownValue(record,"maxHops")=="number"?ownValue(record,"maxHops"):EMPTY_VALUE.maxHops,EMPTY_VALUE.maxHops,1,20)})}function normalizeTypeOptions(value){if(!Array.isArray(value))return EMPTY_OPTIONS;const values=new Set,result=[];for(const candidate of value.slice(0,MAX_TYPES)){if(candidate===null||typeof candidate!="object"||Array.isArray(candidate))continue;const optionValue=boundedString(ownValue(candidate,"value"));if(optionValue.trim().length===0||values.has(optionValue))continue;values.add(optionValue);const label=boundedString(ownValue(candidate,"label"));result.push(Object.freeze({value:optionValue,...label?{label}:{}}))}return Object.freeze(result)}function normalizeSavedQueries(value){if(!Array.isArray(value))return EMPTY_SAVED;const ids=new Set,result=[];for(const candidate of value.slice(0,MAX_SAVED_QUERIES)){if(candidate===null||typeof candidate!="object"||Array.isArray(candidate))continue;const id=boundedString(ownValue(candidate,"id"));id.trim().length===0||ids.has(id)||(ids.add(id),result.push(Object.freeze({id,name:boundedString(ownValue(candidate,"name")),query:normalizeGraphQuery(ownValue(candidate,"query"))})))}return Object.freeze(result)}class LyraGraphQueryBuilder extends LyraElement{static{this.defaultStrings={...super.defaultStrings,fieldRequired:LYRA_DEFAULT_fieldRequired,graphQueryBuilderLabel:LYRA_DEFAULT_graphQueryBuilderLabel,graphQueryDeleteWithContext:LYRA_DEFAULT_graphQueryDeleteWithContext,graphQueryDirectionLabel:LYRA_DEFAULT_graphQueryDirectionLabel,graphQueryEndLabel:LYRA_DEFAULT_graphQueryEndLabel,graphQueryHopRangeInvalid:LYRA_DEFAULT_graphQueryHopRangeInvalid,graphQueryLoadWithContext:LYRA_DEFAULT_graphQueryLoadWithContext,graphQueryMaxHopsLabel:LYRA_DEFAULT_graphQueryMaxHopsLabel,graphQueryMinHopsLabel:LYRA_DEFAULT_graphQueryMinHopsLabel,graphQueryNodeTypeLabel:LYRA_DEFAULT_graphQueryNodeTypeLabel,graphQueryRelationshipTypeLabel:LYRA_DEFAULT_graphQueryRelationshipTypeLabel,graphQueryRun:LYRA_DEFAULT_graphQueryRun,graphQuerySaveButton:LYRA_DEFAULT_graphQuerySaveButton,graphQuerySaveNameLabel:LYRA_DEFAULT_graphQuerySaveNameLabel,graphQuerySavedQueriesLabel:LYRA_DEFAULT_graphQuerySavedQueriesLabel,graphQueryStartLabel:LYRA_DEFAULT_graphQueryStartLabel,neighborDirectionBoth:LYRA_DEFAULT_neighborDirectionBoth,neighborDirectionIn:LYRA_DEFAULT_neighborDirectionIn,neighborDirectionOut:LYRA_DEFAULT_neighborDirectionOut,noData:LYRA_DEFAULT_noData,select:LYRA_DEFAULT_select}}static{this.formAssociated=!0}static{this.styles=[LyraElement.styles,styles]}static{this.immutableEventDetails=Object.freeze(["lr-input","lr-before-query-run","lr-query-run","lr-before-query-save","lr-query-save","lr-before-query-load","lr-query-load"])}static{this.properties={customError:{attribute:"custom-error",reflect:!0,noAccessor:!0},name:{reflect:!0,noAccessor:!0},value:{attribute:!1,noAccessor:!0},disabled:{type:Boolean,reflect:!0,noAccessor:!0}}}get relationshipTypeOptions(){return this._relationshipTypeOptions}set relationshipTypeOptions(value){const previous=this._relationshipTypeOptions;this._relationshipTypeOptions=normalizeTypeOptions(value),this.requestUpdate("relationshipTypeOptions",previous)}get nodeTypeOptions(){return this._nodeTypeOptions}set nodeTypeOptions(value){const previous=this._nodeTypeOptions;this._nodeTypeOptions=normalizeTypeOptions(value),this.requestUpdate("nodeTypeOptions",previous)}get savedQueries(){return this._savedQueries}set savedQueries(value){const previous=this._savedQueries;this._savedQueries=normalizeSavedQueries(value),this.requestUpdate("savedQueries",previous)}constructor(){super(),this._relationshipTypeOptions=EMPTY_OPTIONS,this._nodeTypeOptions=EMPTY_OPTIONS,this._savedQueries=EMPTY_SAVED,this.hopLimit=6,this.label="",this.hint="",this.errorText="",this._errors={},this.touchedFields=new Set,this.saveName="",this.hasHintSlot=!1,this.hasErrorSlot=!1,this.labelId=nextId("graph-query-builder-label"),this.hintId=nextId("graph-query-builder-hint"),this.errorId=nextId("graph-query-builder-error"),this._fieldsetDisabled=!1,this._name="",this._value=EMPTY_VALUE,this.defaultValue=normalizeGraphQuery(EMPTY_VALUE),this.defaultValueCaptured=!1,this._disabled=!1,this.hasInteracted=!1,this.removalFocusGeneration=0,this.onChromeSlotChange=event=>{const slot=event.currentTarget,hasContent=slot.assignedNodes({flatten:!0}).some(node=>node.nodeType===Node.TEXT_NODE?!!node.textContent?.trim():!0);slot.name==="hint"?this.hasHintSlot=hasContent:slot.name==="error"&&(this.hasErrorSlot=hasContent)},this.internals=attachInternalsSafely(this),this.validityController=new AnchoredValidityController(this,this.internals,()=>this[VALIDITY_ANCHOR]()),installCustomErrorProperty(this,()=>this.validityController.customValidityMessage),installInvalidEventAlias(this,init=>this.emit("lr-invalid",null,init)),this.syncFormState()}disconnectedCallback(){this.removalFocusGeneration++,this.pendingRemovalFocus=void 0,super.disconnectedCallback()}get form(){return getFormOwner(this.internals)}set form(owner){setFormOwner(this,owner)}getForm(){return getFormOwner(this.internals)}get labels(){return this.internals.labels}get validity(){return this.internals.validity}get validationMessage(){return this.internals.validationMessage}get willValidate(){return this.internals.willValidate}get value(){return this._value}set value(next){const old=this._value;this._value=normalizeGraphQuery(next),this.syncFormState(),this.requestUpdate("value",old)}get name(){return this._name}set name(next){const old=this._name;this._name=next??"",this._name?this.setAttribute("name",this._name):this.removeAttribute("name"),this.requestUpdate("name",old)}get disabled(){return this._disabled}set disabled(next){const old=this._disabled;this._disabled=!!next,this.toggleAttribute("disabled",this._disabled),this.validityController&&this.syncFormState(),this.requestUpdate("disabled",old)}get effectiveDisabled(){return this.disabled||this._fieldsetDisabled}get errors(){return this.publicValidityErrors()}publicValidityErrors(){const errors={...this._errors};return this.willValidate&&this.validity.customError&&(errors.base=this.validationMessage),Object.freeze(errors)}publishValiditySnapshot(){if(!this.isConnected)return;const valid=!this.willValidate||this.validity.valid,errors=valid?Object.freeze({}):this.publicValidityErrors(),key=JSON.stringify({valid,errors});key!==this.lastValidityKey&&(this.lastValidityKey=key,this.emit("lr-validity-change",Object.freeze({valid,errors})))}[VALIDITY_ANCHOR](){const firstInvalidPart=Object.keys(this._errors)[0];if(!(!firstInvalidPart||!this.renderRoot))return this.renderRoot.querySelector(`[part="${firstInvalidPart}"]`)??void 0}computeValidation(){const errors={},flags={};return this._value.startId.trim()||(errors["start-input"]=this.localize("fieldRequired"),flags.valueMissing=!0),this._value.minHops>this._value.maxHops&&(errors["max-hops"]=this.localize("graphQueryHopRangeInvalid"),flags.rangeUnderflow=!0),{errors,flags}}syncFormState(){const{errors,flags}=this.computeValidation();this._errors=errors;let formValue=null;try{formValue=JSON.stringify(this._value)}catch{formValue=null}if(this.internals.setFormValue(formValue,formValue),this.barredFromValidation||Object.keys(flags).length===0)this.validityController.setValidity({});else{const message=Object.values(errors)[0]??"";this.validityController.setValidity(flags,message)}this.syncValidityCustomStates(),this.publishValiditySnapshot()}get barredFromValidation(){return isBarredFromValidation(this,this.internals)}syncValidityCustomStates(){syncValidityStates(this.internals,{required:!0,hasInteracted:this.hasInteracted,barred:this.barredFromValidation})}checkValidity(){return this.syncFormState(),this.internals.checkValidity()}reportValidity(){return this.hasInteracted=!0,this.syncFormState(),Object.keys(this._errors).length>0&&(this.touchedFields=new Set([...this.touchedFields,...Object.keys(this._errors)])),this.internals.reportValidity()}setCustomValidity(message){this.validityController.setCustomValidity(message??""),this.syncValidityCustomStates(),this.publishValiditySnapshot()}formResetCallback(){this.hasInteracted=!1,this.captureDefaultValue(),this.value=this.defaultValue,this.touchedFields=new Set,this.saveName=""}captureDefaultValue(){this.defaultValueCaptured||(this.defaultValue=normalizeGraphQuery(this._value),this.defaultValueCaptured=!0)}formStateRestoreCallback(state2,_mode){let restored=EMPTY_VALUE;if(typeof state2=="string")try{const parsed=JSON.parse(state2);parsed!==null&&typeof parsed=="object"&&!Array.isArray(parsed)&&(restored=normalizeGraphQuery(parsed))}catch{}this.value=restored}formDisabledCallback(disabled){this._fieldsetDisabled=disabled,this.syncFormState(),this.requestUpdate()}get liveDisabled(){return this.effectiveDisabled||this.matches(":disabled")}focusFirstControl(options){if(!this.renderRoot||this.liveDisabled)return;(this.renderRoot.querySelector('[part="start-input"]')||this.renderRoot.querySelector('[part="end-input"]')||this.renderRoot.querySelector('[part="min-hops"]')||this.renderRoot.querySelector('[part="max-hops"]')||this.renderRoot.querySelector('[part="direction"]')||this.renderRoot.querySelector('[part="save-name-input"]'))?.focus(options)}focus(options){this.focusFirstControl(options)}blur(){const active=deepActiveElementIn(this.shadowRoot);active&&typeof active.blur=="function"&&active.blur()}click(){this.focusFirstControl()}setValue(next){this.effectiveDisabled||(this.hasInteracted=!0,this.value=next,this.emit("lr-input",Object.freeze({value:this._value})))}addRelationshipType(type){!type||this._value.relationshipTypes.includes(type)||this.setValue({...this._value,relationshipTypes:[...this._value.relationshipTypes,type]})}removeRelationshipType(type){this.captureChipRemovalFocus("relationship",type,this._value.relationshipTypes),this.setValue({...this._value,relationshipTypes:this._value.relationshipTypes.filter(t=>t!==type)})}addNodeType(type){!type||this._value.nodeTypes.includes(type)||this.setValue({...this._value,nodeTypes:[...this._value.nodeTypes,type]})}removeNodeType(type){this.captureChipRemovalFocus("node-type",type,this._value.nodeTypes),this.setValue({...this._value,nodeTypes:this._value.nodeTypes.filter(t=>t!==type)})}captureChipRemovalFocus(group,value,selected){const active=this.shadowRoot?.activeElement,expectedPart=group==="relationship"?"relationship-chips":"node-type-chips";if(active?.localName!=="lr-chip"||active.getAttribute("value")!==value||active.closest("lr-chip-group")?.getAttribute("part")!==expectedPart)return;const index=selected.indexOf(value),survivors=selected.filter(candidate=>candidate!==value),targetValue=survivors[Math.min(Math.max(index,0),survivors.length-1)];this.pendingRemovalFocus={kind:"chip",group,targetValue},this.removalFocusGeneration++}markTouched(part){this.hasInteracted=!0,this.syncValidityCustomStates(),!this.touchedFields.has(part)&&(this.touchedFields=new Set(this.touchedFields).add(part))}runQuery(){if(this.effectiveDisabled||!this.reportValidity())return;const detail=()=>Object.freeze({query:normalizeGraphQuery(this._value)});this.emit("lr-before-query-run",detail(),{cancelable:!0}).defaultPrevented||this.emit("lr-query-run",detail())}saveQuery(){if(this.effectiveDisabled)return;const name=this.saveName.trim();if(!name)return;const detail=()=>Object.freeze({name,query:normalizeGraphQuery(this._value)});this.emit("lr-before-query-save",detail(),{cancelable:!0}).defaultPrevented||(this.saveName="",this.emit("lr-query-save",detail()))}loadQuery(item){if(this.effectiveDisabled)return;const detail=()=>Object.freeze({queryId:item.id,query:normalizeGraphQuery(item.query)});this.emit("lr-before-query-load",detail(),{cancelable:!0}).defaultPrevented||(this.setValue({...EMPTY_VALUE,...item.query}),this.emit("lr-query-load",detail()))}deleteQuery(item){if(this.effectiveDisabled)return;const detail=()=>Object.freeze({queryId:item.id});this.emit("lr-before-query-delete",detail(),{cancelable:!0}).defaultPrevented||this.emit("lr-query-delete",detail())}willUpdate(changed){if(super.willUpdate(changed),this.hasUpdated||this.captureDefaultValue(),!changed.has("savedQueries"))return;const active=this.shadowRoot?.activeElement;if(active?.getAttribute("part")!=="saved-delete-button")return;const focusedId=active.closest("[data-query-id]")?.dataset.queryId;if(!focusedId||this.savedQueries.some(item=>item.id===focusedId))return;const index=(changed.get("savedQueries")??[]).findIndex(item=>item.id===focusedId),target=this.savedQueries[Math.min(Math.max(index,0),this.savedQueries.length-1)];this.pendingRemovalFocus={kind:"saved",targetId:target?.id},this.removalFocusGeneration++}updated(changed){super.updated(changed),this.publishValiditySnapshot();const pending=this.pendingRemovalFocus;if(!pending)return;this.pendingRemovalFocus=void 0;const generation=this.removalFocusGeneration;this.scheduleAfterUpdate(()=>{if(!(generation!==this.removalFocusGeneration||!this.isConnected)){if(pending.kind==="chip"){if(pending.targetValue){const part=pending.group==="relationship"?"relationship-chips":"node-type-chips",chip=[...this.shadowRoot?.querySelectorAll(`[part="${part}"] lr-chip`)??[]].find(candidate=>candidate.getAttribute("value")===pending.targetValue);if(chip){chip.focus();return}}const pickerPart=pending.group==="relationship"?"relationship-picker":"node-type-picker";this.shadowRoot?.querySelector(`[part="${pickerPart}"]`)?.focus();return}if(pending.targetId){const action=[...this.shadowRoot?.querySelectorAll("[data-query-id]")??[]].find(candidate=>candidate.dataset.queryId===pending.targetId)?.querySelector('[part="saved-delete-button"]');if(action){action.focus();return}}this.shadowRoot?.querySelector('[part="save-name-input"]')?.focus()}},"graph-query-removal-focus")}hopOptions(){const limit=finiteInteger(this.hopLimit,6,1,20),options=new Set(Array.from({length:limit},(_,i)=>i+1));return options.add(this._value.minHops),options.add(this._value.maxHops),[...options].sort((a,b)=>a-b)}labelForType(options,value){return options.find(o=>o.value===value)?.label??value}renderTypeFilter(kind,options,selected,add,remove,disabled){const pickerPart=kind==="relationship"?"relationship-picker":"node-type-picker",chipsPart=kind==="relationship"?"relationship-chips":"node-type-chips",pickerLabel=kind==="relationship"?this.localize("graphQueryRelationshipTypeLabel"):this.localize("graphQueryNodeTypeLabel"),available=options.filter(o=>!selected.includes(o.value));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,state}from"lit/decorators.js";import{LyraElement}from"../../../internal/lyra-element.js";import"../../../internal/form-control-labels.js";import{closeIcon}from"../../../internal/icons.js";import{AnchoredValidityController,VALIDITY_ANCHOR}from"../../../internal/anchored-validity.js";import{syncValidityStates}from"../../../internal/custom-states.js";import{finiteInteger}from"../../../internal/numbers.js";import{getNumberFormat}from"../../../internal/intl-cache.js";import{nextId}from"../../../internal/a11y.js";import{deepActiveElementIn}from"../../../internal/active-element.js";import{styles}from"./graph-query-builder.styles.js";import{attachInternalsSafely}from"../../../internal/element-internals.js";import{getFormOwner,installCustomErrorProperty,isBarredFromValidation,setFormOwner}from"../../../internal/form-associated.js";import{installInvalidEventAlias}from"../../../internal/invalid-event-alias.js";import{LYRA_DEFAULT_fieldRequired,LYRA_DEFAULT_graphQueryBuilderLabel,LYRA_DEFAULT_graphQueryDeleteWithContext,LYRA_DEFAULT_graphQueryDirectionLabel,LYRA_DEFAULT_graphQueryEndLabel,LYRA_DEFAULT_graphQueryHopRangeInvalid,LYRA_DEFAULT_graphQueryLoadWithContext,LYRA_DEFAULT_graphQueryMaxHopsLabel,LYRA_DEFAULT_graphQueryMinHopsLabel,LYRA_DEFAULT_graphQueryNodeTypeLabel,LYRA_DEFAULT_graphQueryRelationshipTypeLabel,LYRA_DEFAULT_graphQueryRun,LYRA_DEFAULT_graphQuerySaveButton,LYRA_DEFAULT_graphQuerySaveNameLabel,LYRA_DEFAULT_graphQuerySavedQueriesLabel,LYRA_DEFAULT_graphQueryStartLabel,LYRA_DEFAULT_neighborDirectionBoth,LYRA_DEFAULT_neighborDirectionIn,LYRA_DEFAULT_neighborDirectionOut,LYRA_DEFAULT_noData,LYRA_DEFAULT_select}from"../../../internal/default-strings.generated.js";const MAX_TYPES=500,MAX_SAVED_QUERIES=200,MAX_TEXT=256,EMPTY_STRINGS=Object.freeze([]),EMPTY_VALUE=Object.freeze({startId:"",endId:"",relationshipTypes:EMPTY_STRINGS,nodeTypes:EMPTY_STRINGS,direction:"both",minHops:1,maxHops:1}),EMPTY_OPTIONS=Object.freeze([]),EMPTY_SAVED=Object.freeze([]);function ownValue(record,key){try{const descriptor=Object.getOwnPropertyDescriptor(record,key);return descriptor&&"value"in descriptor?descriptor.value:void 0}catch{return}}function boundedString(value){return typeof value=="string"?value.slice(0,MAX_TEXT):""}function stringArray(value){return Array.isArray(value)?Object.freeze([...new Set(value.slice(0,MAX_TYPES).filter(entry=>typeof entry=="string").map(entry=>boundedString(entry)).filter(Boolean))]):EMPTY_STRINGS}function normalizeGraphQuery(value){const record=value!==null&&typeof value=="object"&&!Array.isArray(value)?value:EMPTY_VALUE,direction=ownValue(record,"direction");return Object.freeze({startId:boundedString(ownValue(record,"startId")),endId:boundedString(ownValue(record,"endId")),relationshipTypes:stringArray(ownValue(record,"relationshipTypes")),nodeTypes:stringArray(ownValue(record,"nodeTypes")),direction:direction==="out"||direction==="in"||direction==="both"?direction:"both",minHops:finiteInteger(typeof ownValue(record,"minHops")=="number"?ownValue(record,"minHops"):EMPTY_VALUE.minHops,EMPTY_VALUE.minHops,1,20),maxHops:finiteInteger(typeof ownValue(record,"maxHops")=="number"?ownValue(record,"maxHops"):EMPTY_VALUE.maxHops,EMPTY_VALUE.maxHops,1,20)})}function normalizeTypeOptions(value){if(!Array.isArray(value))return EMPTY_OPTIONS;const values=new Set,result=[];for(const candidate of value.slice(0,MAX_TYPES)){if(candidate===null||typeof candidate!="object"||Array.isArray(candidate))continue;const optionValue=boundedString(ownValue(candidate,"value"));if(optionValue.trim().length===0||values.has(optionValue))continue;values.add(optionValue);const label=boundedString(ownValue(candidate,"label"));result.push(Object.freeze({value:optionValue,...label?{label}:{}}))}return Object.freeze(result)}function normalizeSavedQueries(value){if(!Array.isArray(value))return EMPTY_SAVED;const ids=new Set,result=[];for(const candidate of value.slice(0,MAX_SAVED_QUERIES)){if(candidate===null||typeof candidate!="object"||Array.isArray(candidate))continue;const id=boundedString(ownValue(candidate,"id"));id.trim().length===0||ids.has(id)||(ids.add(id),result.push(Object.freeze({id,name:boundedString(ownValue(candidate,"name")),query:normalizeGraphQuery(ownValue(candidate,"query"))})))}return Object.freeze(result)}class LyraGraphQueryBuilder extends LyraElement{static{this.defaultStrings={...super.defaultStrings,fieldRequired:LYRA_DEFAULT_fieldRequired,graphQueryBuilderLabel:LYRA_DEFAULT_graphQueryBuilderLabel,graphQueryDeleteWithContext:LYRA_DEFAULT_graphQueryDeleteWithContext,graphQueryDirectionLabel:LYRA_DEFAULT_graphQueryDirectionLabel,graphQueryEndLabel:LYRA_DEFAULT_graphQueryEndLabel,graphQueryHopRangeInvalid:LYRA_DEFAULT_graphQueryHopRangeInvalid,graphQueryLoadWithContext:LYRA_DEFAULT_graphQueryLoadWithContext,graphQueryMaxHopsLabel:LYRA_DEFAULT_graphQueryMaxHopsLabel,graphQueryMinHopsLabel:LYRA_DEFAULT_graphQueryMinHopsLabel,graphQueryNodeTypeLabel:LYRA_DEFAULT_graphQueryNodeTypeLabel,graphQueryRelationshipTypeLabel:LYRA_DEFAULT_graphQueryRelationshipTypeLabel,graphQueryRun:LYRA_DEFAULT_graphQueryRun,graphQuerySaveButton:LYRA_DEFAULT_graphQuerySaveButton,graphQuerySaveNameLabel:LYRA_DEFAULT_graphQuerySaveNameLabel,graphQuerySavedQueriesLabel:LYRA_DEFAULT_graphQuerySavedQueriesLabel,graphQueryStartLabel:LYRA_DEFAULT_graphQueryStartLabel,neighborDirectionBoth:LYRA_DEFAULT_neighborDirectionBoth,neighborDirectionIn:LYRA_DEFAULT_neighborDirectionIn,neighborDirectionOut:LYRA_DEFAULT_neighborDirectionOut,noData:LYRA_DEFAULT_noData,select:LYRA_DEFAULT_select}}static{this.formAssociated=!0}static{this.styles=[LyraElement.styles,styles]}static{this.immutableEventDetails=Object.freeze(["lr-input","lr-before-query-run","lr-query-run","lr-before-query-save","lr-query-save","lr-before-query-load","lr-query-load"])}static{this.properties={customError:{attribute:"custom-error",reflect:!0,noAccessor:!0},name:{reflect:!0,noAccessor:!0},value:{attribute:!1,noAccessor:!0},disabled:{type:Boolean,reflect:!0,noAccessor:!0}}}get relationshipTypeOptions(){return this._relationshipTypeOptions}set relationshipTypeOptions(value){const previous=this._relationshipTypeOptions;this._relationshipTypeOptions=normalizeTypeOptions(value),this.requestUpdate("relationshipTypeOptions",previous)}get nodeTypeOptions(){return this._nodeTypeOptions}set nodeTypeOptions(value){const previous=this._nodeTypeOptions;this._nodeTypeOptions=normalizeTypeOptions(value),this.requestUpdate("nodeTypeOptions",previous)}get savedQueries(){return this._savedQueries}set savedQueries(value){const previous=this._savedQueries;this._savedQueries=normalizeSavedQueries(value),this.requestUpdate("savedQueries",previous)}constructor(){super(),this._relationshipTypeOptions=EMPTY_OPTIONS,this._nodeTypeOptions=EMPTY_OPTIONS,this._savedQueries=EMPTY_SAVED,this.hopLimit=6,this.label="",this.hint="",this.errorText="",this._errors={},this.touchedFields=new Set,this.saveName="",this.hasHintSlot=!1,this.hasErrorSlot=!1,this.labelId=nextId("graph-query-builder-label"),this.hintId=nextId("graph-query-builder-hint"),this.errorId=nextId("graph-query-builder-error"),this._fieldsetDisabled=!1,this._name="",this._value=EMPTY_VALUE,this.defaultValue=normalizeGraphQuery(EMPTY_VALUE),this.defaultValueCaptured=!1,this._disabled=!1,this.hasInteracted=!1,this.removalFocusGeneration=0,this.onChromeSlotChange=event=>{const slot=event.currentTarget,hasContent=slot.assignedNodes({flatten:!0}).some(node=>node.nodeType===Node.TEXT_NODE?!!node.textContent?.trim():!0);slot.name==="hint"?this.hasHintSlot=hasContent:slot.name==="error"&&(this.hasErrorSlot=hasContent)},this.internals=attachInternalsSafely(this),this.validityController=new AnchoredValidityController(this,this.internals,()=>this[VALIDITY_ANCHOR]()),installCustomErrorProperty(this,()=>this.validityController.customValidityMessage),installInvalidEventAlias(this,init=>this.emit("lr-invalid",null,init)),this.syncFormState()}disconnectedCallback(){this.removalFocusGeneration++,this.pendingRemovalFocus=void 0,super.disconnectedCallback()}get form(){return getFormOwner(this.internals)}set form(owner){setFormOwner(this,owner)}getForm(){return getFormOwner(this.internals)}get labels(){return this.internals.labels}get validity(){return this.internals.validity}get validationMessage(){return this.internals.validationMessage}get willValidate(){return this.internals.willValidate}get value(){return this._value}set value(next){const old=this._value;this._value=normalizeGraphQuery(next),this.syncFormState(),this.requestUpdate("value",old)}get name(){return this._name}set name(next){const old=this._name;this._name=next??"",this._name?this.setAttribute("name",this._name):this.removeAttribute("name"),this.requestUpdate("name",old)}get disabled(){return this._disabled}set disabled(next){const old=this._disabled;this._disabled=!!next,this.toggleAttribute("disabled",this._disabled),this.validityController&&this.syncFormState(),this.requestUpdate("disabled",old)}get effectiveDisabled(){return this.disabled||this._fieldsetDisabled}get errors(){return this.publicValidityErrors()}publicValidityErrors(){const errors={...this._errors};return this.willValidate&&this.validity.customError&&(errors.base=this.validationMessage),Object.freeze(errors)}publishValiditySnapshot(){if(!this.isConnected)return;const valid=!this.willValidate||this.validity.valid,errors=valid?Object.freeze({}):this.publicValidityErrors(),key=JSON.stringify({valid,errors});key!==this.lastValidityKey&&(this.lastValidityKey=key,this.emit("lr-validity-change",Object.freeze({valid,errors})))}[VALIDITY_ANCHOR](){const firstInvalidPart=Object.keys(this._errors)[0];if(!(!firstInvalidPart||!this.renderRoot))return this.renderRoot.querySelector(`[part="${firstInvalidPart}"]`)??void 0}computeValidation(){const errors={},flags={};return this._value.startId.trim()||(errors["start-input"]=this.localize("fieldRequired"),flags.valueMissing=!0),this._value.minHops>this._value.maxHops&&(errors["max-hops"]=this.localize("graphQueryHopRangeInvalid"),flags.rangeUnderflow=!0),{errors,flags}}syncFormState(){const{errors,flags}=this.computeValidation();this._errors=errors;let formValue=null;try{formValue=JSON.stringify(this._value)}catch{formValue=null}if(this.internals.setFormValue(formValue,formValue),this.barredFromValidation||Object.keys(flags).length===0)this.validityController.setValidity({});else{const message=Object.values(errors)[0]??"";this.validityController.setValidity(flags,message)}this.syncValidityCustomStates(),this.publishValiditySnapshot()}get barredFromValidation(){return isBarredFromValidation(this,this.internals)}syncValidityCustomStates(){syncValidityStates(this.internals,{required:!0,hasInteracted:this.hasInteracted,barred:this.barredFromValidation})}checkValidity(){return this.syncFormState(),this.internals.checkValidity()}reportValidity(){return this.hasInteracted=!0,this.syncFormState(),Object.keys(this._errors).length>0&&(this.touchedFields=new Set([...this.touchedFields,...Object.keys(this._errors)])),this.internals.reportValidity()}setCustomValidity(message){this.validityController.setCustomValidity(message??""),this.syncValidityCustomStates(),this.publishValiditySnapshot()}formResetCallback(){this.hasInteracted=!1,this.captureDefaultValue(),this.value=this.defaultValue,this.touchedFields=new Set,this.saveName=""}captureDefaultValue(){this.defaultValueCaptured||(this.defaultValue=normalizeGraphQuery(this._value),this.defaultValueCaptured=!0)}formStateRestoreCallback(state2,_mode){let restored=EMPTY_VALUE;if(typeof state2=="string")try{const parsed=JSON.parse(state2);parsed!==null&&typeof parsed=="object"&&!Array.isArray(parsed)&&(restored=normalizeGraphQuery(parsed))}catch{}this.value=restored}formDisabledCallback(disabled){this._fieldsetDisabled=disabled,this.syncFormState(),this.requestUpdate()}get liveDisabled(){return this.effectiveDisabled||this.matches(":disabled")}focusFirstControl(options){if(!this.renderRoot||this.liveDisabled)return;(this.renderRoot.querySelector('[part="start-input"]')||this.renderRoot.querySelector('[part="end-input"]')||this.renderRoot.querySelector('[part="min-hops"]')||this.renderRoot.querySelector('[part="max-hops"]')||this.renderRoot.querySelector('[part="direction"]')||this.renderRoot.querySelector('[part="save-name-input"]'))?.focus(options)}focus(options){this.focusFirstControl(options)}blur(){const active=deepActiveElementIn(this.shadowRoot);active&&typeof active.blur=="function"&&active.blur()}click(){this.focusFirstControl()}setValue(next){this.effectiveDisabled||(this.hasInteracted=!0,this.value=next,this.emit("lr-input",Object.freeze({value:this._value})))}addRelationshipType(type){!type||this._value.relationshipTypes.includes(type)||this.setValue({...this._value,relationshipTypes:[...this._value.relationshipTypes,type]})}removeRelationshipType(type){this.captureChipRemovalFocus("relationship",type,this._value.relationshipTypes),this.setValue({...this._value,relationshipTypes:this._value.relationshipTypes.filter(t=>t!==type)})}addNodeType(type){!type||this._value.nodeTypes.includes(type)||this.setValue({...this._value,nodeTypes:[...this._value.nodeTypes,type]})}removeNodeType(type){this.captureChipRemovalFocus("node-type",type,this._value.nodeTypes),this.setValue({...this._value,nodeTypes:this._value.nodeTypes.filter(t=>t!==type)})}captureChipRemovalFocus(group,value,selected){const active=this.shadowRoot?.activeElement,expectedPart=group==="relationship"?"relationship-chips":"node-type-chips";if(active?.localName!=="lr-chip"||active.getAttribute("value")!==value||active.closest("lr-chip-group")?.getAttribute("part")!==expectedPart)return;const index=selected.indexOf(value),survivors=selected.filter(candidate=>candidate!==value),targetValue=survivors[Math.min(Math.max(index,0),survivors.length-1)];this.pendingRemovalFocus={kind:"chip",group,targetValue},this.removalFocusGeneration++}markTouched(part){this.hasInteracted=!0,this.syncValidityCustomStates(),!this.touchedFields.has(part)&&(this.touchedFields=new Set(this.touchedFields).add(part))}runQuery(){if(this.effectiveDisabled||!this.reportValidity())return;const detail=()=>Object.freeze({query:normalizeGraphQuery(this._value)});this.emit("lr-before-query-run",detail(),{cancelable:!0}).defaultPrevented||this.emit("lr-query-run",detail())}saveQuery(){if(this.effectiveDisabled)return;const name=this.saveName.trim();if(!name)return;const detail=()=>Object.freeze({name,query:normalizeGraphQuery(this._value)});this.emit("lr-before-query-save",detail(),{cancelable:!0}).defaultPrevented||(this.saveName="",this.emit("lr-query-save",detail()))}loadQuery(item){if(this.effectiveDisabled)return;const detail=()=>Object.freeze({queryId:item.id,query:normalizeGraphQuery(item.query)});this.emit("lr-before-query-load",detail(),{cancelable:!0}).defaultPrevented||(this.setValue({...EMPTY_VALUE,...item.query}),this.emit("lr-query-load",detail()))}deleteQuery(item){if(this.effectiveDisabled)return;const detail=()=>Object.freeze({queryId:item.id});this.emit("lr-before-query-delete",detail(),{cancelable:!0}).defaultPrevented||this.emit("lr-query-delete",detail())}willUpdate(changed){if(super.willUpdate(changed),this.hasUpdated||this.captureDefaultValue(),!changed.has("savedQueries"))return;const active=this.shadowRoot?.activeElement;if(active?.getAttribute("part")!=="saved-delete-button")return;const focusedId=active.closest("[data-query-id]")?.dataset.queryId;if(!focusedId||this.savedQueries.some(item=>item.id===focusedId))return;const index=(changed.get("savedQueries")??[]).findIndex(item=>item.id===focusedId),target=this.savedQueries[Math.min(Math.max(index,0),this.savedQueries.length-1)];this.pendingRemovalFocus={kind:"saved",targetId:target?.id},this.removalFocusGeneration++}updated(changed){super.updated(changed),this.publishValiditySnapshot();const pending=this.pendingRemovalFocus;if(!pending)return;this.pendingRemovalFocus=void 0;const generation=this.removalFocusGeneration;this.scheduleAfterUpdate(()=>{if(!(generation!==this.removalFocusGeneration||!this.isConnected)){if(pending.kind==="chip"){if(pending.targetValue){const part=pending.group==="relationship"?"relationship-chips":"node-type-chips",chip=[...this.shadowRoot?.querySelectorAll(`[part="${part}"] lr-chip`)??[]].find(candidate=>candidate.getAttribute("value")===pending.targetValue);if(chip){chip.focus();return}}const pickerPart=pending.group==="relationship"?"relationship-picker":"node-type-picker";this.shadowRoot?.querySelector(`[part="${pickerPart}"]`)?.focus();return}if(pending.targetId){const action=[...this.shadowRoot?.querySelectorAll("[data-query-id]")??[]].find(candidate=>candidate.dataset.queryId===pending.targetId)?.querySelector('[part="saved-delete-button"]');if(action){action.focus();return}}this.shadowRoot?.querySelector('[part="save-name-input"]')?.focus()}},"graph-query-removal-focus")}hopOptions(){const limit=finiteInteger(this.hopLimit,6,1,20),options=new Set(Array.from({length:limit},(_,i)=>i+1));return options.add(this._value.minHops),options.add(this._value.maxHops),[...options].sort((a,b)=>a-b)}labelForType(options,value){return options.find(o=>o.value===value)?.label??value}renderTypeFilter(kind,options,selected,add,remove,disabled){const pickerPart=kind==="relationship"?"relationship-picker":"node-type-picker",chipsPart=kind==="relationship"?"relationship-chips":"node-type-chips",pickerLabel=kind==="relationship"?this.localize("graphQueryRelationshipTypeLabel"):this.localize("graphQueryNodeTypeLabel"),available=options.filter(o=>!selected.includes(o.value));return html`
2
2
  <div part="filter-group" data-kind=${kind}>
3
3
  <lr-select
4
4
  part=${pickerPart}
@@ -88,6 +88,14 @@ export interface HeatmapLegendStop {
88
88
  color?: string;
89
89
  /** Optional label override; defaults to the component's own numeric formatting of `value`. */
90
90
  label?: string;
91
+ /**
92
+ * Set to `false` to exclude this stop from `warnOnLegendRampMismatch()`'s `colorSteps` agreement
93
+ * check, for a real, distinctly-colored swatch that is intentionally not part of the sequential
94
+ * ramp -- e.g. a calendar heatmap's fixed neutral "no data" color shown alongside an N-step
95
+ * ramp. Defaults to `true`. A caption-only stop (no `color`) is already excluded regardless of
96
+ * this flag, since it describes no color to compare.
97
+ */
98
+ partOfRamp?: boolean;
91
99
  }
92
100
  /** A single cell to mark as persistently selected -- `row`/`col` in matrix mode, `date` in
93
101
  * calendar mode (whichever pair matches the active `mode`; the other field is ignored),
@@ -139,8 +147,14 @@ export type LyraHeatmapCellClickDetail = {
139
147
  col: number;
140
148
  value: number;
141
149
  };
150
+ export type LyraHeatmapMatrixGeometryChangeDetail = {
151
+ padLeft: number;
152
+ padTop: number;
153
+ cellSize: number;
154
+ };
142
155
  export interface LyraHeatmapEventMap {
143
156
  'lr-cell-click': CustomEvent<LyraHeatmapCellClickDetail>;
157
+ 'lr-matrix-geometry-change': CustomEvent<LyraHeatmapMatrixGeometryChangeDetail>;
144
158
  }
145
159
  /**
146
160
  * `<lr-heatmap>` — a Canvas heatmap with a DPR-aware, resize-aware redraw
@@ -251,6 +265,10 @@ export interface LyraHeatmapEventMap {
251
265
  * tooltip and the keyboard live-region announcement. Use the callback for application-specific
252
266
  * wording that is not represented by the locale catalog.
253
267
  * `cellColor` overrides a cell's ramp-computed color entirely for an exact value.
268
+ * @event lr-matrix-geometry-change - Fired after a matrix-mode draw pass whose resolved
269
+ * `matrixGeometry` (`padLeft`/`padTop`/`cellSize`) differs from the previous draw -- e.g. after
270
+ * `row-label-width="auto"`/`col-label-height="auto"` resolves against new label content or a
271
+ * resize. `detail` is the same object `matrixGeometry` returns. Never fired in calendar mode.
254
272
  * @csspart base - The heatmap wrapper.
255
273
  * @csspart canvas - The heatmap canvas.
256
274
  * @csspart cells - The opt-in per-cell accessibility overlay.
@@ -347,6 +365,22 @@ export declare class LyraHeatmap extends LyraElement<LyraHeatmapEventMap> {
347
365
  * painted. Only ever differs from the default while `rowLabelWidth="auto"`. */
348
366
  private resolvedRowLabelWidth;
349
367
  private get matrixPadLeft();
368
+ /**
369
+ * The gutter/cell geometry the last matrix-mode draw actually painted with --
370
+ * `{ padLeft, padTop, cellSize }`, all in CSS pixels -- so a light-DOM consumer (e.g. a sticky
371
+ * header mirror) can line up with the canvas without hardcoding the same numbers `row-label-width`
372
+ * or `col-label-height`'s `"auto"` resolution would otherwise keep private. `undefined` in
373
+ * calendar mode, and before the first matrix draw. Reuses the exact getters/method `drawMatrix()`
374
+ * itself calls, so this can never disagree with what was actually painted. See also the
375
+ * `lr-matrix-geometry-change` event, fired whenever this value changes.
376
+ */
377
+ get matrixGeometry(): Readonly<LyraHeatmapMatrixGeometryChangeDetail> | undefined;
378
+ /** Set on the first successful `drawMatrix()` pass; gates `matrixGeometry` returning a real
379
+ * value only once there has actually been a draw to describe. */
380
+ private hasDrawnMatrix;
381
+ /** Last geometry `lr-matrix-geometry-change` fired, so a same-valued redraw (a color-only
382
+ * update, an unrelated data change) does not refire the event. */
383
+ private lastEmittedMatrixGeometry?;
350
384
  private get matrixPadTop();
351
385
  /** Tallest rotated column label plus inset, floored at the built-in band and capped so labels can
352
386
  * never crowd out the matrix. The column mirror of `measureRowLabelWidth()`. */
@@ -644,7 +678,8 @@ export declare class LyraHeatmap extends LyraElement<LyraHeatmapEventMap> {
644
678
  * Warning rather than deriving one from the other: deriving would silently change what an
645
679
  * existing `colorSteps`-only consumer sees, and would also break the deliberate `cellColor`
646
680
  * escape hatch. This keeps every current behavior and only makes the disagreement audible.
647
- * Compares only the stops that carry a color -- a caption-only stop describes no color at all.
681
+ * Compares only the stops that carry a color -- a caption-only stop describes no color at all --
682
+ * and, among those, only the ones that did not opt out via `partOfRamp: false`.
648
683
  */
649
684
  private warnOnLegendRampMismatch;
650
685
  private cachedLegendStops;
@@ -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{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_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)},FALLBACK_NO_DATA_FILL="rgba(128,128,128,0.25)",RAMP_STEPS=7,FALLBACK_SCALE_LO="#cde2fb",FALLBACK_SCALE_HI="#0969da",FALLBACK_LABEL_FONT="10px system-ui, sans-serif",CAL_PAD_LEFT=28,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)}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})`}const warnedInvalidColors=new Set;function warnInvalidColor(color){warnedInvalidColors.has(color)||(warnedInvalidColors.add(color),console.warn(`<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},toAttribute(value){return value==null?null:String(value)}},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))},toAttribute(value){return String(normalizeBucketCount(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,heatmapValueLabel:LYRA_DEFAULT_heatmapValueLabel}}static{this.ownedCollectionProperties=Object.freeze(["data","annotations","legendStops","colorSteps"])}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 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 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;for(const label of labels)widest=Math.max(widest,ctx.measureText(label).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("")}\u2026`;if(ctx.measureText(candidate).width<=maxWidth)return candidate;kept-=1}return ctx.measureText("\u2026").width<=maxWidth?"\u2026":""}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)}get calendarWeekdayLabelText(){return this.calendarData?.weekdayLabelText}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.resolvedColLabelHeight=PAD_TOP,this.resolvedRowLabelWidth=PAD_LEFT,this.scale="linear",this.fitToWidth=!1,this._bucketCount=DEFAULT_BUCKET_COUNT,this.annotations=[],this.selectedCell=null,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.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=>{const pos=this.hitTest(e.offsetX,e.offsetY);pos&&(this.focusedCell=pos,this.announce(pos),this.emitCellClick(pos))},this.onKeyDown=e=>{this.effectiveMode==="calendar"?this.onCalendarKeyDown(e):this.onMatrixKeyDown(e)},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.focusedCell=pos,this.announce(pos))},this.onAccessibleCellClick=e=>{const key=e.currentTarget.dataset.cellKey,pos=key?this.accessibleCellAtKey(key):null;pos&&(this.focusedCell=pos,this.announce(pos),this.emitCellClick(pos))},this.onAccessibleCellKeyDown=e=>{if(!ARROW_KEYS.has(e.key))return;const key=e.currentTarget.dataset.cellKey,pos=key?this.accessibleCellAtKey(key):null;pos&&(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).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.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")||!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")||!this.hasUpdated){const colorSteps=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")||!this.hasUpdated)&&(this.cachedValueRange=this.computeValueRange()),(collectionChanged||!this.hasUpdated)&&this.rebuildAccessiblePositions(),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])}\u2013${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.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),["data","cellSize","maxCellSize","minCellSize","valueLabel","scale","fitToWidth","bucketCount","annotations","focusedCell","colorSteps","cellColor","selectedCell","legendStops","accessibleCells","accessibleTargetSizePx","locale"].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}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 inset=Math.min(state2==="annotation"?.5:state2==="selected"?3.5:6.5,Math.max(.5,(size-RING_LINE_WIDTH-1)/2)),extent=Math.max(1,size-inset*2);ctx.lineWidth=RING_LINE_WIDTH,ctx.strokeStyle=color,ctx.setLineDash?.(state2==="annotation"?[]:state2==="selected"?[4,2]:[1,2]),ctx.strokeRect(x+inset,y+inset,extent,extent),ctx.setLineDash?.([])}isSelectedPos(pos){return 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||CAL_PAD_LEFT+weekCount*(this.cellSize+CAL_GAP);size=this.clampFitCellSize((hostWidth-CAL_PAD_LEFT)/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]??CAL_PAD_LEFT}rowYFor(weekday){return this.calendarRowPositions()[weekday]??CAL_LABEL_H}calendarColumnPositions(){const cellSize=this.calendarCellSize(),weekCount=this.cachedCalendarGrid.weekCount,callback=this.calendarColumnX,cached=this.cachedColumnGeometry;if(cached!==void 0&&cached.callback===callback&&cached.cellSize===cellSize&&cached.weekCount===weekCount)return cached.positions;const positions=[];for(let index=0;index<=weekCount;index++){const fallback=index===0?CAL_PAD_LEFT: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,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}drawCalendar(){if(!this.canvas)return;const{weekCount,firstWeekStart,monthLabels}=this.cachedCalendarGrid,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 cs=this.ownerDocument.defaultView?.getComputedStyle(this);if(!cs)return;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.cachedCalendarCellsByPos.get(`${week}:${weekday}`)?.value??-1,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))}if(this.selectedCell?.date!=null){const match=this.cachedCalendarCellsByDate.get(this.selectedCell.date);if(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))}}ctx.fillStyle=this.labelColor(cs),ctx.font=this.labelFont(cs);for(const m of monthLabels)ctx.fillText(m.label,this.columnXFor(m.week),CAL_LABEL_H-4);this.weekdayLabels(firstWeekStart).forEach((label,weekday)=>{label&&ctx.fillText(label,2,this.rowYFor(weekday)+cellSize-1)}),this.canvasHasContent=!0}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;return this.accessibleCells?Math.max(size,this.accessibleTargetSizePx):size}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));ctx.fillRect(this.matrixPadLeft+col*cellSize,this.matrixPadTop+row*cellSize,cellSize-1,cellSize-1)}paintMatrixFocusOverlays(ctx,row,col,cellSize,cs){const x=this.matrixPadLeft+col*cellSize,y=this.matrixPadTop+row*cellSize;this.cachedMatrixAnnotationPositions.has(`${row}:${col}`)&&this.strokeCellState(ctx,x,y,cellSize,"annotation",this.annotationColor(cs)),this.selectedCell?.row===row&&this.selectedCell.col===col&&this.strokeCellState(ctx,x,y,cellSize,"selected",this.selectedColor(cs)),this.focusedCell&&"row"in this.focusedCell&&this.focusedCell.row===row&&this.focusedCell.col===col&&this.strokeCellState(ctx,x,y,cellSize,"focus",this.focusRingColor(cs))}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;ctx.clearRect(x-RING_LINE_WIDTH-1,y-RING_LINE_WIDTH-1,cellSize+2*(RING_LINE_WIDTH+1),cellSize+2*(RING_LINE_WIDTH+1));const cs=this.ownerDocument.defaultView?.getComputedStyle(this);cs&&(this.paintMatrixCell(ctx,pos.row,pos.col,cellSize,cs,this.colorRamp(RAMP_STEPS,cs),this.noDataFill(cs)),this.paintMatrixFocusOverlays(ctx,pos.row,pos.col,cellSize,cs))}paintCalendarCell(ctx,week,weekday,cellSize,cs,ramp,noDataFill){const value=this.cachedCalendarCellsByPos.get(`${week}:${weekday}`)?.value??-1,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){const date=this.calendarDateAt(week,weekday),x=this.columnXFor(week),y=this.rowYFor(weekday),matches=candidate=>candidate?.date===date;this.cachedCalendarAnnotationDates.has(date)&&this.strokeCellState(ctx,x,y,cellSize,"annotation",this.annotationColor(cs)),matches(this.selectedCell??void 0)&&this.strokeCellState(ctx,x,y,cellSize,"selected",this.selectedColor(cs)),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;ctx.clearRect(x-RING_LINE_WIDTH-1,y-RING_LINE_WIDTH-1,cellSize+2*(RING_LINE_WIDTH+1),cellSize+2*(RING_LINE_WIDTH+1));const cs=this.ownerDocument.defaultView?.getComputedStyle(this);if(!cs)return;const ramp=this.colorRamp(normalizeBucketCount(this.bucketCount),cs).colors;this.paintCalendarCell(ctx,pos.week,pos.weekday,cellSize,cs,ramp,this.noDataFill(cs)),this.paintCalendarFocusOverlays(ctx,pos.week,pos.weekday,cellSize,cs),ctx.fillStyle=this.labelColor(cs),ctx.font=this.labelFont(cs);for(const month of this.cachedCalendarGrid.monthLabels)ctx.fillText(month.label,this.columnXFor(month.week),CAL_LABEL_H-4);this.weekdayLabels(firstWeekStart).forEach((label,weekday)=>{label&&ctx.fillText(label,2,this.rowYFor(weekday)+cellSize-1)})}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),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)}ctx.fillRect(x,y,cellSize-1,cellSize-1)}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))}if(this.selectedCell?.row!=null&&this.selectedCell.col!=null){const{row,col}=this.selectedCell;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))}}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)});const colRotation=this.effectiveColLabelRotation;if(colRotation===0)this.matrixColLabels.forEach((label,c)=>{ctx.fillText(label,padLeft+c*cellSize+2,padTop-COL_LABEL_INSET)});else{const radians=colRotation*Math.PI/180,previousAlign=ctx.textAlign;ctx.textAlign="right",this.matrixColLabels.forEach((label,c)=>{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}this.canvasHasContent=!0}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 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:-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);return{x:this.matrixPadLeft+pos.col*cellSize,y:this.matrixPadTop+pos.row*cellSize,w:cellSize-1,h: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){const text=this.resolveCellText(pos),announcement=this.isSelectedPos(pos)?this.localize("heatmapSelectedCellLabel",void 0,{cell:text}):text;this.liveText=announcement,this.announcementSink?.announce(announcement)}emitCellClick(pos){if(this.isCellInteractive(pos))if("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})}}tooltipStyle(pos){const rect=this.cellRect(pos);return{left:`${rect.x+rect.w/2}px`,top:`${rect.y}px`}}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);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.announce(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.announce(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);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,this.announce(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,this.announce(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{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_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)},FALLBACK_NO_DATA_FILL="rgba(128,128,128,0.25)",RAMP_STEPS=7,FALLBACK_SCALE_LO="#cde2fb",FALLBACK_SCALE_HI="#0969da",FALLBACK_LABEL_FONT="10px system-ui, sans-serif",CAL_PAD_LEFT=28,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)}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})`}const warnedInvalidColors=new Set;function warnInvalidColor(color){warnedInvalidColors.has(color)||(warnedInvalidColors.add(color),console.warn(`<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},toAttribute(value){return value==null?null:String(value)}},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))},toAttribute(value){return String(normalizeBucketCount(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,heatmapValueLabel:LYRA_DEFAULT_heatmapValueLabel}}static{this.ownedCollectionProperties=Object.freeze(["data","annotations","legendStops","colorSteps"])}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 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"||!this.hasDrawnMatrix))return{padLeft:this.matrixPadLeft,padTop:this.matrixPadTop,cellSize:this.matrixCellSize(this.matrixColLabels.length)}}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;for(const label of labels)widest=Math.max(widest,ctx.measureText(label).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("")}\u2026`;if(ctx.measureText(candidate).width<=maxWidth)return candidate;kept-=1}return ctx.measureText("\u2026").width<=maxWidth?"\u2026":""}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)}get calendarWeekdayLabelText(){return this.calendarData?.weekdayLabelText}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.resolvedColLabelHeight=PAD_TOP,this.resolvedRowLabelWidth=PAD_LEFT,this.hasDrawnMatrix=!1,this.scale="linear",this.fitToWidth=!1,this._bucketCount=DEFAULT_BUCKET_COUNT,this.annotations=[],this.selectedCell=null,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.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=>{const pos=this.hitTest(e.offsetX,e.offsetY);pos&&(this.focusedCell=pos,this.announce(pos),this.emitCellClick(pos))},this.onKeyDown=e=>{this.effectiveMode==="calendar"?this.onCalendarKeyDown(e):this.onMatrixKeyDown(e)},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.focusedCell=pos,this.announce(pos))},this.onAccessibleCellClick=e=>{const key=e.currentTarget.dataset.cellKey,pos=key?this.accessibleCellAtKey(key):null;pos&&(this.focusedCell=pos,this.announce(pos),this.emitCellClick(pos))},this.onAccessibleCellKeyDown=e=>{if(!ARROW_KEYS.has(e.key))return;const key=e.currentTarget.dataset.cellKey,pos=key?this.accessibleCellAtKey(key):null;pos&&(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.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")||!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")||!this.hasUpdated){const colorSteps=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")||!this.hasUpdated)&&(this.cachedValueRange=this.computeValueRange()),(collectionChanged||!this.hasUpdated)&&this.rebuildAccessiblePositions(),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])}\u2013${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.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),["data","cellSize","maxCellSize","minCellSize","valueLabel","scale","fitToWidth","bucketCount","annotations","focusedCell","colorSteps","cellColor","selectedCell","legendStops","accessibleCells","accessibleTargetSizePx","locale"].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}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 inset=Math.min(state2==="annotation"?.5:state2==="selected"?3.5:6.5,Math.max(.5,(size-RING_LINE_WIDTH-1)/2)),extent=Math.max(1,size-inset*2);ctx.lineWidth=RING_LINE_WIDTH,ctx.strokeStyle=color,ctx.setLineDash?.(state2==="annotation"?[]:state2==="selected"?[4,2]:[1,2]),ctx.strokeRect(x+inset,y+inset,extent,extent),ctx.setLineDash?.([])}isSelectedPos(pos){return 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||CAL_PAD_LEFT+weekCount*(this.cellSize+CAL_GAP);size=this.clampFitCellSize((hostWidth-CAL_PAD_LEFT)/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]??CAL_PAD_LEFT}rowYFor(weekday){return this.calendarRowPositions()[weekday]??CAL_LABEL_H}calendarColumnPositions(){const cellSize=this.calendarCellSize(),weekCount=this.cachedCalendarGrid.weekCount,callback=this.calendarColumnX,cached=this.cachedColumnGeometry;if(cached!==void 0&&cached.callback===callback&&cached.cellSize===cellSize&&cached.weekCount===weekCount)return cached.positions;const positions=[];for(let index=0;index<=weekCount;index++){const fallback=index===0?CAL_PAD_LEFT: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,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}drawCalendar(){if(!this.canvas)return;const{weekCount,firstWeekStart,monthLabels}=this.cachedCalendarGrid,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 cs=this.ownerDocument.defaultView?.getComputedStyle(this);if(!cs)return;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.cachedCalendarCellsByPos.get(`${week}:${weekday}`)?.value??-1,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))}if(this.selectedCell?.date!=null){const match=this.cachedCalendarCellsByDate.get(this.selectedCell.date);if(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))}}ctx.fillStyle=this.labelColor(cs),ctx.font=this.labelFont(cs);for(const m of monthLabels)ctx.fillText(m.label,this.columnXFor(m.week),CAL_LABEL_H-4);this.weekdayLabels(firstWeekStart).forEach((label,weekday)=>{label&&ctx.fillText(label,2,this.rowYFor(weekday)+cellSize-1)}),this.canvasHasContent=!0}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;return this.accessibleCells?Math.max(size,this.accessibleTargetSizePx):size}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));ctx.fillRect(this.matrixPadLeft+col*cellSize,this.matrixPadTop+row*cellSize,cellSize-1,cellSize-1)}paintMatrixFocusOverlays(ctx,row,col,cellSize,cs){const x=this.matrixPadLeft+col*cellSize,y=this.matrixPadTop+row*cellSize;this.cachedMatrixAnnotationPositions.has(`${row}:${col}`)&&this.strokeCellState(ctx,x,y,cellSize,"annotation",this.annotationColor(cs)),this.selectedCell?.row===row&&this.selectedCell.col===col&&this.strokeCellState(ctx,x,y,cellSize,"selected",this.selectedColor(cs)),this.focusedCell&&"row"in this.focusedCell&&this.focusedCell.row===row&&this.focusedCell.col===col&&this.strokeCellState(ctx,x,y,cellSize,"focus",this.focusRingColor(cs))}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;ctx.clearRect(x-RING_LINE_WIDTH-1,y-RING_LINE_WIDTH-1,cellSize+2*(RING_LINE_WIDTH+1),cellSize+2*(RING_LINE_WIDTH+1));const cs=this.ownerDocument.defaultView?.getComputedStyle(this);cs&&(this.paintMatrixCell(ctx,pos.row,pos.col,cellSize,cs,this.colorRamp(RAMP_STEPS,cs),this.noDataFill(cs)),this.paintMatrixFocusOverlays(ctx,pos.row,pos.col,cellSize,cs))}paintCalendarCell(ctx,week,weekday,cellSize,cs,ramp,noDataFill){const value=this.cachedCalendarCellsByPos.get(`${week}:${weekday}`)?.value??-1,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){const date=this.calendarDateAt(week,weekday),x=this.columnXFor(week),y=this.rowYFor(weekday),matches=candidate=>candidate?.date===date;this.cachedCalendarAnnotationDates.has(date)&&this.strokeCellState(ctx,x,y,cellSize,"annotation",this.annotationColor(cs)),matches(this.selectedCell??void 0)&&this.strokeCellState(ctx,x,y,cellSize,"selected",this.selectedColor(cs)),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;ctx.clearRect(x-RING_LINE_WIDTH-1,y-RING_LINE_WIDTH-1,cellSize+2*(RING_LINE_WIDTH+1),cellSize+2*(RING_LINE_WIDTH+1));const cs=this.ownerDocument.defaultView?.getComputedStyle(this);if(!cs)return;const ramp=this.colorRamp(normalizeBucketCount(this.bucketCount),cs).colors;this.paintCalendarCell(ctx,pos.week,pos.weekday,cellSize,cs,ramp,this.noDataFill(cs)),this.paintCalendarFocusOverlays(ctx,pos.week,pos.weekday,cellSize,cs),ctx.fillStyle=this.labelColor(cs),ctx.font=this.labelFont(cs);for(const month of this.cachedCalendarGrid.monthLabels)ctx.fillText(month.label,this.columnXFor(month.week),CAL_LABEL_H-4);this.weekdayLabels(firstWeekStart).forEach((label,weekday)=>{label&&ctx.fillText(label,2,this.rowYFor(weekday)+cellSize-1)})}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);this.hasDrawnMatrix=!0;const geometry={padLeft,padTop,cellSize},previous=this.lastEmittedMatrixGeometry;(!previous||previous.padLeft!==padLeft||previous.padTop!==padTop||previous.cellSize!==cellSize)&&(this.lastEmittedMatrixGeometry=geometry,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)}ctx.fillRect(x,y,cellSize-1,cellSize-1)}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))}if(this.selectedCell?.row!=null&&this.selectedCell.col!=null){const{row,col}=this.selectedCell;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))}}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)});const colRotation=this.effectiveColLabelRotation;if(colRotation===0)this.matrixColLabels.forEach((label,c)=>{ctx.fillText(label,padLeft+c*cellSize+2,padTop-COL_LABEL_INSET)});else{const radians=colRotation*Math.PI/180,previousAlign=ctx.textAlign;ctx.textAlign="right",this.matrixColLabels.forEach((label,c)=>{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}this.canvasHasContent=!0}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 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:-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);return{x:this.matrixPadLeft+pos.col*cellSize,y:this.matrixPadTop+pos.row*cellSize,w:cellSize-1,h: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){const text=this.resolveCellText(pos),announcement=this.isSelectedPos(pos)?this.localize("heatmapSelectedCellLabel",void 0,{cell:text}):text;this.liveText=announcement,this.announcementSink?.announce(announcement)}emitCellClick(pos){if(this.isCellInteractive(pos))if("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})}}tooltipStyle(pos){const rect=this.cellRect(pos);return{left:`${rect.x+rect.w/2}px`,top:`${rect.y}px`}}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);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.announce(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.announce(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);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,this.announce(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,this.announce(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"
@@ -973,6 +973,25 @@ export declare class LyraTable<T = unknown> extends LyraElement<LyraTableEventMa
973
973
  *
974
974
  * No `tabindex` on either: a persistent editor is a plain tab stop, exactly like the row-expand
975
975
  * toggle rendered a few lines above, and stays outside the header/row roving model. */
976
+ /** Column keys already reported by `renderCellValue()`, so a 400-row table logs once, not 400
977
+ * times, for the same authoring mistake. */
978
+ private readonly reportedMissingCellColumns;
979
+ /**
980
+ * Renders one cell, tolerating a column that omits its required `cell` renderer.
981
+ *
982
+ * `TableColumn.cell` is typed and documented required, but columns arrive through a lit
983
+ * `.columns=${[...]}` property binding, and lit-html property bindings are not type-checked by
984
+ * `tsc` -- only by lit-analyzer, which many projects do not run. So required-ness is unenforced
985
+ * where it is actually written. Calling it unguarded meant a single malformed column threw out of
986
+ * lit's `repeat` directive and took the WHOLE table down, with a stack carrying only lyra and
987
+ * lit-html frames: no application frame, no column key, no table identity. One report described
988
+ * carrying it undiagnosed across two releases as 16 unattributed unhandled rejections, while the
989
+ * suite still passed because its assertions were on surrounding markup.
990
+ *
991
+ * So: degrade to an empty cell -- the rest of the table stays usable -- and report once per
992
+ * column, naming the key and the tag, because attribution was the harder half of that bug.
993
+ */
994
+ private renderCellValue;
976
995
  private renderCellEditor;
977
996
  /** One rectangular placeholder, using `<lr-skeleton>`'s canonical `shape` axis. `announce` is
978
997
  * switched off on every one of them: `<lr-skeleton>` defaults it