@aceshooting/lyra-ui 11.1.0 → 12.0.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 (153) hide show
  1. package/CHANGELOG.md +456 -0
  2. package/README.md +19 -8
  3. package/custom-elements.json +1 -1
  4. package/dist/all.d.ts +1 -0
  5. package/dist/all.js +1 -1
  6. package/dist/components/agent-tools/activity-feed/activity-feed.class.js +1 -1
  7. package/dist/components/agent-tools/agent-eval-dashboard/agent-eval-dashboard.class.js +1 -1
  8. package/dist/components/agent-tools/agent-run/agent-run.class.js +1 -1
  9. package/dist/components/agent-tools/agent-trace/agent-trace.class.js +1 -1
  10. package/dist/components/agent-tools/browser-frame/browser-frame.class.js +1 -1
  11. package/dist/components/agent-tools/commit-card/commit-card.class.js +1 -1
  12. package/dist/components/agent-tools/span-waterfall/span-waterfall.class.js +1 -1
  13. package/dist/components/agent-tools/task-list/task-list.class.js +2 -2
  14. package/dist/components/agent-tools/test-results/test-results.class.js +1 -1
  15. package/dist/components/agent-tools/thinking-panel/thinking-panel.class.js +1 -1
  16. package/dist/components/agent-tools/tool-call-chip/tool-call-chip.class.js +2 -2
  17. package/dist/components/agent-tools/tool-param-form/tool-param-form.class.d.ts +1 -0
  18. package/dist/components/agent-tools/tool-param-form/tool-param-form.class.js +1 -1
  19. package/dist/components/agent-tools/tool-result-dialog/tool-result-dialog.class.js +2 -2
  20. package/dist/components/agent-tools/trace-tree/trace-tree.class.js +2 -2
  21. package/dist/components/charts/chart/bar-chart.class.js +1 -1
  22. package/dist/components/charts/chart/bubble-chart.class.js +1 -1
  23. package/dist/components/charts/chart/chart.class.d.ts +13 -1
  24. package/dist/components/charts/chart/chart.class.js +1 -1
  25. package/dist/components/charts/chart/doughnut-chart.class.js +1 -1
  26. package/dist/components/charts/chart/histogram.class.js +1 -1
  27. package/dist/components/charts/chart/line-chart.class.js +1 -1
  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/funnel/funnel.class.d.ts +92 -0
  40. package/dist/components/data/funnel/funnel.class.js +25 -0
  41. package/dist/components/data/funnel/funnel.d.ts +1 -0
  42. package/dist/components/data/funnel/funnel.js +1 -0
  43. package/dist/components/data/funnel/funnel.styles.d.ts +1 -0
  44. package/dist/components/data/funnel/funnel.styles.js +127 -0
  45. package/dist/components/data/graph-query-builder/graph-query-builder.class.d.ts +1 -0
  46. package/dist/components/data/graph-query-builder/graph-query-builder.class.js +1 -1
  47. package/dist/components/data/heatmap/heatmap.class.d.ts +222 -5
  48. package/dist/components/data/heatmap/heatmap.class.js +30 -22
  49. package/dist/components/data/heatmap/heatmap.styles.js +36 -0
  50. package/dist/components/data/index.d.ts +1 -0
  51. package/dist/components/data/index.js +1 -1
  52. package/dist/components/data/table/table.class.js +1 -1
  53. package/dist/components/forms/checkbox/checkbox.class.d.ts +1 -0
  54. package/dist/components/forms/checkbox/checkbox.class.js +1 -1
  55. package/dist/components/forms/checkbox-group/checkbox-group.class.d.ts +1 -0
  56. package/dist/components/forms/checkbox-group/checkbox-group.class.js +1 -1
  57. package/dist/components/forms/combobox/combobox.class.d.ts +1 -0
  58. package/dist/components/forms/combobox/combobox.class.js +1 -1
  59. package/dist/components/forms/date-picker/date-input.class.d.ts +23 -0
  60. package/dist/components/forms/date-picker/date-input.class.js +1 -1
  61. package/dist/components/forms/locale-picker/locale-picker.class.d.ts +1 -0
  62. package/dist/components/forms/locale-picker/locale-picker.class.js +1 -1
  63. package/dist/components/forms/radio/radio-group.class.d.ts +1 -0
  64. package/dist/components/forms/radio/radio-group.class.js +1 -1
  65. package/dist/components/forms/radio/radio.class.d.ts +1 -0
  66. package/dist/components/forms/radio/radio.class.js +1 -1
  67. package/dist/components/forms/rubric-form/rubric-form.class.d.ts +1 -0
  68. package/dist/components/forms/rubric-form/rubric-form.class.js +1 -1
  69. package/dist/components/forms/select/select.class.d.ts +1 -0
  70. package/dist/components/forms/select/select.class.js +1 -1
  71. package/dist/components/forms/slider/slider.class.d.ts +1 -0
  72. package/dist/components/forms/slider/slider.class.js +1 -1
  73. package/dist/components/forms/switch/switch.class.d.ts +1 -0
  74. package/dist/components/forms/switch/switch.class.js +1 -1
  75. package/dist/components/forms/time-range/time-range.class.d.ts +1 -0
  76. package/dist/components/forms/time-range/time-range.class.js +1 -1
  77. package/dist/components/forms/token-input/token-input.class.d.ts +1 -0
  78. package/dist/components/forms/token-input/token-input.class.js +1 -1
  79. package/dist/components/layout/app-rail/app-rail-item.class.d.ts +16 -0
  80. package/dist/components/layout/app-rail/app-rail-item.class.js +4 -4
  81. package/dist/components/layout/filter-bar/filter-bar.class.d.ts +32 -3
  82. package/dist/components/layout/filter-bar/filter-bar.class.js +2 -1
  83. package/dist/components/layout/widget/widget.class.d.ts +16 -0
  84. package/dist/components/layout/widget/widget.class.js +2 -2
  85. package/dist/components/lr-funnel.d.ts +1 -0
  86. package/dist/components/lr-funnel.js +1 -0
  87. package/dist/components/media/attachment-chip/attachment-chip.class.js +2 -2
  88. package/dist/components/media/attachment-trigger/attachment-trigger.class.js +2 -2
  89. package/dist/components/media/file-icon/file-icon.class.js +1 -1
  90. package/dist/components/media/file-input/file-input.class.d.ts +1 -0
  91. package/dist/components/media/file-input/file-input.class.js +1 -1
  92. package/dist/components/media/flag/flag-peer-bulk-standard.d.ts +25 -0
  93. package/dist/components/media/flag/flag-peer-bulk-standard.js +1 -0
  94. package/dist/components/media/flag/flag-peer-bulk.d.ts +12 -0
  95. package/dist/components/media/flag/flag-peer-bulk.js +1 -0
  96. package/dist/components/media/flag/flag.class.d.ts +36 -0
  97. package/dist/components/media/flag/flag.class.js +2 -2
  98. package/dist/components/media/map/map.class.d.ts +196 -15
  99. package/dist/components/media/map/map.class.js +1 -1
  100. package/dist/components/overlays/chip/chip-group.class.d.ts +16 -0
  101. package/dist/components/overlays/chip/chip-group.class.js +10 -3
  102. package/dist/components/retrieval/citation-badge/citation-badge.class.js +1 -1
  103. package/dist/components/retrieval/claim-evidence/claim-evidence.class.js +1 -1
  104. package/dist/components/retrieval/grounding-summary/grounding-summary.class.js +2 -2
  105. package/dist/components/retrieval/retrieval-trace/retrieval-trace.class.js +1 -1
  106. package/dist/components/viewers/archive-viewer/archive-viewer.class.js +1 -1
  107. package/dist/components/viewers/contact-viewer/contact-viewer.class.js +1 -1
  108. package/dist/components/viewers/document-compare/document-compare.class.js +1 -1
  109. package/dist/components/viewers/ebook-viewer/ebook-viewer.class.js +1 -1
  110. package/dist/components/viewers/email-viewer/email-viewer.class.js +2 -2
  111. package/dist/custom-elements-jsx.d.ts +12 -4
  112. package/dist/events.d.ts +7 -0
  113. package/dist/internal/autoloader-manifest.js +1 -1
  114. package/dist/internal/autoloader-tags.d.ts +1 -1
  115. package/dist/internal/autoloader-tags.js +1 -1
  116. package/dist/internal/form-associated.d.ts +1 -0
  117. package/dist/internal/form-associated.js +1 -1
  118. package/dist/internal/form-control-labels.js +1 -1
  119. package/dist/internal/lyra-element.d.ts +7 -1
  120. package/dist/internal/lyra-element.js +1 -1
  121. package/dist/internal/package-metadata.d.ts +1 -1
  122. package/dist/internal/package-metadata.js +1 -1
  123. package/dist/internal/root-registration-allowlist.d.ts +1 -1
  124. package/dist/internal/root-registration-allowlist.js +1 -1
  125. package/dist/lyra.d.ts +4 -2
  126. package/dist/lyra.js +1 -1
  127. package/dist/ssr/all.d.ts +1 -0
  128. package/dist/ssr/all.js +1 -1
  129. package/dist/ssr.d.ts +4 -4
  130. package/dist/styles/tokens-root.css +488 -0
  131. package/dist/svelte.d.ts +13 -4
  132. package/dist/vue.d.ts +12 -4
  133. package/llms/components/lr-app-rail-item.md +8 -1
  134. package/llms/components/lr-app-rail.md +6 -0
  135. package/llms/components/lr-chip-group.md +7 -0
  136. package/llms/components/lr-chip.md +7 -0
  137. package/llms/components/lr-date-input.md +19 -1
  138. package/llms/components/lr-date-picker.md +19 -1
  139. package/llms/components/lr-filter-bar.md +50 -1
  140. package/llms/components/lr-flag.md +38 -1
  141. package/llms/components/lr-funnel.md +122 -0
  142. package/llms/components/lr-heatmap.md +64 -8
  143. package/llms/components/lr-map.md +65 -8
  144. package/llms/components/lr-widget.md +7 -1
  145. package/llms/index.md +3 -2
  146. package/llms/peers.md +2 -2
  147. package/llms/shared.md +129 -1
  148. package/llms-full.txt +526 -20
  149. package/llms.txt +1 -1
  150. package/package.json +28 -9
  151. package/vscode-css-data.json +42 -0
  152. package/vscode-html-data.json +96 -17
  153. package/web-types.json +32714 -317
