UNPKG

js.foresight-devtools

Version:

Visual debugging tools for ForesightJS - mouse trajectory prediction and element interaction visualization

1,086 lines (1,009 loc) 101 kB
var ze=Object.defineProperty;var He=Object.getOwnPropertyDescriptor;var n=(o,r,e,t)=>{for(var i=t>1?void 0:t?He(r,e):r,a=o.length-1,s;a>=0;a--)(s=o[a])&&(i=(t?s(r,e,i):s(i))||i);return t&&i&&ze(r,e,i),i};import{LitElement as zn,css as Hn,html as Fe}from"lit";import{customElement as Bn,state as Gn}from"lit/decorators.js";import{LitElement as yn,css as wn,html as xn}from"lit";import{customElement as kn,state as Q}from"lit/decorators.js";import{classMap as re}from"lit/directives/class-map.js";import{ForesightManager as Ae}from"js.foresight";import{css as St,html as B,LitElement as Tt}from"lit";import{customElement as Dt,state as L}from"lit/decorators.js";import{map as Me}from"lit/directives/map.js";import{ForesightManager as $}from"js.foresight";import{html as c}from"lit";var le=c` <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" > <rect x="2" y="2" width="20" height="15" rx="2" ry="2"></rect> <line x1="2" y1="17" x2="22" y2="17"></line> <line x1="7" y1="21" x2="17" y2="21"></line> <line x1="12" y1="17" x2="12" y2="21"></line> </svg> `,ce=c` <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" > <polyline points="4 17 10 11 4 5"></polyline> <line x1="12" y1="19" x2="20" y2="19"></line> </svg> `,de=c` <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" > <path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"></path> <path d="M13.73 21a2 2 0 0 1-3.46 0"></path> <line x1="1" y1="1" x2="23" y2="23"></line> </svg> `,ge=c` <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" > <path d="M12 2v8" /> <path d="M12 10l-6 6" /> <path d="M12 10l6 6" /> <circle cx="6" cy="18" r="2" /> <circle cx="18" cy="18" r="2" /> </svg> `,pe=c` <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" > <path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z" /> <circle cx="12" cy="12" r="3" /> </svg> `,he=c` <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" > <path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z" /> <polyline points="14 2 14 8 20 8" /> <line x1="16" y1="13" x2="8" y2="13" /> <line x1="16" y1="17" x2="8" y2="17" /> <line x1="10" y1="9" x2="8" y2="9" /> </svg> `,me=c` <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" > <path d="M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01" /> </svg> `,h=c` <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" > <polygon points="22,3 2,3 10,12.46 10,19 14,21 14,12.46" /> </svg> `,ue=c` <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" > <circle cx="12" cy="12" r="10" /> <line x1="4.93" y1="4.93" x2="19.07" y2="19.07" /> </svg> `,be=c` <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" > <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect> <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path> </svg> `,ve=c` <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" > <polyline points="20 6 9 17 4 12"></polyline> </svg> `,fe=c` <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" > <path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" ></path> <line x1="12" y1="9" x2="12" y2="13"></line> <line x1="12" y1="17" x2="12.01" y2="17"></line> </svg> `,ye=c` <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" > <circle cx="6" cy="12" r="3"></circle> <circle cx="18" cy="12" r="3"></circle> <path d="M9 12h6"></path> <path d="M15 9l3 3-3 3"></path> <circle cx="12" cy="6" r="2"></circle> <circle cx="12" cy="18" r="2"></circle> <path d="M10 8l2-2 2 2"></path> <path d="M14 16l-2 2-2-2"></path> </svg> `,we=c` <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" > <polyline points="3 6 5 6 21 6"></polyline> <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path> <line x1="10" y1="11" x2="10" y2="17"></line> <line x1="14" y1="11" x2="14" y2="17"></line> </svg> `,Yn=c` <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" > <path d="M18 8a6 6 0 0 0-12 0c0 2 3 4 6 6 3-2 6-4 6-6z"/> <circle cx="12" cy="8" r="3"/> </svg> `,Jn=c` <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" > <rect x="2" y="3" width="20" height="14" rx="2" ry="2"/> <line x1="8" y1="21" x2="16" y2="21"/> <line x1="12" y1="17" x2="12" y2="21"/> <circle cx="12" cy="10" r="2"/> </svg> `,Xn=c` <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" > <circle cx="12" cy="12" r="10"/> <line x1="4.93" y1="4.93" x2="19.07" y2="19.07"/> </svg> `;import{LitElement as Be,html as Ge,css as We}from"lit";import{customElement as Ke,property as qe}from"lit/decorators.js";var U=class extends Be{constructor(){super(...arguments);this.title=""}render(){return Ge` <span class="chip" title="${this.title}"> <slot></slot> </span> `}};U.styles=[We` :host { display: inline-block; } .chip { display: inline-flex; align-items: center; padding: 3px 8px; background-color: rgba(255, 255, 255, 0.05); color: #e8e8e8; font-size: 10px; font-weight: 500; white-space: nowrap; border: 1px solid rgba(255, 255, 255, 0.1); font-family: "SF Mono", "Monaco", "Consolas", "Liberation Mono", "Courier New", monospace; letter-spacing: 0.02em; line-height: 1.2; transition: all 0.2s ease; } `],n([qe({type:String})],U.prototype,"title",2),U=n([Ke("chip-element")],U);import{LitElement as Ye,html as te,css as Je}from"lit";import{customElement as Xe,property as xe}from"lit/decorators.js";var D=class extends Ye{constructor(){super(...arguments);this.noContentMessage="No content available.";this.hasContent=!0}render(){return te` <div class="content-container"> ${this.hasContent?te`<slot></slot>`:te`<div class="no-content-message">${this.noContentMessage}</div>`} </div> `}};D.styles=[Je` :host { overflow: hidden; } .content-container::-webkit-scrollbar { width: 8px; } .content-container::-webkit-scrollbar-track { background: rgba(30, 30, 30, 0.5); } .content-container::-webkit-scrollbar-thumb { background-color: rgba(176, 196, 222, 0.5); border: 2px solid rgba(0, 0, 0, 0.2); } .content-container::-webkit-scrollbar-thumb:hover { background-color: rgba(176, 196, 222, 0.7); } .content-container { scrollbar-gutter: stable; height: 100%; min-height: 150px; overflow-y: auto; scrollbar-width: thin; scrollbar-color: rgba(176, 196, 222, 0.5) rgba(30, 30, 30, 0.5); } .no-content-message { display: flex; justify-content: center; align-items: center; height: 100%; color: #afafaf; font-style: italic; font-family: "Courier New", monospace; } `],n([xe({type:String,attribute:"no-content-message"})],D.prototype,"noContentMessage",2),n([xe({type:Boolean})],D.prototype,"hasContent",2),D=n([Xe("tab-content")],D);import{LitElement as Ze,html as Qe,css as et}from"lit";import{customElement as tt}from"lit/decorators.js";var z=class extends Ze{render(){return Qe` <div class="tab-bar-elements"> <div class="tab-bar-info"> <div class="stats-chips"> <slot name="chips"></slot> </div> </div> <div class="tab-bar-actions"> <slot name="actions"></slot> </div> </div> `}};z.styles=[et` :host { } .tab-bar-info { display: flex; gap: 12px; align-items: center; flex: 1; } .stats-chips { display: flex; gap: 8px; align-items: center; } .chip { font-size: 11px; font-weight: 500; padding: 4px 8px; border: 1px solid #555; white-space: nowrap; letter-spacing: 0.3px; background: rgba(40, 40, 40, 0.7); color: #b0c4de; } .tab-bar-actions { display: flex; gap: 6px; align-items: center; position: relative; flex-direction: row; } .tab-bar-elements { display: flex; justify-content: space-between; padding: 4px 0 4px 0; border-bottom: 1px solid #444; position: sticky; top: 0; z-index: 5; min-height: 36px; } `],z=n([tt("tab-header")],z);import{html as rt}from"lit";import{customElement as st,property as Ee}from"lit/decorators.js";import{LitElement as nt,html as ke,css as it}from"lit";import{property as ot,state as at}from"lit/decorators.js";var g=class g extends nt{constructor(){super(...arguments);this.isDropdownOpen=!1;this.dropdownOptions=[];this._toggleDropdown=e=>{e.stopPropagation(),this.isDropdownOpen?this._closeDropdown():(g.currentlyOpen&&g.currentlyOpen!==this&&g.currentlyOpen._closeDropdown(),this.isDropdownOpen=!0,g.currentlyOpen=this,requestAnimationFrame(()=>{this._positionDropdown()}))};this._handleOutsideClick=e=>{this.isDropdownOpen&&(e.composedPath().includes(this)||this._closeDropdown())}}connectedCallback(){super.connectedCallback(),document.addEventListener("click",this._handleOutsideClick)}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("click",this._handleOutsideClick),g.currentlyOpen===this&&(g.currentlyOpen=null)}_closeDropdown(){this.isDropdownOpen=!1,g.currentlyOpen===this&&(g.currentlyOpen=null)}_positionDropdown(){if(typeof window>"u")return;let e=this.shadowRoot?.querySelector(".trigger-button"),t=this.shadowRoot?.querySelector(".dropdown-menu");if(e&&t){let i=e.getBoundingClientRect(),a=t.offsetHeight||200,s=i.bottom+5,d=window.innerWidth-i.right;window.innerHeight-i.bottom<a&&i.top>a?t.style.top=`${i.top-a-5}px`:t.style.top=`${s}px`,t.style.right=`${d}px`}}render(){let e=`trigger-button ${this.isDropdownOpen?"active":""}`,t=`dropdown-menu ${this.isDropdownOpen?"active":""}`;return ke` <div class="dropdown-container"> <button class="${e}" title="${this._getTriggerTitle()}" @click="${this._toggleDropdown}" aria-haspopup="true" aria-expanded="${this.isDropdownOpen}" aria-controls="dropdown-menu" aria-label="${this._getTriggerLabel()}" > ${this._getTriggerIcon()} <svg class="arrow-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" > <polyline points="6 9 12 15 18 9"></polyline> </svg> </button> <div class="${t}" id="dropdown-menu" role="menu"> ${this.dropdownOptions.map(i=>ke` <button value="${i.value}" title="${i.title}" class="${this._isOptionSelected(i)?"active":""}" @click="${()=>this._handleOptionClick(i)}" role="menuitem" > ${i.label} </button> `)} </div> </div> `}};g.currentlyOpen=null,g.styles=[it` :host { display: inline-block; } .dropdown-container { position: relative; display: inline-block; } .trigger-button { background: none; border: none; color: white; cursor: pointer; padding: 6px; display: flex; align-items: center; justify-content: center; gap: 4px; transition: all 0.2s ease; } .trigger-button svg { width: 16px; height: 16px; stroke: white; transition: stroke 0.2s; } .trigger-button .arrow-icon { width: 10px; height: 10px; stroke: white; fill: none; stroke-width: 2; transition: transform 0.2s ease, stroke 0.2s; } .trigger-button:hover { background-color: rgba(176, 196, 222, 0.1); } .trigger-button:hover svg, .trigger-button:hover .arrow-icon { stroke: #b0c4de; } .trigger-button.active { background-color: rgba(176, 196, 222, 0.2); } .trigger-button.active svg { stroke: #b0c4de; } .trigger-button.active .arrow-icon { transform: rotate(180deg); stroke: #b0c4de; } .dropdown-menu { position: fixed; z-index: 9999; display: none; flex-direction: column; background-color: #3a3a3a; border: 1px solid #555; min-width: 200px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); overflow: hidden; } .dropdown-menu.active { display: flex; } .dropdown-menu button { background: none; border: none; color: #ccc; font-size: 12px; text-align: left; padding: 8px 12px; cursor: pointer; transition: all 0.2s ease; display: flex; align-items: center; position: relative; width: 100%; box-sizing: border-box; } .dropdown-menu button:hover { background-color: #555; color: white; } .dropdown-menu button.active { color: #b0c4de; font-weight: bold; background-color: rgba(176, 196, 222, 0.1); } .dropdown-menu button.active::after { content: "✓"; position: absolute; right: 8px; top: 50%; transform: translateY(-50%); color: #b0c4de; font-weight: bold; } `],n([at()],g.prototype,"isDropdownOpen",2),n([ot({type:Array})],g.prototype,"dropdownOptions",2);var M=g;var N=class extends M{constructor(){super(...arguments);this.selectedOptionValue=""}connectedCallback(){super.connectedCallback(),this.dropdownOptions.length>0&&!this.selectedOptionValue&&(this.selectedOptionValue=this.dropdownOptions[0].value)}willUpdate(e){e.has("dropdownOptions")&&this.dropdownOptions.length>0&&!this.selectedOptionValue&&(this.selectedOptionValue=this.dropdownOptions[0].value)}_handleOptionClick(e){e.value!==this.selectedOptionValue&&(this.selectedOptionValue=e.value,this.onSelectionChange?.(e.value)),this._closeDropdown()}_getTriggerIcon(){let e=this._getSelectedOption();return e?e.icon:rt``}_isOptionSelected(e){return e.value===this.selectedOptionValue}_getTriggerTitle(){let e=this._getSelectedOption();return e?e.title:"Change selection"}_getTriggerLabel(){let e=this._getSelectedOption();return e?`Current selection: ${e.label}`:"No selection"}_getSelectedOption(){return this.dropdownOptions.find(e=>e.value===this.selectedOptionValue)}};n([Ee({type:String})],N.prototype,"selectedOptionValue",2),n([Ee({type:Function})],N.prototype,"onSelectionChange",2),N=n([st("single-select-dropdown")],N);import{LitElement as wt,html as xt,css as kt}from"lit";import{customElement as Et,property as J,state as Ct}from"lit/decorators.js";import{LitElement as pt,html as Te,css as ht}from"lit";import{customElement as mt,property as H}from"lit/decorators.js";import{LitElement as lt,html as ct,css as dt}from"lit";import{customElement as gt,property as Ce,state as Se}from"lit/decorators.js";var y=class extends lt{constructor(){super(...arguments);this.title="Copy to clipboard";this.isCopied=!1;this.copyTimeout=null}async handleClick(e){if(!this.isCopied){if(this.onCopy)try{await this.onCopy(e)}catch(t){console.error("Error in onCopy function:",t)}this.isCopied=!0,this.copyTimeout&&clearTimeout(this.copyTimeout),this.copyTimeout=setTimeout(()=>{this.isCopied=!1,this.copyTimeout=null},2e3)}}disconnectedCallback(){super.disconnectedCallback(),this.copyTimeout&&(clearTimeout(this.copyTimeout),this.copyTimeout=null)}render(){return ct` <button class="copy-button ${this.isCopied?"copied":""}" title="${this.title}" @click=${this.handleClick} > ${this.isCopied?ve:be} </button> `}};y.styles=dt` .copy-button { background: transparent; border: 0px; cursor: pointer; padding: 6px; display: flex; align-items: center; justify-content: center; opacity: 0.6; transition: opacity 0.2s ease, background-color 0.2s ease; } :host([positioned]) .copy-button { position: absolute; top: 10px; right: 1px; } .copy-button:hover { background-color: rgba(176, 196, 222, 0.1); } .copy-button:hover svg { stroke: #b0c4de; } .copy-button svg { width: 14px; height: 14px; stroke: #ddd; stroke-width: 2.5; } .copy-button.copied svg { stroke: #4caf50; } `,n([Ce({type:String})],y.prototype,"title",2),n([Ce({type:Function})],y.prototype,"onCopy",2),n([Se()],y.prototype,"isCopied",2),n([Se()],y.prototype,"copyTimeout",2),y=n([gt("copy-icon")],y);var b=class extends pt{constructor(){super(...arguments);this.borderColor="#555";this.showCopyButton=!1;this.itemId="";this.isExpanded=!1}toggleExpand(){this.onToggle&&this.onToggle(this.itemId)}async handleCopy(e){e.stopPropagation();let t=this.shadowRoot?.querySelector('slot[name="details"]');if(t){let a=t.assignedNodes().map(s=>s.textContent).join("");try{await navigator.clipboard.writeText(a)}catch(s){console.error("Failed to copy text: ",s)}}}render(){return this.style.setProperty("--border-color",this.borderColor),Te` <div class="item-entry ${this.isExpanded?"expanded":""}"> <div class="item-header ${this.isExpanded?"expanded":""}" @click="${this.toggleExpand}"> <div class="item-content"> <slot name="content"></slot> </div> <span class="item-toggle ${this.isExpanded?"expanded":""}"> <svg viewBox="0 0 24 24"> <polyline points="9,18 15,12 9,6"></polyline> </svg> </span> </div> ${this.isExpanded?Te` <div class="item-details"> <copy-icon positioned title="Copy Details" .onCopy=${e=>this.handleCopy(e)} ></copy-icon> <pre class="item-data"> <slot name="details"></slot> </pre> </div> `:""} </div> `}};b.styles=[ht` :host { display: block; } .item-entry { margin-bottom: 2px; font-size: 11px; line-height: 1.3; overflow: hidden; transition: all 0.2s ease; border-left: 2px solid var(--border-color, #555); padding-left: 6px; } .item-entry:hover:not(.expanded) { background-color: rgba(255, 255, 255, 0.02); } .item-entry.expanded { background-color: rgba(255, 255, 255, 0.03); } .item-header { display: flex; align-items: center; padding: 3px 4px; cursor: pointer; transition: background-color 0.2s ease; gap: 8px; min-height: 20px; } .item-header:hover:not(.expanded) { background-color: rgba(255, 255, 255, 0.03); } .item-details { position: relative; border-top: 1px solid rgba(255, 255, 255, 0.1); } .item-toggle { display: flex; align-items: center; justify-content: center; width: 16px; height: 16px; user-select: none; cursor: pointer; transition: all 0.2s ease; } .item-toggle:hover { background-color: rgba(255, 255, 255, 0.1); } .item-toggle svg { width: 14px; height: 14px; fill: none; stroke: #b0c4de; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; transition: all 0.2s ease; } .item-toggle:hover svg { stroke: #d4e4f4; } .item-toggle.expanded svg { transform: rotate(90deg); } .item-content { flex: 1; display: flex; align-items: center; gap: 8px; min-width: 0; overflow: hidden; } .item-data { color: #e0e0e0; white-space: pre; font-size: 11px; margin: 0; padding: 0; font-family: "Courier New", monospace; line-height: 1.3; display: block; overflow-x: auto; } `],n([H()],b.prototype,"borderColor",2),n([H()],b.prototype,"showCopyButton",2),n([H()],b.prototype,"itemId",2),n([H()],b.prototype,"isExpanded",2),n([H()],b.prototype,"onToggle",2),b=n([mt("expandable-item")],b);import{ForesightManager as ut}from"js.foresight";import{LitElement as bt,css as vt,html as Y}from"lit";import{customElement as ft,property as yt,state as De}from"lit/decorators.js";var E=class extends bt{constructor(){super(...arguments);this.remainingTime=0;this.isCountdownActive=!1;this.intervalId=null;this.startTime=0;this.handleTimerClick=e=>{e.stopPropagation(),ut.instance.reactivate(this.elementData.element)}}connectedCallback(){super.connectedCallback(),this.checkAndStartCountdown()}disconnectedCallback(){super.disconnectedCallback(),this.clearCountdown()}updated(e){super.updated(e),e.has("elementData")&&this.checkAndStartCountdown()}checkAndStartCountdown(){let e=this.elementData?.callbackInfo;if(!e){this.clearCountdown();return}let t=e.lastCallbackCompletedAt||e.lastCallbackInvokedAt;!e.isCallbackActive&&t&&e.reactivateAfter>0?this.startCountdown():this.clearCountdown()}startCountdown(){this.clearCountdown();let e=this.elementData?.callbackInfo;if(!e)return;if(this.isCountdownActive=!0,e.reactivateAfter===1/0){this.remainingTime=1/0;return}let t=e.reactivateAfter,i=e.lastCallbackCompletedAt||e.lastCallbackInvokedAt;if(!i){this.clearCountdown();return}this.startTime=i;let a=()=>{let s=Date.now()-this.startTime,d=Math.max(0,t-s);this.remainingTime=d,this.requestUpdate(),(d<=0||this.elementData.callbackInfo.isCallbackActive)&&this.clearCountdown()};a(),this.remainingTime>0&&typeof window<"u"&&(this.intervalId=window.setInterval(a,100))}clearCountdown(){this.intervalId!==null&&(clearInterval(this.intervalId),this.intervalId=null),this.isCountdownActive=!1,this.remainingTime=0}formatTime(e){if(e===1/0)return"\u221E";let t=Math.ceil(e/1e3);if(t<60)return`${t}s`;let i=Math.floor(t/60),a=t%60;if(i<60)return a>0?`${i}m ${a}s`:`${i}m`;let s=Math.floor(i/60),d=i%60;return d>0?`${s}h ${d}m`:`${s}h`}render(){return this.isCountdownActive?this.remainingTime===1/0?Y` <button class="reactivate-button" @click="${this.handleTimerClick}" title="Click to reactivate manually" > <span class="countdown-time infinity">∞</span> </button> `:this.remainingTime<=0?Y``:Y` <button class="reactivate-button" @click="${this.handleTimerClick}" title="Click to reactivate immediately" > <span class="countdown-time clickable">${this.formatTime(this.remainingTime)}</span> </button> `:Y``}};E.styles=[vt` :host { display: inline-block; } .reactivate-button { all: unset; cursor: pointer; padding: 2px 4px; transition: background-color 0.2s ease; } .reactivate-button:hover { background-color: rgba(255, 165, 0, 0.1); } .countdown-time { color: #ffa726; font-weight: 500; font-size: 10px; } .countdown-time.infinity { font-size: 12px; font-weight: 600; } .countdown-time.clickable { cursor: pointer; } `],n([yt({hasChanged:()=>!0})],E.prototype,"elementData",2),n([De()],E.prototype,"remainingTime",2),n([De()],E.prototype,"isCountdownActive",2),E=n([ft("reactivate-countdown")],E);import{ForesightManager as ne}from"js.foresight";var v=class extends wt{constructor(){super(...arguments);this.isActive=!1;this.isExpanded=!1;this.currentDeviceStrategy="mouse";this._abortController=null;this.handleUnregister=e=>{e.stopPropagation(),ne.instance.unregister(this.elementData.element,"devtools")}}connectedCallback(){super.connectedCallback(),this._abortController=new AbortController;let{signal:e}=this._abortController;this.currentDeviceStrategy=ne.instance.getManagerData.currentDeviceStrategy,ne.instance.addEventListener("deviceStrategyChanged",t=>{this.currentDeviceStrategy=t.newStrategy},{signal:e})}disconnectedCallback(){super.disconnectedCallback(),this._abortController?.abort(),this._abortController=null}getBorderColor(){return this.isActive?"#ffeb3b":this.elementData.callbackInfo.isCallbackActive?this.currentDeviceStrategy==="touch"?"#ba68c8":this.elementData.isIntersectingWithViewport?"#4caf50":"#666":"#999"}getStatusIndicatorClass(){return this.isActive?"prefetching":this.elementData.callbackInfo.isCallbackActive?this.currentDeviceStrategy==="touch"?"touch-device":this.elementData.isIntersectingWithViewport?"visible":"hidden":"inactive"}getStatusText(){if(this.isActive)return"callback active";if(!this.elementData.callbackInfo.isCallbackActive)return"callback inactive";let e=this.elementData.isIntersectingWithViewport?"in viewport":"not in viewport",t=this.currentDeviceStrategy==="touch"?" (touch device)":"";return e+t}formatElementDetails(){let e=this.elementData,t={status:this.getStatusText(),isIntersecting:e.isIntersectingWithViewport,registerCount:e.registerCount,hitSlop:{top:e.elementBounds.hitSlop.top,right:e.elementBounds.hitSlop.right,bottom:e.elementBounds.hitSlop.bottom,left:e.elementBounds.hitSlop.left},callbackInfo:e.callbackInfo,meta:this.elementData.meta};return JSON.stringify(t,null,2)}render(){let e=!this.elementData.isIntersectingWithViewport&&this.currentDeviceStrategy!=="touch";return xt` <div class="element-wrapper ${e?"not-visible":""}"> <expandable-item .borderColor=${this.getBorderColor()} .showCopyButton=${!0} .itemId=${this.elementData.id} .isExpanded=${this.isExpanded} .onToggle=${this.onToggle} > <div slot="content" class="element-content" title="Status: ${this.getStatusText()}"> <div class="status-indicator ${this.getStatusIndicatorClass()}"></div> <span class="element-name ${this.isActive?"callback-active":this.elementData.callbackInfo.isCallbackActive?"":"callback-inactive"}" > ${this.elementData.name||"unnamed"} </span> <reactivate-countdown .elementData=${this.elementData}> </reactivate-countdown> <button class="unregister-button" @click="${this.handleUnregister}" title="Unregister element" > ${we} </button> </div> <div slot="details">${this.formatElementDetails()}</div> </expandable-item> </div> `}};v.styles=[kt` :host { display: block; } .element-wrapper { display: block; } .element-content { display: flex; align-items: center; gap: 8px; flex: 1; } .status-indicator { margin-left: 2px; width: 8px; height: 8px; flex-shrink: 0; transition: all 0.3s ease; } .status-indicator.visible { background-color: #4caf50; box-shadow: 0 0 0 2px rgba(76, 175, 80, 0.3); } .status-indicator.hidden { background-color: #666; box-shadow: 0 0 0 2px rgba(102, 102, 102, 0.2); } .status-indicator.prefetching { background-color: #ffeb3b; box-shadow: 0 0 0 2px rgba(255, 235, 59, 0.4); } .status-indicator.inactive { background-color: #999; box-shadow: 0 0 0 2px rgba(153, 153, 153, 0.3); } .status-indicator.touch-device { background-color: #ba68c8; box-shadow: 0 0 0 2px rgba(186, 104, 200, 0.4); } .unregister-button { all: unset; display: flex; align-items: center; justify-content: center; width: 14px; height: 14px; padding: 1px; cursor: pointer; color: #999; } .unregister-button:hover { background-color: rgba(255, 107, 107, 0.1); color: #ff6b6b; } .element-name { flex-grow: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 11px; font-weight: 500; color: #e8e8e8; } .element-name.callback-active { color: #fff; font-weight: 600; } .element-name.callback-inactive { color: #999; font-weight: 500; } .reactivate-countdown { font-size: 14px; color: #ffa726; font-weight: 500; min-width: 0; white-space: nowrap; } .reactivate-countdown:empty { display: none; } :host(.not-visible) { opacity: 0.5; } .element-wrapper.not-visible { opacity: 0.5; } `],n([J({hasChanged:()=>!0})],v.prototype,"elementData",2),n([J()],v.prototype,"isActive",2),n([J()],v.prototype,"isExpanded",2),n([J()],v.prototype,"onToggle",2),n([Ct()],v.prototype,"currentDeviceStrategy",2),v=n([Et("single-element")],v);var m=class extends Tt{constructor(){super();this.hitCount={mouse:{hover:0,trajectory:0},scroll:{down:0,left:0,right:0,up:0},tab:{forwards:0,reverse:0},touch:0,viewport:0,total:0};this.elementListItems=new Map;this.noContentMessage="No Elements Registered To The Foresight Manager";this.runningCallbacks=new Set;this.expandedElementIds=new Set;this._abortController=null;this.handleSortChange=e=>{this.sortOrder=e};this.handleElementToggle=e=>{let t=new Set(this.expandedElementIds);t.has(e)?t.delete(e):t.add(e),this.expandedElementIds=t};this.sortByDocumentPosition=(e,t)=>{let i=e.element.compareDocumentPosition(t.element);return i&Node.DOCUMENT_POSITION_FOLLOWING?-1:i&Node.DOCUMENT_POSITION_PRECEDING?1:0};this.sortOrder=l.instance.devtoolsSettings.sortElementList,this.sortDropdown=[{value:"visibility",label:"Visibility",title:"Sort by Visibility",icon:pe},{value:"documentOrder",label:"Document Order",title:"Sort by Document Order",icon:he},{value:"insertionOrder",label:"Insertion Order",title:"Sort by Insertion Order",icon:me}]}_generateHitsChipTitle(e){let t=[];t.push(`Total Callback Hits: ${e.total}`),t.push("");let i=e.mouse.trajectory+e.mouse.hover,a=e.scroll.up+e.scroll.down+e.scroll.left+e.scroll.right,s=e.tab.forwards+e.tab.reverse;t.push("Desktop Strategy"),i>0?t.push(` Mouse (${i}): ${e.mouse.trajectory} trajectory, ${e.mouse.hover} hover`):t.push(" Mouse: No hits"),a>0?t.push(` Scroll (${a}): Up ${e.scroll.up}, Down ${e.scroll.down}, Left ${e.scroll.left}, Right ${e.scroll.right}`):t.push(" Scroll: No hits"),s>0?t.push(` Tab (${s}): ${e.tab.forwards} forward, ${e.tab.reverse} reverse`):t.push(" Tab: No hits"),t.push("");let d=e.touch+e.viewport;return t.push("Touch Strategy"),e.touch>0?t.push(` Touch Start: ${e.touch}`):t.push(" Touch Start: No hits"),e.viewport>0?t.push(` Viewport Enter: ${e.viewport}`):t.push(" Viewport Enter: No hits"),d===0&&i+a+s===0&&(t.push(""),t.push("Interact with registered elements to see callback statistics")),t.join(` `)}connectedCallback(){super.connectedCallback(),this._abortController=new AbortController;let{signal:e}=this._abortController;this.updateElementListFromManager(),$.instance.addEventListener("elementRegistered",t=>{this.elementListItems.set(t.elementData.element,t.elementData)},{signal:e}),$.instance.addEventListener("elementDataUpdated",t=>{this.elementListItems.get(t.elementData.element)&&(this.elementListItems.set(t.elementData.element,t.elementData),this.requestUpdate())},{signal:e}),$.instance.addEventListener("elementReactivated",t=>{this.elementListItems.get(t.elementData.element)&&(this.elementListItems.set(t.elementData.element,t.elementData),this.requestUpdate())},{signal:e}),$.instance.addEventListener("elementUnregistered",t=>{this.elementListItems.delete(t.elementData.element),this.elementListItems.size||(this.noContentMessage="No Elements Registered To The Foresight Manager"),this.runningCallbacks.delete(t.elementData.element),this.requestUpdate()},{signal:e}),$.instance.addEventListener("callbackInvoked",t=>{this.elementListItems.get(t.elementData.element)&&this.elementListItems.set(t.elementData.element,t.elementData),this.runningCallbacks.add(t.elementData.element),this.requestUpdate()},{signal:e}),$.instance.addEventListener("callbackCompleted",t=>{this.elementListItems.get(t.elementData.element)&&this.elementListItems.set(t.elementData.element,t.elementData),this.handleCallbackCompleted(t.hitType),this.runningCallbacks.delete(t.elementData.element),this.requestUpdate()},{signal:e})}disconnectedCallback(){super.disconnectedCallback(),this._abortController?.abort(),this._abortController=null}updateElementListFromManager(){this.elementListItems=new Map($.instance.registeredElements)}handleCallbackCompleted(e){switch(e.kind){case"mouse":this.hitCount.mouse[e.subType]++;break;case"tab":this.hitCount.tab[e.subType]++;break;case"scroll":this.hitCount.scroll[e.subType]++;break;case"touch":this.hitCount.touch++;break;case"viewport":this.hitCount.viewport++;break;default:}this.hitCount.total++,this.requestUpdate()}getSortedElements(){let e=Array.from(this.elementListItems.values());switch(this.sortOrder){case"insertionOrder":return e;case"documentOrder":return e.sort(this.sortByDocumentPosition);case"visibility":return e.sort((t,i)=>t.isIntersectingWithViewport!==i.isIntersectingWithViewport?t.isIntersectingWithViewport?-1:1:this.sortByDocumentPosition(t,i));default:return this.sortOrder,e}}getActiveElements(){return this.getSortedElements().filter(e=>e.callbackInfo.isCallbackActive)}getInactiveElements(){return this.getSortedElements().filter(e=>!e.callbackInfo.isCallbackActive)}render(){return B` <tab-header> <div slot="chips" class="chips-container"> <chip-element title="${this._generateHitsChipTitle(this.hitCount)}"> ${this.hitCount.total} hits </chip-element> </div> <div slot="actions"> <single-select-dropdown .dropdownOptions="${this.sortDropdown}" .selectedOptionValue="${this.sortOrder}" .onSelectionChange="${this.handleSortChange}" ></single-select-dropdown> </div> </tab-header> <tab-content .noContentMessage=${this.noContentMessage} .hasContent=${!!this.elementListItems.size} > ${this.getActiveElements().length>0?B` <div class="element-section"> <h3 class="section-header active"> Active Elements (${this.getActiveElements().length}) </h3> ${Me(this.getActiveElements(),e=>B` <single-element .elementData=${e} .isActive=${this.runningCallbacks.has(e.element)} .isExpanded=${this.expandedElementIds.has(e.id)} .onToggle=${this.handleElementToggle} > </single-element> `)} </div> `:""} ${this.getInactiveElements().length>0?B` <div class="element-section"> <h3 class="section-header inactive"> Inactive Elements (${this.getInactiveElements().length}) </h3> ${Me(this.getInactiveElements(),e=>B` <single-element .elementData=${e} .isActive=${this.runningCallbacks.has(e.element)} .isExpanded=${this.expandedElementIds.has(e.id)} .onToggle=${this.handleElementToggle} > </single-element> `)} </div> `:""} </tab-content> `}};m.styles=St` :host { display: flex; flex-direction: column; height: 100%; } .chips-container { display: flex; gap: 8px; } .element-section { margin-bottom: 16px; } .element-section:last-child { margin-bottom: 0; } .section-header { margin: 4px 0 4px 0; font-size: 12px; font-weight: 600; } .section-header.active { color: #e8e8e8; } .section-header.inactive { color: #999; } `,n([L()],m.prototype,"hitCount",2),n([L()],m.prototype,"sortDropdown",2),n([L()],m.prototype,"sortOrder",2),n([L()],m.prototype,"elementListItems",2),n([L()],m.prototype,"noContentMessage",2),n([L()],m.prototype,"runningCallbacks",2),n([L()],m.prototype,"expandedElementIds",2),m=n([Dt("element-tab")],m);import{css as Mt,html as Le,LitElement as Lt}from"lit";import{customElement as $t,property as _t}from"lit/decorators.js";var A=class extends Lt{constructor(){super(...arguments);this.activeTab="settings";this.tabs=["settings","elements","logs"]}_handleTabClick(e){this.dispatchEvent(new CustomEvent("tab-change",{detail:{tab:e},bubbles:!0,composed:!0}))}render(){return Le` <div class="tab-selector-wrapper"> ${this.tabs.map(e=>Le` <button class="tab-button ${this.activeTab===e?"active":""}" @click="${()=>this._handleTabClick(e)}" data-tab="${e}" > ${e.charAt(0).toUpperCase()+e.slice(1)} </button> `)} </div> `}};A.styles=Mt` .tab-selector-wrapper { border-bottom: 2px solid #444; margin-top: 12px; display: flex; justify-content: space-evenly; width: 100%; } .tab-button { background: none; border: none; color: #9e9e9e; flex: 1; padding: 8px; cursor: pointer; border-bottom: 2px solid transparent; transition: all 0.2s ease; font-size: 13px; font-weight: 500; text-align: center; } .tab-button:hover { color: #b0c4de; background-color: rgba(176, 196, 222, 0.1); } .tab-button.active { color: #b0c4de; border-bottom-color: #b0c4de; } `,n([_t({type:String})],A.prototype,"activeTab",2),A=n([$t("tab-selector")],A);import{ForesightManager as G}from"js.foresight";import{LitElement as Vt,css as Rt,html as X}from"lit";import{customElement as Ft,property as zt,state as j}from"lit/decorators.js";import{map as Ht}from"lit/directives/map.js";function _e(o,r){let e={};o.eventListeners.forEach((i,a)=>{e[a]=i.length});let t=[];return o.registeredElements.forEach((i,a)=>{let{element:s,...d}=i;t.push({...d,elementInfo:`${a.id?`#${a.id}`:""}${a.className?`.${a.className.replace(/\s+/g,".")}`:""}`})}),{type:"managerDataPayload",warning:"this is a lot easier to view in the console",logId:r,globalCallbackHits:o.globalCallbackHits,localizedTimestamp:new Date().toLocaleTimeString(),eventListenerCount:e,managerSettings:o.globalSettings,registeredElements:t,summary:`${t.length} elements, ${Object.values(e).flat().length} listeners, ${o.globalCallbackHits.total} hits`}}function Ie(o,r){try{switch(o.type){case"elementRegistered":return{type:"elementRegistered",name:o.elementData.name,id:o.elementData.element.id||"",callbackInfo:o.elementData.callbackInfo,hitslop:o.elementData.elementBounds.hitSlop,localizedTimestamp:new Date(o.timestamp).toLocaleTimeString(),meta:o.elementData.meta,logId:r,summary:o.elementData.registerCount===1?o.elementData.name:`${o.elementData.name} - ${$e(o.elementData.registerCount)} time`};case"elementReactivated":return{type:"elementReactivated",name:o.elementData.name,id:o.elementData.element.id||"",callbackInfo:o.elementData.callbackInfo,localizedTimestamp:new Date(o.timestamp).toLocaleTimeString(),meta:o.elementData.meta,logId:r,summary:o.elementData.registerCount===1?o.elementData.name:`${o.elementData.name} - ${$e(o.elementData.registerCount)} time`};case"elementUnregistered":return{type:"elementUnregistered",name:o.elementData.name,id:o.elementData.element.id||"",meta:o.elementData.meta,callbackInfo:o.elementData.callbackInfo,wasLastRegisteredElement:o.wasLastRegisteredElement,localizedTimestamp:new Date(o.timestamp).toLocaleTimeString(),logId:r,summary:`${o.elementData.name} - ${o.unregisterReason}`};case"elementDataUpdated":return{type:"elementDataUpdated",name:o.elementData.name,updatedProps:o.updatedProps||[],callbackInfo:o.elementData.callbackInfo,isIntersecting:o.elementData.isIntersectingWithViewport,meta:o.elementData.meta,localizedTimestamp:new Date().toLocaleTimeString(),logId:r,summary:`${o.elementData.name} - ${o.updatedProps.toString()}`};case"callbackInvoked":return{type:"callbackInvoked",name:o.elementData.name,hitType:o.hitType,callbackInfo:o.elementData.callbackInfo,meta:o.elementData.meta,localizedTimestamp:new Date(o.timestamp).toLocaleTimeString(),logId:r,summary:`${o.elementData.name} - ${o.hitType.kind}`};case"callbackCompleted":{let e=It(o.elementData.callbackInfo.lastCallbackRuntime||0);return{type:"callbackCompleted",name:o.elementData.name,hitType:o.hitType,callbackInfo:o.elementData.callbackInfo,meta:o.elementData.meta,wasLastActiveElement:o.wasLastActiveElement,elapsed:e,localizedTimestamp:new Date(o.timestamp).toLocaleTimeString(),logId:r,status:o.elementData.callbackInfo.lastCallbackStatus,errorMessage:o.elementData.callbackInfo.lastCallbackErrorMessage,summary:`${o.elementData.name} - ${e}`}}case"mouseTrajectoryUpdate":return{type:"mouseTrajectoryUpdate",currentPoint:o.trajectoryPositions?.currentPoint,predictedPoint:o.trajectoryPositions?.predictedPoint,positionCount:o.trajectoryPositions?.positions?.length||0,mousePredictionEnabled:o.predictionEnabled,localizedTimestamp:new Date().toLocaleTimeString(),logId:r,summary:""};case"scrollTrajectoryUpdate":return{type:"scrollTrajectoryUpdate",currentPoint:o.currentPoint,predictedPoint:o.predictedPoint,scrollDirection:o.scrollDirection,localizedTimestamp:new Date().toLocaleTimeString(),logId:r,summary:o.scrollDirection};case"managerSettingsChanged":return{type:"managerSettingsChanged",globalSettings:o.managerData?.globalSettings||{},settingsChanged:o.updatedSettings,localizedTimestamp:new Date(o.timestamp).toLocaleTimeString(),logId:r,summary:o.updatedSettings.map(e=>e.setting).join(", ")};case"deviceStrategyChanged":return{type:"deviceStrategyChanged",oldStrategy:o.oldStrategy,newStrategy:o.newStrategy,localizedTimestamp:new Date(o.timestamp).toLocaleTimeString(),logId:r,summary:`${o.oldStrategy} \u2192 ${o.newStrategy}`};default:return{type:"serializationError",error:"Failed to serialize event data",errorMessage:JSON.stringify(o),localizedTimestamp:new Date().toLocaleTimeString(),logId:r,summary:""}}}catch(e){return{type:"serializationError",error:"Failed to serialize event data",localizedTimestamp:new Date().toLocaleTimeString(),errorMessage:e instanceof Error?e.message:String(e),logId:r,summary:""}}}function It(o){return`${(o/1e3).toFixed(4)} s`}function $e(o){let r=["th","st","nd","rd"],e=o%100;return o+(r[(e-20)%10]||r[e]||r[0])}import{html as Oe,css as Ot}from"lit";import{customElement as Pt,property as Pe}from"lit/decorators.js";var _=class extends M{constructor(){super(...arguments);this.selectedValues=[]}_handleOptionClick(e){let t=this.selectedValues.includes(e.value);t?this.selectedValues=this.selectedValues.filter(a=>a!==e.value):this.selectedValues=[...this.selectedValues,e.value];let i=!t;this.onSelectionChange?.(e.value,i)}_getTriggerIcon(){return h}_isOptionSelected(e){return this.selectedValues.includes(e.value)}_getTriggerTitle(){let e=this.selectedValues.length;return e===0?"No items selected":e===1?"1 item selected":`${e} items selected`}_getTriggerLabel(){return`Filter options: ${this.selectedValues.length} selected`}render(){let e=`trigger-button ${this.isDropdownOpen?"active":""}`,t=`dropdown-menu ${this.isDropdownOpen?"active":""}`;return Oe` <div class="dropdown-container"> <button class="${e}" title="${this._getTriggerTitle()}" @click="${this._toggleDropdown}" aria-haspopup="true" aria-expanded="${this.isDropdownOpen}" aria-controls="dropdown-menu" aria-label="${this._getTriggerLabel()}" > ${this._getTriggerIcon()} <span class="selected-count">${this.selectedValues.length}</span> <svg class="arrow-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" > <polyline points="6 9 12 15 18 9"></polyline> </svg> </button> <div class="${t}" id="dropdown-menu" role="menu"> ${this.dropdownOptions.map(i=>Oe` <button value="${i.value}" title="${i.title}" class="${this._isOptionSelected(i)?"active":""}" @click="${()=>this._handleOptionClick(i)}" role="menuitem" > ${i.label} </button> `)} </div> </div> `}};_.styles=[...M.styles,Ot` .dropdown-menu button.active::after { content: "✓"; position: absolute; right: 8px; top: 50%; transform: translateY(-50%); color: #b0c4de; font-weight: bold; } .selected-count { font-size: 10px; color: #b0c4de; margin-left: 2px; } `],n([Pe({type:Array})],_.prototype,"selectedValues",2),n([Pe()],_.prototype,"onSelectionChange",2),_=n([Pt("multi-select-dropdown")],_);import{LitElement as Ut,html as Nt,css as At}from"lit";import{customElement as jt,property as ie}from"lit/decorators.js";var C=class extends Ut{constructor(e){super();this.isExpanded=!1;this.log=e}updated(e){if(e.has("log")&&this.log){let t=this.log,i=t.type==="callbackCompleted"&&"status"in t&&t.status==="error",a=i?"#f44336":this.getLogTypeColor(t.type),s=i?"rgba(244, 67, 54, 0.1)":"transparent";this.style.setProperty("--log-color",a),this.style.setProperty("--log-background-color",s)}}serializeLogDataWithoutSummary(e){let{summary:t,...i}=e;return JSON.stringify(i,null,2)}getLogTypeColor(e){return{elementRegistered:"#2196f3",elementReactivated:"#ff9800",callbackInvoked:"#00bcd4",callbackCompleted:"#4caf50",elementDataUpdated:"#ffc107",elementUnregistered:"#ff9800",managerSettingsChanged:"#f44336",mouseTrajectoryUpdate:"#78909c",scrollTrajectoryUpdate:"#607d8b",deviceStrategyChanged:"#9c27b0"}[e]||"#555"}getEventDisplayName(e){return{elementRegistered:"Registered",elementReactivated:"Reactivated",el