import{html as e,Directives as t,render as o}from"../../third_party/lit-html/lit-html.js";import{ResourceUtils as s}from"../../bindings/bindings.js";const r=t=>e`${t}`;var i=Object.freeze({__proto__:null,primitiveRenderer:r,codeBlockRenderer:t=>e`<code>${t}</code>`});const l=new Set(["ArrowUp","ArrowDown","ArrowLeft","ArrowRight"]);function n(e){return l.has(e)}function a(e,t){const o=e.cells.find((e=>e.columnId===t));if(void 0===o)throw new Error(`Found a row that was missing an entry for column ${t}.`);return o}function c(e){return e.renderer?e.renderer(e.value):r(e.value)}function d(e,t){const o=e.filter((e=>e.visible)).reduce(((e,t)=>e+t.widthWeighting),0),s=e.find((e=>e.id===t));if(!s)throw new Error("Could not find column with ID "+t);if(s.widthWeighting<1)throw new Error(`Error with column ${t}: width weightings must be >= 1.`);return s.visible?Math.round(s.widthWeighting/o*100):0}function h(e){const{key:t,currentFocusedCell:o,columns:s,rows:r}=e,[i,l]=o;switch(t){case"ArrowLeft":{if(i===s.findIndex((e=>e.visible)))return[i,l];let e=i;for(let t=e-1;t>=0;t--){if(s[t].visible){e=t;break}}return[e,l]}case"ArrowRight":{let e=i;for(let t=e+1;t<s.length;t++){if(s[t].visible){e=t;break}}return[e,l]}case"ArrowUp":{const e=s.some((e=>!0===e.sortable))?0:1;if(l===e)return[i,l];let t=l;for(let o=l-1;o>=e;o--){if(0===o){t=0;break}if(!r[o-1].hidden){t=o;break}}return[i,t]}case"ArrowDown":{if(0===l){const e=r.findIndex((e=>!e.hidden));return e>-1?[i,e+1]:[i,l]}let e=l;for(let t=e+1;t<r.length+1;t++){if(!r[t-1].hidden){e=t;break}}return[i,e]}}}const u=e=>{const{columns:t,rows:o}=e,s=t.some((e=>!0===e.sortable))?0:o.findIndex((e=>!e.hidden))+1;return[t.findIndex((e=>e.visible)),s]};var f=Object.freeze({__proto__:null,ARROW_KEYS:l,keyIsArrowKey:n,getRowEntryForColumnId:a,renderCellValue:c,calculateColumnWidthPercentageFromWeighting:d,handleArrowKeyNavigation:h,calculateFirstFocusableCell:u});class m extends Event{constructor(e,t){super("column-header-click"),this.data={column:e,columnIndex:t}}}class w extends Event{constructor(e,t){super("cell-focused"),this.data={cell:e,row:t}}}const b=new Set([" ","Enter"]);class p extends HTMLElement{constructor(){super(...arguments),this.shadow=this.attachShadow({mode:"open"}),this.columns=[],this.rows=[],this.sortState=null,this.focusableCell=[0,1],this.hasRenderedAtLeastOnce=!1}get data(){return{columns:this.columns,rows:this.rows,activeSort:this.sortState}}set data(e){if(this.columns=e.columns,this.rows=e.rows,this.sortState=e.activeSort,this.hasRenderedAtLeastOnce||(this.focusableCell=u({columns:this.columns,rows:this.rows})),this.hasRenderedAtLeastOnce){const[e,t]=this.focusableCell,o=e>this.columns.length,s=t>this.rows.length;this.focusableCell=o||s?[o?this.columns.length:e,s?this.rows.length:t]:u({columns:this.columns,rows:this.rows})}this.render()}scrollToBottomIfRequired(){if(!1===this.hasRenderedAtLeastOnce)return;const e=this.getCurrentlyFocusableCell();if(e&&e===this.shadow.activeElement)return;const t=this.shadow.querySelector("tbody tr:not(.hidden):last-child");t&&t.scrollIntoView()}getCurrentlyFocusableCell(){const[e,t]=this.focusableCell;return this.shadow.querySelector(`[data-row-index="${t}"][data-col-index="${e}"]`)}focusCell([e,t]){const[o,s]=this.focusableCell;o===e&&s===t||(this.focusableCell=[e,t],this.render());const r=this.getCurrentlyFocusableCell();if(!r)throw new Error("Unexpected error: could not find cell marked as focusable");r!==this.shadow.activeElement&&r.focus()}onTableKeyDown(e){const t=e.key;if(b.has(t)){const e=this.getCurrentlyFocusableCell(),[t,o]=this.focusableCell,s=this.columns[t];e&&0===o&&s&&s.sortable&&this.onColumnHeaderClick(s,t)}if(!n(t))return;const o=h({key:t,currentFocusedCell:this.focusableCell,columns:this.columns,rows:this.rows});this.focusCell(o)}onColumnHeaderClick(e,t){this.dispatchEvent(new m(e,t))}ariaSortForHeader(e){return!e.sortable||this.sortState&&this.sortState.columnId===e.id?this.sortState&&this.sortState.columnId===e.id?"ASC"===this.sortState.direction?"ascending":"descending":void 0:"none"}renderFillerRow(){const o=this.columns.filter((e=>e.visible)).map(((o,s)=>{const r=t.classMap({firstVisibleColumn:0===s});return e`<td tabindex="-1" class=${r}></td>`}));return e`<tr tabindex="-1" class="filler-row">${o}</tr>`}render(){const s=this.columns.findIndex((e=>e.visible)),r=this.columns.some((e=>!0===e.sortable));o(e`
    <style>
      :host {
        --table-divider-color: #aaa;
        --toolbar-bg-color: #f3f3f3;
        --selected-row-color: rgb(212, 212, 212);
        --selection-bg-color: #1a73e8;

        height: 100%;
        display: block;
      }
      /* Ensure that vertically we don't overflow */
      .wrapping-container {
        overflow-y: scroll;
        /* Use max-height instead of height to ensure that the
           table does not use more space than necessary. */
        height: 100%;
        position: relative;
      }

      table {
        border-spacing: 0;
        width: 100%;
        height: 100%;
        /* To make sure that we properly hide overflowing text
           when horizontal space is too narrow. */
        table-layout: fixed;
      }

      tr {
        outline: none;
      }


      tbody tr.selected {
        background-color: var(--selected-row-color);
      }

      table:focus tr.selected {
        background-color: var(--selection-bg-color)
      }

      td, th {
        padding: 1px 4px;
        /* Divider between each cell, except the first one (see below) */
        border-left: 1px solid var(--table-divider-color);
        line-height: 18px;
        height: 18px;
        user-select: text;
        /* Ensure that text properly cuts off if horizontal space is too narrow */
        white-space: nowrap;
        text-overflow: ellipsis;
        overflow: hidden;
      }
      /* There is no divider before the first cell */
      td.firstVisibleColumn, th.firstVisibleColumn {
        border-left: none;
      }

      th {
        font-weight: normal;
        text-align: left;
        border-bottom: 1px solid var(--table-divider-color);
        position: sticky;
        top: 0;
        z-index: 2;
        background-color: var(--toolbar-bg-color);
      }

      .hidden {
        display: none;
      }

      .filler-row {
        /**
        * The filler row is only there to stylistically fill grid lines down to the
        * bottom, we don't want users to be able to focus into it (it's got tabIndex
        * of -1) nor should they be able to click into it.
        */
        pointer-events: none;
      }

      .filler-row td {
        /* By making the filler row cells 100% they take up any extra height,
         * leaving the cells with content to be the regular height, and the
         * final filler row to be as high as it needs to be to fill the empty
         * space.
         */
        height: 100%;
      }

      [aria-sort]:hover {
        cursor: pointer;
      }

      [aria-sort="descending"]::after {
        content: " ";
        border-left: 0.3em solid transparent;
        border-right: 0.3em solid transparent;
        border-top: 0.3em solid black;
        position: absolute;
        right: 0.5em;
        top: 0.6em;
      }
      [aria-sort="ascending"]::after {
        content: " ";
        border-bottom: 0.3em solid black;
        border-left: 0.3em solid transparent;
        border-right: 0.3em solid transparent;
        position: absolute;
        right: 0.5em;
        top: 0.6em;
      }
    </style>
    <div class="wrapping-container">
      <table
        aria-rowcount=${this.rows.length}
        aria-colcount=${this.columns.length}
        @keydown=${this.onTableKeyDown}
      >
        <colgroup>
          ${this.columns.filter((e=>e.visible)).map((t=>{const o=d(this.columns,t.id);return e`<col style=${`width: ${o}%`}>`}))}
        </colgroup>
        <thead>
          <tr>
            ${this.columns.map(((o,i)=>{const l=t.classMap({hidden:!o.visible,firstVisibleColumn:i===s}),n=r&&i===this.focusableCell[0]&&0===this.focusableCell[1];return e`<th class=${l}
                data-grid-header-cell=${o.id}
                @click=${()=>{this.focusCell([i,0]),this.onColumnHeaderClick(o,i)}}
                title=${o.title}
                aria-sort=${t.ifDefined(this.ariaSortForHeader(o))}
                aria-colindex=${i+1}
                data-row-index='0'
                data-col-index=${i}
                tabindex=${t.ifDefined(r?n?"0":"-1":void 0)}
              >${o.title}</th>`}))}
          </tr>
        </thead>
        <tbody>
          ${this.rows.map(((o,r)=>{const i=this.getCurrentlyFocusableCell(),[,l]=this.focusableCell,n=r+1,d=!!i&&(i===document.activeElement&&n===l),h=t.classMap({selected:d,hidden:!0===o.hidden});return e`
              <tr
                aria-rowindex=${r+1}
                class=${h}
              >${this.columns.map(((r,i)=>{const l=a(o,r.id),d=t.classMap({hidden:!r.visible,firstVisibleColumn:i===s}),h=i===this.focusableCell[0]&&n===this.focusableCell[1],u=c(l);return e`<td
                  class=${d}
                  title=${l.title||String(l.value)}
                  tabindex=${h?"0":"-1"}
                  aria-colindex=${i+1}
                  data-row-index=${n}
                  data-col-index=${i}
                  data-grid-value-cell-for-column=${r.id}
                  @focus=${()=>{this.dispatchEvent(new w(l,o))}}
                  @click=${()=>{this.focusCell([i,n])}}
                >${u}</td>`}))}
            `}))}
         ${this.renderFillerRow()}
        </tbody>
      </table>
    </div>
    `,this.shadow,{eventContext:this}),this.scrollToBottomIfRequired(),this.hasRenderedAtLeastOnce=!0}}customElements.define("devtools-data-grid",p);var g=Object.freeze({__proto__:null,ColumnHeaderClickEvent:m,BodyCellFocusedEvent:w,DataGrid:p});class v extends HTMLElement{constructor(){super(...arguments),this.shadow=this.attachShadow({mode:"open"}),this.hasRenderedAtLeastOnce=!1,this.columns=[],this.rows=[],this.originalColumns=[],this.originalRows=[],this.sortState=null,this.filters=[]}get data(){return{columns:this.originalColumns,rows:this.originalRows,filters:this.filters}}set data(e){this.originalColumns=e.columns,this.originalRows=e.rows,this.filters=e.filters||[],this.columns=[...this.originalColumns],this.rows=this.cloneAndFilterRows(e.rows,this.filters),!this.hasRenderedAtLeastOnce&&e.initialSort&&(this.sortState=e.initialSort,this.sortRows(this.sortState)),this.render()}testRowWithFilter(e,t){let o=!1;const{key:s,text:r,negative:i,regex:l}=t;let n;if(s){const t=a(e,s);n=JSON.stringify(t.value).toLowerCase()}else n=JSON.stringify(e.cells.map((e=>e.value))).toLowerCase();return l?o=l.test(n):r&&(o=n.includes(r.toLowerCase())),i?!o:o}cloneAndFilterRows(e,t){return 0===t.length?[...e]:e.map((e=>{let o=!0;for(const s of t){if(!this.testRowWithFilter(e,s)){o=!1;break}}return{...e,hidden:!o}}))}sortRows(e){const{columnId:t,direction:o}=e;this.rows.sort(((e,s)=>{const r=a(e,t),i=a(s,t),l="number"==typeof r.value?r.value:String(r.value).toUpperCase(),n="number"==typeof i.value?i.value:String(i.value).toUpperCase();return l<n?"ASC"===o?-1:1:l>n?"ASC"===o?1:-1:0})),this.render()}onColumnHeaderClick(e){const{column:t}=e.data;if(this.sortState&&this.sortState.columnId===t.id){const{columnId:e,direction:t}=this.sortState;this.sortState="DESC"===t?null:{columnId:e,direction:"DESC"}}else this.sortState={columnId:t.id,direction:"ASC"};this.sortState?this.sortRows(this.sortState):(this.rows=[...this.originalRows],this.render())}render(){o(e`
      <style>
        :host {
          display: block;
          height: 100%;
          overflow: hidden;
        }
      </style>
      <devtools-data-grid .data=${{columns:this.columns,rows:this.rows,activeSort:this.sortState}}
        @column-header-click=${this.onColumnHeaderClick}
      ></devtools-data-grid>
    `,this.shadow,{eventContext:this}),this.hasRenderedAtLeastOnce=!0}}customElements.define("devtools-data-grid-controller",v);var x=Object.freeze({__proto__:null,DataGridController:v});class C extends Event{constructor(e){super("linkifier-activated",{bubbles:!0,composed:!0}),this.data=e}}class y extends HTMLElement{constructor(){super(...arguments),this.shadow=this.attachShadow({mode:"open"}),this.url=""}set data(e){this.url=e.url,this.lineNumber=e.lineNumber,this.columnNumber=e.columnNumber,this.render()}onLinkActivation(e){e.preventDefault();const t=new C({url:this.url,lineNumber:this.lineNumber,columnNumber:this.columnNumber});this.dispatchEvent(t)}render(){if(!this.url)throw new Error("Cannot construct a Linkifier without providing a valid string URL.");return o(e`
      <style>
         .link:link, .link:visited {
            color: var(--color-link);
            text-decoration: underline;
            cursor: pointer;
         }
      </style>
      <a class="link" href=${this.url} @click=${this.onLinkActivation}>${function(e,t){if(e){let o=""+s.displayNameForURL(e);return void 0!==t&&(o+=":"+(t+1)),o}throw new Error("New linkifier component error: don't know how to generate link text for given arguments")}(this.url,this.lineNumber)}</a>
    `,this.shadow,{eventContext:this})}}customElements.define("devtools-linkifier",y);var k=Object.freeze({__proto__:null,LinkifierClick:C,Linkifier:y});class S extends HTMLElement{constructor(){super(...arguments),this.shadow=this.attachShadow({mode:"open"})}connectedCallback(){this.render()}render(){o(e`
      <style>
        .content {
          background-color:  var(--color-background);
          overflow: auto;
        }
      </style>

      <div class="content">
        <slot></slot>
      </div>
    `,this.shadow)}}class $ extends HTMLElement{constructor(){super(...arguments),this.shadow=this.attachShadow({mode:"open"}),this.sectionTitle=""}set data({sectionTitle:e}){this.sectionTitle=e,this.render()}render(){o(e`
      <style>
        .section {
          display: flex;
          padding: 12px;
          border-bottom: 1px solid var(--color-details-hairline);
          flex-direction: column;
        }

        .header {
          margin-left: 18px;
          display: flex;
          flex-direction: row;
          align-items: center;
          flex: auto;
          text-overflow: ellipsis;
          overflow: hidden;
          font-weight: bold;
          color: var(--color-text-primary);
        }
      </style>
      <div class="section">
        <div class="header">${this.sectionTitle}</div>
        <dl><slot></slot></dl>
      </div>
    `,this.shadow)}}class E extends HTMLElement{constructor(){super(...arguments),this.shadow=this.attachShadow({mode:"open"})}connectedCallback(){this.render()}render(){o(e`
      <style>
        :host {
          display: flex;
          line-height: 28px;
          margin: 8px 0px 0px 0px;
        }

        .name {
          color: var(--color-text-secondary);
          flex: 0 0 var(--name-column-width, 128px);
          padding: 0 6px;
          text-align: right;
          white-space: pre;
        }

        .value {
          color: var(--color-text-primary);
          flex: auto;
          padding: 0 6px;
          white-space: pre;
        }
      </style>
      <dt class="name"><slot name="name"></slot></dt>
      <dd class="value"><slot name="value"></slot></dd>
    `,this.shadow)}}customElements.define("devtools-report",S),customElements.define("devtools-report-section",$),customElements.define("devtools-report-row",E);var R=Object.freeze({__proto__:null,Report:S,ReportSection:$,ReportRow:E});export{g as DataGrid,x as DataGridController,i as DataGridRenderers,f as DataGridUtils,k as Linkifier,R as ReportView};