@@ -1,6 +1,7 @@
1
1
  import type { LyraEventDetailSnapshot } from '../../../internal/lyra-element.js';
2
2
  import { type TemplateResult, type PropertyValues } from 'lit';
3
3
  import { LyraElement } from '../../../internal/lyra-element.js';
4
+ import '../../../internal/form-control-labels.js';
4
5
  import { type FormOwnerValue } from '../../../internal/form-associated.js';
5
6
  /** Traversal direction relative to the matched node(s): `'out'` (outgoing edges), `'in'`
6
7
  * (incoming edges), or `'both'`. */
@@ -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}
@@ -1,6 +1,18 @@
1
1
  import { type PropertyValues, type TemplateResult } from 'lit';
2
2
  import { LyraElement } from '../../../internal/lyra-element.js';
3
3
  import { type CalendarDay } from './calendar-grid.js';
4
+ /**
5
+ * Which matrix label band, if any, is frozen while the grid scrolls.
6
+ *
7
+ * One closed set rather than a boolean or a pair of booleans, because freezing one axis is a real
8
+ * request on its own: a wide matrix needs the row gutter to survive horizontal scrolling, a tall one
9
+ * needs the column band to survive vertical scrolling, and the two are independent. A boolean cannot
10
+ * express that at all, and a `sticky-row-labels`/`sticky-col-labels` pair spends two attributes and
11
+ * four states on it while leaving no single reflected value to select on in CSS. The `rows`/`cols`
12
+ * spelling matches the vocabulary the rest of this component already uses (`rowLabels`,
13
+ * `row-label-width`, `colLabels`, `col-label-height`) rather than introducing axis letters.
14
+ */
15
+ export type LyraHeatmapStickyLabels = 'none' | 'rows' | 'cols' | 'both';
4
16
  /**
5
17
  * A linear RGB ramp cannot contain more than 256 visually distinct integer
6
18
  * steps on any channel. Keeping the bucket count within that bound avoids an
@@ -88,6 +100,14 @@ export interface HeatmapLegendStop {
88
100
  color?: string;
89
101
  /** Optional label override; defaults to the component's own numeric formatting of `value`. */
