import{html as e,Directives as t,render as o}from"../../third_party/lit-html/lit-html.js";const r=t=>{const o=String(t);return e`${o}`};var s=Object.freeze({__proto__:null,stringRenderer:r,codeBlockRenderer:t=>e`<code>${t}</code>`});const i=new Set(["ArrowUp","ArrowDown","ArrowLeft","ArrowRight"]);function n(e){return i.has(e)}function l(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 a(e){return e.renderer?e.renderer(e.value):r(e.value)}function d(e){return e.title}function c(e,t){const o=e.filter((e=>!e.hidden)).reduce(((e,t)=>e+t.widthWeighting),0),r=e.find((e=>e.id===t));if(!r)throw new Error("Could not find column with ID "+t);if(r.widthWeighting<1)throw new Error(`Error with column ${t}: width weightings must be >= 1.`);return r.hidden?0:Math.round(r.widthWeighting/o*100)}function h(e){const{key:t,currentFocusedCell:o,columns:r,rows:s}=e,[i,n]=o;switch(t){case"ArrowLeft":{if(i===r.findIndex((e=>!e.hidden)))return[i,n];let e=i;for(let t=e-1;t>=0;t--){if(!r[t].hidden){e=t;break}}return[e,n]}case"ArrowRight":{let e=i;for(let t=e+1;t<r.length;t++){if(!r[t].hidden){e=t;break}}return[e,n]}case"ArrowUp":{const e=r.some((e=>!0===e.sortable))?0:1;if(n===e)return[i,n];let t=n;for(let o=n-1;o>=e;o--){if(0===o){t=0;break}if(!s[o-1].hidden){t=o;break}}return[i,t]}case"ArrowDown":{if(0===n){const e=s.findIndex((e=>!e.hidden));return e>-1?[i,e+1]:[i,n]}let e=n;for(let t=e+1;t<s.length+1;t++){if(!s[t-1].hidden){e=t;break}}return[i,e]}}}const u=e=>{const{columns:t,rows:o}=e,r=t.some((e=>!0===e.sortable))?0:o.findIndex((e=>!e.hidden))+1;return[t.findIndex((e=>!e.hidden)),r]};var f=Object.freeze({__proto__:null,ARROW_KEYS:i,keyIsArrowKey:n,getRowEntryForColumnId:l,renderCellValue:a,stringValueForCell:d,calculateColumnWidthPercentageFromWeighting:c,handleArrowKeyNavigation:h,calculateFirstFocusableCell:u});class w extends Event{constructor(e,t){super("column-header-click"),this.data={column:e,columnIndex:t}}}class m extends Event{constructor(e,t){super("cell-focused"),this.data={cell:e,row:t}}}const b=new Set([" ","Enter"]);class g 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,r=t>this.rows.length;this.focusableCell=o||r?[o?this.columns.length:e,r?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,r]=this.focusableCell;o===e&&r===t||(this.focusableCell=[e,t],this.render());const s=this.getCurrentlyFocusableCell();if(!s)throw new Error("Unexpected error: could not find cell marked as focusable");s!==this.shadow.activeElement&&s.focus()}onTableKeyDown(e){const t=e.key;if(b.has(t)){const e=this.getCurrentlyFocusableCell(),[t,o]=this.focusableCell,r=this.columns[t];e&&0===o&&r&&r.sortable&&this.onColumnHeaderClick(r,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 w(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.hidden)).map(((o,r)=>{const s=t.classMap({firstVisibleColumn:0===r});return e`<td tabindex="-1" class=${s}></td>`}));return e`<tr tabindex="-1" class="filler-row">${o}</tr>`}render(){const r=this.columns.findIndex((e=>!e.hidden)),s=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 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.hidden)).map((t=>{const o=c(this.columns,t.id);return e`<col style=${`width: ${o}%`}>`}))}
        </colgroup>
        <thead>
          <tr>
            ${this.columns.map(((o,i)=>{const n=t.classMap({hidden:!0===o.hidden,firstVisibleColumn:i===r}),l=s&&i===this.focusableCell[0]&&0===this.focusableCell[1];return e`<th class=${n}
                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(s?l?"0":"-1":void 0)}
              >${o.title}</th>`}))}
          </tr>
        </thead>
        <tbody>
          ${this.rows.map(((o,s)=>{const i=this.getCurrentlyFocusableCell(),[,n]=this.focusableCell,c=s+1,h=!!i&&(i===document.activeElement&&c===n),u=t.classMap({selected:h,hidden:!0===o.hidden});return e`
              <tr
                aria-rowindex=${s+1}
                class=${u}
              >${this.columns.map(((s,i)=>{const n=l(o,s.id),h=t.classMap({hidden:!0===s.hidden,firstVisibleColumn:i===r}),u=i===this.focusableCell[0]&&c===this.focusableCell[1],f=d(n),w=a(n);return e`<td
                  class=${h}
                  title=${f}
                  tabindex=${u?"0":"-1"}
                  aria-colindex=${i+1}
                  data-row-index=${c}
                  data-col-index=${i}
                  data-grid-value-cell-for-column=${s.id}
                  @focus=${()=>{this.dispatchEvent(new m(n,o))}}
                  @click=${()=>{this.focusCell([i,c])}}
                >${w}</td>`}))}
            `}))}
         ${this.renderFillerRow()}
        </tbody>
      </table>
    </div>
    `,this.shadow,{eventContext:this}),this.scrollToBottomIfRequired(),this.hasRenderedAtLeastOnce=!0}}customElements.define("devtools-data-grid",g);var p=Object.freeze({__proto__:null,ColumnHeaderClickEvent:w,BodyCellFocusedEvent:m,DataGrid:g});class C 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}get data(){return{columns:this.originalColumns,rows:this.originalRows,filterText:this.filterText}}set data(e){this.originalColumns=e.columns,this.originalRows=e.rows,this.filterText=e.filterText,this.columns=[...this.originalColumns],this.rows=this.cloneAndFilterRows(e.rows,this.filterText),!this.hasRenderedAtLeastOnce&&e.initialSort&&(this.sortState=e.initialSort,this.sortRows(this.sortState)),this.render()}cloneAndFilterRows(e,t){return t?e.map((e=>{const o=e.cells.some((e=>d(e).toLowerCase().includes(t.toLowerCase())));return{...e,hidden:!o}})):[...e]}sortRows(e){const{columnId:t,direction:o}=e;this.rows.sort(((e,r)=>{const s=l(e,t),i=l(r,t),n=d(s).toUpperCase(),a=d(i).toUpperCase();return n<a?"ASC"===o?-1:1:n>a?"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",C);var v=Object.freeze({__proto__:null,DataGridController:C});export{p as DataGrid,v as DataGridController,s as DataGridRenderers,f as DataGridUtils};