90
102
  label?: string;
103
+ /**
104
+ * Set to `false` to exclude this stop from `warnOnLegendRampMismatch()`'s `colorSteps` agreement
105
+ * check, for a real, distinctly-colored swatch that is intentionally not part of the sequential
106
+ * ramp -- e.g. a calendar heatmap's fixed neutral "no data" color shown alongside an N-step
107
+ * ramp. Defaults to `true`. A caption-only stop (no `color`) is already excluded regardless of
108
+ * this flag, since it describes no color to compare.
109
+ */
110
+ partOfRamp?: boolean;
91
111
  }
92
112
  /** A single cell to mark as persistently selected -- `row`/`col` in matrix mode, `date` in
93
113
  * calendar mode (whichever pair matches the active `mode`; the other field is ignored),
@@ -139,8 +159,14 @@ export type LyraHeatmapCellClickDetail = {
139
159
  col: number;
140
160
  value: number;
141
161
  };
162
+ export type LyraHeatmapMatrixGeometryChangeDetail = {
163
+ padLeft: number;
164
+ padTop: number;
165
+ cellSize: number;
166
+ };
142
167
  export interface LyraHeatmapEventMap {
143
168
  'lr-cell-click': CustomEvent<LyraHeatmapCellClickDetail>;
169
+ 'lr-matrix-geometry-change': CustomEvent<LyraHeatmapMatrixGeometryChangeDetail>;
144
170
  }
145
171
  /**
146
172
  * `<lr-heatmap>` — a Canvas heatmap with a DPR-aware, resize-aware redraw
@@ -213,6 +239,22 @@ export interface LyraHeatmapEventMap {
213
239
  * focus, its semantic matrix coordinate or calendar date remains the sole roving stop; removal
214
240
  * clamps to the nearest survivor, or to the stable heatmap base when no interactive cells remain.
215
241
  *
242
+ * `stickyLabels` freezes a matrix label band against the grid's own scrolling — `'rows'` pins the
243
+ * row-label gutter through horizontal scrolling, `'cols'` pins the column-label band through
244
+ * vertical scrolling, `'both'` pins both. The frozen band is repainted into its own layer from the
245
+ * same `matrixGeometry` the cells were painted with in the same pass, so it tracks a
246
+ * `row-label-width`/`col-label-height` `"auto"` re-resolution instead of hardcoding it. The default
247
+ * `'none'` renders exactly what it always did: one canvas, no scrollport.
248
+ *
249
+ * Everything positioned in canvas coordinates moves into that scrollport with the cells. The hover
250
+ * tooltip renders inside it, so it stays on the cell it describes through a scroll instead of
251
+ * drifting by the scroll offset; since `overflow: auto` there clips whatever leaves the
252
+ * scrollport, it is also kept inside the visible window — clamped along the inline axis, and
253
+ * flipped to below its cell when a frozen band leaves no room above. Arrow-key navigation scrolls
254
+ * the focused cell into that window, clear of the frozen bands: the canvas is the roving tab stop,
255
+ * its focus ring is painted into the bitmap, and it calls `preventDefault()` on the arrows, so
256
+ * without that scroll a keyboard user has no way at all to bring the focused cell back into view.
257
+ *
216
258
  * Calendar `data.columnX` overrides the x-origin computed for each
217
259
  * week column — drawing, hit-testing, the focus ring, and month-label
218
260
  * positioning all consult it consistently, so a consumer can pixel-align a
@@ -251,11 +293,20 @@ export interface LyraHeatmapEventMap {
251
293
  * tooltip and the keyboard live-region announcement. Use the callback for application-specific
252
294
  * wording that is not represented by the locale catalog.
253
295
  * `cellColor` overrides a cell's ramp-computed color entirely for an exact value.
296
+ * @event lr-matrix-geometry-change - Fired after a matrix-mode draw pass whose resolved
297
+ * `matrixGeometry` (`padLeft`/`padTop`/`cellSize`) differs from the previous draw -- e.g. after
298
+ * `row-label-width="auto"`/`col-label-height="auto"` resolves against new label content or a
299
+ * resize. `detail` is the same object `matrixGeometry` returns. Never fired in calendar mode.
254
300
  * @csspart base - The heatmap wrapper.
255
301
  * @csspart canvas - The heatmap canvas.
302
+ * @csspart grid - The scrollport wrapping the canvas while `stickyLabels` freezes an axis; absent otherwise.
303
+ * @csspart row-labels - The frozen row-label gutter, rendered while `stickyLabels` is `rows` or `both`.
304
+ * @csspart col-labels - The frozen column-label band, rendered while `stickyLabels` is `cols` or `both`.
256
305
  * @csspart cells - The opt-in per-cell accessibility overlay.
257
306
  * @csspart cell - An opt-in native button for one matrix or calendar cell.
258
- * @csspart tooltip - The hover tooltip.
307
+ * @csspart tooltip - The hover tooltip, positioned over the hovered cell. It renders inside
308
+ * `[part="grid"]` while `stickyLabels` freezes an axis (so it scrolls with the cells) and as a
309
+ * `[part="base"]` child otherwise.
259
310
  * @csspart live-region - An aria-hidden shadow mirror of the keyboard announcement; the actual
260
311
  * announcement uses the shared light-DOM polite sink.
261
312
  * @csspart projection-limit - Localized assistive disclosure for bounded projections.
@@ -276,6 +327,8 @@ export interface LyraHeatmapEventMap {
276
327
  * @cssprop [--lr-heatmap-focus-ring-color=var(--lr-focus-ring-color)] - Focus ring around a focused cell.
277
328
  * @cssprop [--lr-heatmap-annotation-color=var(--lr-color-danger)] - Border color for an annotated cell.
278
329
  * @cssprop [--lr-heatmap-selected-color=var(--lr-color-success)] - Border color for the selected cell.
330
+ * @cssprop [--lr-heatmap-sticky-label-bg=var(--lr-color-surface)] - Backdrop painted under a frozen `stickyLabels` band. Must be opaque: it covers the same labels the scrolling canvas painted underneath it.
331
+ * @cssprop [--lr-heatmap-grid-max-block-size=none] - Block-size ceiling of the `stickyLabels` scrollport. A frozen column band only stays behind once the grid actually scrolls vertically.
279
332
  * @cssprop [--lr-heatmap-color-steps-gradient=linear-gradient(to right, var(--lr-heatmap-scale-lo), var(--lr-heatmap-scale-hi))] - Gradient painted on the continuous legend bar. Set on the host by the component itself while `colorSteps` is supplied, and removed again when it is not; the fallback is the two-endpoint scale ramp.
280
333
  * @status stable
281
334
  * @since 4.0.0
@@ -339,6 +392,46 @@ export declare class LyraHeatmap extends LyraElement<LyraHeatmapEventMap> {
339
392
  * would be incoherent.
340
393
  */
341
394
  colLabelRotation?: number;
395
+ private _stickyLabels;
396
+ /**
397
+ * Freezes a matrix label band against the grid's own scrolling, instead of leaving it baked into
398
+ * the scrolling bitmap. `'rows'` pins the row-label gutter so it survives horizontal scrolling,
399
+ * `'cols'` pins the column-label band so it survives vertical scrolling, `'both'` pins both, and
400
+ * the default `'none'` renders exactly what this component rendered before the option existed:
401
+ * one canvas, no scrollport, no extra elements.
402
+ *
403
+ * Labels and cells share one bitmap, so a band cannot be `position: sticky` on its own; a tall
404
+ * matrix therefore scrolled its column header away and left the columns unidentifiable. Setting
405
+ * this repaints the requested band into its own layer, in the same draw pass and from the same
406
+ * resolved `matrixGeometry` the cells were painted with, so the two cannot drift under scroll, a
407
+ * resize, a DPR change, or a `rowLabelWidth`/`colLabelHeight` `"auto"` re-resolution. That last
408
+ * one is the point: a hand-rolled light-DOM mirror had to hardcode the gutter width, which made
409
+ * it mutually exclusive with `row-label-width="auto"`.
410
+ *
411
+ * Freezing needs something to scroll, so the frozen modes wrap the grid in a `[part="grid"]`
412
+ * scrollport. It is bounded inline by the host's own allocation (a matrix wider than a 320px host
413
+ * scrolls inside the component rather than overflowing it) and unbounded in block by default; set
414
+ * `--lr-heatmap-grid-max-block-size` to bound it, since a column band can only stay behind while
415
+ * the grid actually scrolls vertically.
416
+ *
417
+ * Matrix mode only, like `matrixGeometry` and `lr-matrix-geometry-change`: calendar mode's axes
418
+ * are a different geometry (a fixed weekday gutter, a month band, and the optional `columnX`/
419
+ * `rowY` overrides), so this property is read but has no effect there.
420
+ *
421
+ * Under `dir="rtl"` the grid keeps this component's documented physical LTR geometry, so the
422
+ * scrollport is direction-pinned like the canvas already is and the bands then freeze against the
423
+ * logical inline-start/block-start edges of that pinned box — which is to say the physical left
424
+ * and top, where the labels they duplicate are actually painted.
425
+ *
426
+ * See `LyraHeatmapStickyLabels` for why this is one closed set rather than a boolean or a pair.
427
+ */
428
+ get stickyLabels(): LyraHeatmapStickyLabels;
429
+ set stickyLabels(next: LyraHeatmapStickyLabels);
430
+ /** `stickyLabels` restricted to the mode it applies to. One gate for render and paint alike, so
431
+ * switching `data` to a calendar can never leave a frozen band or a scrollport behind. */
432
+ private get effectiveStickyLabels();
433
+ private get freezesRowLabels();
434
+ private get freezesColLabels();
342
435
  /** Column band resolved during the last draw, mirroring `resolvedRowLabelWidth`. */
343
436
  private resolvedColLabelHeight;
344
437
  /** Normalized rotation in degrees: finite, clamped to `[0, 90]`. */
@@ -347,6 +440,31 @@ export declare class LyraHeatmap extends LyraElement<LyraHeatmapEventMap> {
347
440
  * painted. Only ever differs from the default while `rowLabelWidth="auto"`. */
348
441
  private resolvedRowLabelWidth;
349
442
  private get matrixPadLeft();
443
+ /**
444
+ * The gutter/cell geometry the last matrix-mode draw actually painted with --
445
+ * `{ padLeft, padTop, cellSize }`, all in CSS pixels -- so a light-DOM consumer (e.g. a sticky
446
+ * header mirror) can line up with the canvas without hardcoding the same numbers `row-label-width`
447
+ * or `col-label-height`'s `"auto"` resolution would otherwise keep private. `undefined` in
448
+ * calendar mode, and before the first matrix draw.
449
+ *
450
+ * This returns the frozen object `drawMatrix()` stored (and `lr-matrix-geometry-change` carried)
451
+ * on the last draw -- not a fresh computation. That distinction is the whole contract. Computing
452
+ * it on read from the same internal getters `drawMatrix()` uses looks equivalent and is not:
453
+ * those getters read CURRENT layout, so any interval where layout has moved but no draw has
454
+ * happened yet makes the getter describe a canvas that does not exist. Two such intervals are
455
+ * routine -- full redraws pause while the host is outside the viewport (documented behaviour of
456
+ * this component), and `rowLabelWidth`/`colLabelHeight` are not redraw-triggering properties at
457
+ * all -- and both land hardest on the tall, partly-scrolled matrix this getter exists to serve.
458
+ * Returning the stored object also makes the getter and the event the same value by
459
+ * construction rather than by coincidence.
460
+ */
461
+ get matrixGeometry(): Readonly<LyraHeatmapMatrixGeometryChangeDetail> | undefined;
462
+ /** The geometry the last `drawMatrix()` pass painted with, frozen and shared with the
463
+ * `lr-matrix-geometry-change` detail. `undefined` until the first draw, which is what gates
464
+ * `matrixGeometry` returning a real value only once there is a draw to describe. Also backs the
465
+ * event's change detection, so a same-valued redraw (a color-only update, an unrelated data
466
+ * change) does not refire it. */
467
+ private lastPaintedMatrixGeometry?;
350
468
  private get matrixPadTop();
351
469
  /** Tallest rotated column label plus inset, floored at the built-in band and capped so labels can
352
470
  * never crowd out the matrix. The column mirror of `measureRowLabelWidth()`. */
@@ -644,7 +762,8 @@ export declare class LyraHeatmap extends LyraElement<LyraHeatmapEventMap> {
644
762
  * Warning rather than deriving one from the other: deriving would silently change what an
645
763
  * existing `colorSteps`-only consumer sees, and would also break the deliberate `cellColor`
646
764
  * 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.
765
+ * Compares only the stops that carry a color -- a caption-only stop describes no color at all --
766
+ * and, among those, only the ones that did not opt out via `partOfRamp: false`.
648
767
  */
649
768
  private warnOnLegendRampMismatch;
650
769
  private cachedLegendStops;
@@ -733,6 +852,10 @@ export declare class LyraHeatmap extends LyraElement<LyraHeatmapEventMap> {
733
852
  private labelColor;
734
853
  /** Reads the customizable canvas axis/label font off the host's computed style. */
735
854
  private labelFont;
855
+ /** Reads the customizable frozen-label-band backdrop off the host's computed style, resolved to a
856
+ * concrete color: canvas silently keeps its previous `fillStyle` for anything it cannot parse,
857
+ * and a `var()` chain is exactly that. */
858
+ private stickyLabelBg;
736
859
  /** Reads the customizable no-data cell fill off the host's computed style. */
737
860
  private noDataFill;
738
861
  /** Reads the customizable canvas-drawn keyboard-focus-ring stroke color off the host's computed style. */
@@ -863,6 +986,32 @@ export declare class LyraHeatmap extends LyraElement<LyraHeatmapEventMap> {
863
986
  private paintCalendarFocusOverlays;
864
987
  private repaintCalendarFocusCell;
865
988
  private drawMatrix;
989
+ /** Paints the row-label gutter at `x = 0 .. padLeft`. Extracted so the cell canvas and a frozen
990
+ * `[part="row-labels"]` band paint from one routine and one set of geometry arguments — the
991
+ * band's own canvas shares the cell canvas's origin, so "aligned" is what the same coordinates
992
+ * mean, rather than something a second implementation has to keep agreeing about. */
993
+ private paintMatrixRowLabels;
994
+ /** The column-label band at `y = 0 .. padTop`, rotation included. The mirror of
995
+ * `paintMatrixRowLabels()`, shared with a frozen `[part="col-labels"]` band the same way. */
996
+ private paintMatrixColLabels;
997
+ /**
998
+ * Repaints whichever label bands `stickyLabels` freezes, from the geometry this very draw pass
999
+ * painted the cells with. Each band is a canvas sharing the cell canvas's origin (both sit in the
1000
+ * same single-area grid), sized to the band it owns and offset on one axis only by
1001
+ * `position: sticky`, so it slides along the axis it is not frozen on and stays put on the one it
1002
+ * is. Nothing here recomputes geometry, which is what keeps a band aligned across a resize, a DPR
1003
+ * change, and a `row-label-width`/`col-label-height` `"auto"` re-resolution alike.
1004
+ *
1005
+ * The cell canvas keeps painting its own labels underneath: leaving that pass untouched is what
1006
+ * makes the default `'none'` byte-identical, and the band's opaque backdrop covers the duplicate
1007
+ * once it scrolls out from under the frozen copy.
1008
+ */
1009
+ private paintFrozenLabelBands;
1010
+ private frozenBandCanvas;
1011
+ /** Sizes one band's backing store to the same DPR the cell canvas uses, fills the opaque backdrop,
1012
+ * then hands the caller a context already in CSS-pixel coordinates identical to the cell
1013
+ * canvas's — so a label lands on the same physical pixel in both. */
1014
+ private paintFrozenBand;
866
1015
  /**
867
1016
  * Maps a pointer position, in canvas-local CSS px (e.g.
868
1017
  * `PointerEvent.offsetX/offsetY`), to the cell underneath it — or `null`
@@ -905,7 +1054,7 @@ export declare class LyraHeatmap extends LyraElement<LyraHeatmapEventMap> {
905
1054
  * `CalendarCellPos` in this component goes through here, so no call site can forget the date. */
906
1055
  private calendarPos;
907
1056
  /**
908
- * Pixel rect (canvas-local CSS px) of a cell — shared by `tooltipStyle()`
1057
+ * Pixel rect (canvas-local CSS px) of a cell — shared by `tooltipAnchor()`
909
1058
  * so the tooltip's position always agrees with the same geometry
910
1059
  * `drawMatrix()`/`drawCalendar()`/`hitTest*()` use.
911
1060
  */
@@ -933,8 +1082,53 @@ export declare class LyraHeatmap extends LyraElement<LyraHeatmapEventMap> {
933
1082
  * wording anywhere around the cell text instead of it being appended. */
934
1083
  private announce;
935
1084
  private emitCellClick;
936
- /** Inline `style` for `[part="tooltip"]`, centered above the given cell. */
937
- private tooltipStyle;
1085
+ /** The `stickyLabels` scrollport, or `null` in the default unfrozen render, which has none. */
1086
+ private get gridScrollport();
1087
+ /** The tooltip's own rendered box in CSS px, recorded by `measureTooltip()`: `inline` is its
1088
+ * border box, `block` that box plus the token-sized gap it keeps from the cell. Only read while
1089
+ * a scrollport can clip it; zero until the first measurement, which degrades to the unclamped
1090
+ * placement rather than to a wrong one. */
1091
+ private tooltipSize;
1092
+ /**
1093
+ * Records the tooltip's rendered size, so the next paint can keep it inside the `stickyLabels`
1094
+ * scrollport. Measured rather than derived: the box is sized by caller text, and the gap it
1095
+ * keeps from the cell is a design token whose value belongs in the stylesheet.
1096
+ *
1097
+ * Repositioning can never resize it (`white-space: nowrap`, no inline-size constraint), so the
1098
+ * re-render scheduled here always settles in one step. It runs from `scheduleAfterUpdate()`
1099
+ * rather than straight out of `updated()` on purpose: that keeps the `requestUpdate()` outside
1100
+ * Lit's own update cycle, and its microtask still flushes before paint, so the corrected
1101
+ * position is the first one the user ever sees.
1102
+ */
1103
+ private measureTooltip;
1104
+ /**
1105
+ * Inline `style` for `[part="tooltip"]` — centered on the given cell — plus whether it had to be
1106
+ * flipped below that cell.
1107
+ *
1108
+ * With no `stickyLabels` scrollport this is the original unconditional "centered above the cell"
1109
+ * placement, in the canvas-local coordinates `cellRect()` returns. With one, the tooltip renders
1110
+ * *inside* that scrollport, which is what keeps it pinned to the cell it describes through a
1111
+ * scroll — and there `overflow: auto` clips whatever leaves the scrollport, while an opaque
1112
+ * frozen band hides whatever is drawn under it. So the placement is additionally kept inside the
1113
+ * band-free part of the visible window: still centered on the cell but clamped to that window,
1114
+ * and flipped to below the cell when there is no room above it and there is room below. Flipping
1115
+ * is conditional on both, deliberately: an unconditional flip at the block end would push the
1116
+ * tooltip past the content box and grow the scrollable area under the pointer.
1117
+ */
1118
+ private tooltipAnchor;
1119
+ /**
1120
+ * Keeps the keyboard-focused cell inside the `stickyLabels` scrollport, clear of the frozen
1121
+ * bands' own boxes.
1122
+ *
1123
+ * Without this the feature is an accessibility regression: the default (unset `accessibleCells`)
1124
+ * roving stop is the canvas itself, its focus ring is painted into the canvas bitmap rather than
1125
+ * carried by a focusable element the browser would scroll to, and `onMatrixKeyDown()` calls
1126
+ * `preventDefault()` on every arrow — so the browser's own scrolling never happens either, and
1127
+ * arrowing far enough leaves the focus indicator off-screen with no keyboard way to reveal it.
1128
+ * A minimal scroll (never re-centering a cell that is already fully visible) keeps the scroll
1129
+ * position stable while arrowing around inside the visible window.
1130
+ */
1131
+ private scrollCellIntoView;
938
1132
  /**
939
1133
  * Value-equality check for a `CellPos`, since `hoverCell` is assigned a
940
1134
  * fresh object literal on every `pointermove` — Lit's `@state()`
@@ -981,6 +1175,29 @@ export declare class LyraHeatmap extends LyraElement<LyraHeatmapEventMap> {
981
1175
  * unset (or empty) `legendStops` therefore reproduces the pre-`legendStops` markup exactly.
982
1176
  */
983
1177
  private renderLegendScale;
1178
+ /**
1179
+ * The cell canvas, the opt-in per-cell overlay, and — while `stickyLabels` freezes an axis — the
1180
+ * frozen label bands, wrapped in the scrollport those bands stick to.
1181
+ *
1182
+ * Both branches emit the same canvas and overlay from one template, so the unfrozen default keeps
1183
+ * rendering exactly the elements it always did (no wrapper, no scrollport, no second canvas) with
1184
+ * no second copy of the canvas's attribute/listener surface to drift. The bands are decorative
1185
+ * duplicates of pixels the cell canvas already painted, so they carry `aria-hidden` and no role:
1186
+ * the accessible representation stays the canvas's own `role="application"` name, or the
1187
+ * `[part="cells"]` grid under `accessibleCells` — which moves inside the scrollport so the cells
1188
+ * scroll with the canvas they overlay.
1189
+ */
1190
+ private renderGridSurface;
1191
+ /**
1192
+ * The hover tooltip, rendered once: inside the `stickyLabels` scrollport's stack when an axis is
1193
+ * frozen (see `renderGridSurface()`), and as the `[part="base"]` sibling it has always been
1194
+ * otherwise, where the canvas's origin already *is* the base's.
1195
+ *
1196
+ * `dir` is carried explicitly because the scrollport pins `direction: ltr` for the physically
1197
+ * non-mirrored grid geometry, and the tooltip is the one thing in there that is prose rather
1198
+ * than geometry -- it keeps the host's own direction it inherited before the scrollport existed.
1199
+ */
1200
+ private renderTooltip;
984
1201
  render(): TemplateResult;
985
1202
  /** `localize()` interpolates with a bare `String(value)`, so a number handed to it renders in
986
1203
  * ASCII digits no matter the locale -- mixing two numbering systems inside one translated