@internetarchive/ads-table 1.1.0 → 1.2.3

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.
package/dist/ads-table.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { __decorate } from "tslib";
2
2
  // interface class for a Lit component class that contains table data
3
3
  import { css, html, LitElement, } from "lit";
4
- import { property, state, query, queryAll, customElement, } from "lit/decorators.js";
4
+ import { property, state, query, customElement } from "lit/decorators.js";
5
5
  import { EventHelpers } from "@internetarchive/ads-library";
6
6
  import { getUserOS, UserOperatingSystem } from "@internetarchive/ads-library";
7
7
  export class AdsTable extends LitElement {
@@ -17,9 +17,6 @@ export class AdsTable extends LitElement {
17
17
  this.selectedRowIds = [];
18
18
  this.isLoading = false;
19
19
  }
20
- getTableRowElementById(id) {
21
- return Array.from(this.tableRows || []).find((row) => row.id === `row-${id}`);
22
- }
23
20
  updated(changedProperties) {
24
21
  super.updated(changedProperties);
25
22
  if (changedProperties.has("selectedRowIds")) {
@@ -248,7 +245,21 @@ export class AdsTable extends LitElement {
248
245
  return this.onUpDownArrowKey(event);
249
246
  }
250
247
  }
251
- // listener applies when column has focus
248
+ // listener applies only after table has focus
249
+ onTableKeyDown(event) {
250
+ if (this.disableKeyboardNavigation) {
251
+ return;
252
+ }
253
+ // on esc or delete, emit an event
254
+ switch (event.key) {
255
+ case "Escape":
256
+ return this.emitEvent("table-navigate-back");
257
+ case "Backspace":
258
+ return this.emitEvent("table-navigate-back");
259
+ }
260
+ }
261
+ // listener applies when column has focus - does nothing since
262
+ // column header cannot get focus right now.
252
263
  onColumnKeyDown(event, column) {
253
264
  if (this.disableKeyboardNavigation) {
254
265
  return;
@@ -277,21 +288,22 @@ export class AdsTable extends LitElement {
277
288
  }
278
289
  }
279
290
  }
280
- onUpDownArrowKey(event) {
291
+ focusTableElement() {
281
292
  var _a;
293
+ (_a = this.tableElement) === null || _a === void 0 ? void 0 : _a.focus();
294
+ }
295
+ onUpDownArrowKey(event) {
282
296
  if (this.rows.length === 0) {
283
297
  // there are no rows to navigate or select with arrows. avoids array out of bounds.
284
298
  return;
285
299
  }
300
+ // focus the main table element with each arrow key press
301
+ this.focusTableElement();
286
302
  const indexOffset = event.key === "ArrowUp" ? -1 : 1;
287
303
  const newSelectedRowIndex = this.constrainIndex(this.indexOfLastSelectedRow + indexOffset);
288
304
  const newSelectedRowId = this.rows[newSelectedRowIndex].id;
289
- if (event.shiftKey) {
290
- // - focus and (maybe) select and focus the prev or next, if it exists
291
- this.groupRowSelect(newSelectedRowIndex);
292
- }
293
- else if (this.selectedRowIds.length === 0) {
294
- // select the first row if none are selected
305
+ if (this.selectedRowIds.length === 0) {
306
+ // if none are selected, select the first row
295
307
  const firstRowId = this.rows[0] ? this.rows[0].id : undefined;
296
308
  if (firstRowId) {
297
309
  this.selectedRowIds = [firstRowId];
@@ -301,8 +313,6 @@ export class AdsTable extends LitElement {
301
313
  // offset in the proper direction of the arrow
302
314
  this.selectedRowIds = [newSelectedRowId];
303
315
  }
304
- // always try to focus the next element in the direction of the arrow if you can
305
- (_a = this.getTableRowElementById(newSelectedRowId)) === null || _a === void 0 ? void 0 : _a.focus();
306
316
  }
307
317
  // ensures index values are kept to the closest in-bounds index
308
318
  constrainIndex(index) {
@@ -315,16 +325,22 @@ export class AdsTable extends LitElement {
315
325
  }
316
326
  render() {
317
327
  return html `
318
- <table id="main-table">
328
+ <table
329
+ tabindex="0"
330
+ role="treegrid"
331
+ id="main-table"
332
+ @keydown=${(e) => this.onTableKeyDown(e)}
333
+ >
319
334
  <thead>
320
- <tr>
335
+ <tr role="row">
321
336
  ${this.visibleColumns.map((column) => html `
322
337
  <th
338
+ role="gridcell"
339
+ aria-label=${column.label}
323
340
  @click=${() => this.onColumnClick(column)}
324
341
  @keydown=${(e) => this.onColumnKeyDown(e, column)}
325
342
  class=${column.dataType.compare ? "sortable" : ""}
326
343
  style=${`flex: ${column.flexRatio}`}
327
- tabindex="0"
328
344
  >
329
345
  ${column.label}
330
346
  ${column.dataType.compare
@@ -338,31 +354,35 @@ export class AdsTable extends LitElement {
338
354
  ${!this.isLoading
339
355
  ? this.sortedRows.map((row, index) => html `
340
356
  <tr
357
+ role="row"
341
358
  @click=${(e) => this.onRowClick(e, row, index)}
342
359
  @dblclick=${() => this.onRowDoubleClick(row)}
343
360
  @keydown=${(e) => this.onRowKeyDown(e, row, index)}
344
361
  class=${this.isSelected(row) ? "row-selected" : ""}
362
+ aria-selected=${this.isSelected(row)}
345
363
  data-row-selected=${this.isSelected(row)}
346
364
  data-id=${row.id}
347
365
  id=${"row-" + row.id}
348
- tabindex="0"
349
366
  >
350
367
  ${this.visibleColumns.map((column) => html `
351
- <td style=${`flex: ${column.flexRatio}`}>
368
+ <td
369
+ role="gridcell"
370
+ style=${`flex: ${column.flexRatio}`}
371
+ >
352
372
  ${column.dataType.format(row.data)}
353
373
  </td>
354
374
  `)}
355
375
  </tr>
356
376
  `)
357
377
  : html `
358
- <tr>
359
- <td class="no-data">Loading...</td>
378
+ <tr role="row">
379
+ <td role="gridcell" class="no-data">Loading...</td>
360
380
  </tr>
361
381
  `}
362
382
  ${!this.isLoading && this.sortedRows.length === 0
363
383
  ? html `
364
- <tr>
365
- <td class="no-data">${this.noDataText}</td>
384
+ <tr role="row">
385
+ <td role="gridcell" class="no-data">${this.noDataText}</td>
366
386
  </tr>
367
387
  `
368
388
  : null}
@@ -447,9 +467,6 @@ AdsTable.styles = css `
447
467
  __decorate([
448
468
  query("#main-table")
449
469
  ], AdsTable.prototype, "tableElement", void 0);
450
- __decorate([
451
- queryAll("table tr")
452
- ], AdsTable.prototype, "tableRows", void 0);
453
470
  __decorate([
454
471
  property({ type: Array })
455
472
  ], AdsTable.prototype, "rows", void 0);
@@ -1 +1 @@
1
- {"version":3,"file":"ads-table.js","sourceRoot":"","sources":["../src/ads-table.ts"],"names":[],"mappings":"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","sourcesContent":["// interface class for a Lit component class that contains table data\nimport {\n css,\n CSSResultGroup,\n html,\n LitElement,\n PropertyValues,\n TemplateResult,\n} from \"lit\";\nimport {\n SortComparisonFunction,\n TableColumn,\n TableDataType,\n TableRow,\n} from \"./types\";\nimport {\n property,\n state,\n query,\n queryAll,\n customElement,\n} from \"lit/decorators.js\";\nimport { EventHelpers } from \"@internetarchive/ads-library\";\nimport { getUserOS, UserOperatingSystem } from \"@internetarchive/ads-library\";\n\nexport abstract class AdsTable<T> extends LitElement {\n @query(\"#main-table\") tableElement: HTMLTableElement | undefined;\n\n @queryAll(\"table tr\") tableRows: HTMLTableRowElement[] | undefined;\n\n protected getTableRowElementById(\n id: string,\n ): HTMLTableRowElement | undefined {\n return Array.from(this.tableRows || []).find(\n (row) => row.id === `row-${id}`,\n );\n }\n\n // base list of data that this class sorts\n @property({ type: Array }) rows: TableRow<T>[] = [];\n\n @property({ type: Boolean }) disableKeyboardNavigation: boolean = false;\n\n // abstract members to override\n protected abstract columns: TableColumn<T>[];\n protected abstract sortKey: keyof T | undefined;\n protected abstract secondarySortKey: keyof T | undefined;\n\n protected noDataText: string = \"No items found\";\n\n protected readonly defaultSortDirection: \"ascending\" | \"descending\" =\n \"ascending\";\n\n @state() protected sortDirection: \"ascending\" | \"descending\" =\n this.defaultSortDirection;\n\n // list of selected rows in order of least to most recently added\n @state() protected selectedRowIds: string[] = [];\n\n @state() isLoading: boolean = false;\n\n protected override updated(changedProperties: PropertyValues) {\n super.updated(changedProperties);\n if (changedProperties.has(\"selectedRowIds\")) {\n // report selected rows to parent via an event\n this.emitEvent(\"row-select\", { selectedRows: this.selectedRows });\n }\n\n // if rows change, re-ensure selected rows exist in table\n if (this.rowsDidUpdate(changedProperties)) {\n this.filterSelectedRowsToExistingRows();\n }\n }\n\n // rather than compare references, determine if 'this.rows' has updated. an update occurs if:\n // - row list is a different size\n // - any elements in the sorted list may have changed place\n protected rowsDidUpdate(changedProperties: PropertyValues): boolean {\n // if the sort properties change, assume the elements have rearranged\n if (\n changedProperties.has(\"sortKey\") ||\n changedProperties.has(\"sortDirection\")\n ) {\n return true;\n }\n if (!changedProperties.has(\"rows\") || !changedProperties.get(\"rows\")) {\n return false;\n }\n const oldRowIds: string[] = (\n changedProperties.get(\"rows\") as TableRow<T>[]\n ).map((row: TableRow<T>) => row.id);\n // first check length. if list length changes, rows have changed.\n if (oldRowIds.length !== this.rows.length) {\n return true;\n }\n // otherwise, if they're the same size, compare individual items and ensure they're the same set of items\n const newRowsIdsSet: Set<string> = new Set(this.rows.map((row) => row.id));\n return !oldRowIds.every((id) => newRowsIdsSet.has(id));\n }\n\n protected emitEvent(eventName: string, detail = {}) {\n this.dispatchEvent(\n EventHelpers.createEvent(eventName, detail ? { detail } : {}),\n );\n }\n\n protected get visibleColumns(): TableColumn<T>[] {\n return this.columns.filter(({ isHidden }) => !isHidden);\n }\n\n protected get rowsById(): { [key: string]: TableRow<T> } {\n return Object.fromEntries<TableRow<T>>(\n this.rows.map((row) => [row.id, row]),\n );\n }\n\n protected get sortedRows(): TableRow<T>[] {\n // if sorting has been done already, return the rows as-is.\n if (this.selectedColumn.preSorted) {\n return this.rows;\n }\n const sortByPrimaryKey = this.getSortFunction(\n this.sortColumnDataType,\n this.sortDirection,\n );\n const sortBySecondaryKey = this.getSortFunction(\n this.secondarySortDataType,\n this.secondarySortDataType?.defaultSortDirection || this.sortDirection,\n );\n return this.rows.sort((rowA, rowB) => {\n // sort by primary key: the selected column and direction\n const sortResult = sortByPrimaryKey?.(rowA.data, rowB.data) || 0;\n // if sort result on primary sort key is inconclusive, use secondary sort data type\n if (sortResult === 0) {\n return sortBySecondaryKey?.(rowA.data, rowB.data) || 0;\n } else {\n return sortResult;\n }\n });\n }\n\n // rows highlighted by user\n protected get selectedRows(): TableRow<T>[] {\n return this.selectedRowIds.map((id) => this.rowsById[id]).filter((x) => x);\n }\n\n // the column you are currently sorting by\n protected get selectedColumn(): TableColumn<T> {\n return this.columnByKey[this.sortKey as string];\n }\n\n // handler for when a user clicks on a column header\n protected onColumnClick(\n column: TableColumn<T>,\n defaultSortDirection: \"ascending\" | \"descending\" = this\n .defaultSortDirection,\n ): void {\n if (this.sortKey === column.key) {\n // toggle the sort direction if the column you are clicking is already sorted\n this.sortDirection =\n this.sortDirection === \"ascending\" ? \"descending\" : \"ascending\";\n } else {\n // otherwise, sort by the column you clicked on, and in the default sort direction\n this.sortKey = column.key;\n this.sortDirection =\n column.dataType.defaultSortDirection || defaultSortDirection;\n }\n this.emitEvent(\"column-click\", {\n column,\n sortKey: this.sortKey,\n sortDirection: this.sortDirection,\n });\n }\n\n // a map of column keys to their respective data types so we don't have to call .find everywhere\n protected get columnByKey(): {\n [columnKey: string]: TableColumn<T>;\n } {\n return Object.fromEntries<TableColumn<T>>(\n this.columns.map((col) => [col.key, col]),\n );\n }\n\n // data type of the currently sorted column\n protected get sortColumnDataType(): TableDataType<T> | undefined {\n if (this.sortKey) {\n return this.columnByKey[this.sortKey as string].dataType;\n } else {\n return undefined;\n }\n }\n\n // data type of the secondary sort column\n protected get secondarySortDataType(): TableDataType<T> | undefined {\n if (this.secondarySortKey) {\n return this.columnByKey[this.secondarySortKey as string].dataType;\n } else {\n return undefined;\n }\n }\n\n // swaps the parameters of the sort function to reverse the sort direction\n protected getSortFunction(\n dataType: TableDataType<T> | undefined,\n sortDirection: \"ascending\" | \"descending\",\n ): SortComparisonFunction<T> | undefined {\n if (!dataType) {\n return undefined;\n }\n if (sortDirection === \"ascending\") {\n // return the original comparison function\n return dataType.compare;\n } else if (dataType.compare !== undefined) {\n // swap compare function parameters for descending\n return (a, b) => dataType.compare?.(b, a) || 0;\n } else {\n return undefined;\n }\n }\n\n protected renderArrowIcon(columnKey: keyof T): TemplateResult {\n if (columnKey !== this.sortKey) {\n return html``;\n } else if (this.sortDirection === \"ascending\") {\n return html`▲`;\n } else {\n return html`▼`;\n }\n }\n\n protected get selectedRowIdsSet(): Set<string> {\n return new Set(this.selectedRowIds);\n }\n\n protected get rowIdsSet(): Set<string> {\n return new Set(this.rows.map((row) => row.id));\n }\n\n protected isSelected(row: TableRow<T>): boolean {\n return this.selectedRowIdsSet.has(row.id);\n }\n\n protected toggleRowSelected(rowId: string): void {\n if (this.selectedRowIdsSet.has(rowId)) {\n // row is already selected: filter out clicked id\n this.selectedRowIds = this.selectedRowIds.filter((id) => id !== rowId);\n } else {\n // row is not yet selected: append clicked id\n this.selectedRowIds = [...this.selectedRowIds, rowId];\n }\n }\n\n protected get lastSelectedRowId(): string {\n return this.selectedRowIds[this.selectedRowIds.length - 1];\n }\n\n protected get indexOfLastSelectedRow(): number {\n return this.rows.findIndex((row) => row.id === this.lastSelectedRowId);\n }\n\n // select rows in order from the last selected element up til the given index\n protected groupRowSelect(rowIndex: number): void {\n const getRowsToAdd = (): TableRow<T>[] => {\n // get rows between index of last selected until index of selected row\n if (rowIndex > this.indexOfLastSelectedRow) {\n return this.rows.filter(\n (_, i) => rowIndex >= i && i >= this.indexOfLastSelectedRow,\n );\n } else {\n // reverse order of adding rows since clicked index is lower than last selected\n return this.rows\n .filter((_, i) => this.indexOfLastSelectedRow >= i && i >= rowIndex)\n .reverse();\n }\n };\n const rowIdsToAdd: string[] = getRowsToAdd().map((row) => row.id);\n const rowIdsSet: Set<string> = new Set(rowIdsToAdd);\n // first remove ids you are about to re-add, so they'll be in renewed order\n this.selectedRowIds = this.selectedRowIds.filter(\n (id) => !rowIdsSet.has(id),\n );\n // finally, add the new rows\n this.selectedRowIds = [...this.selectedRowIds, ...rowIdsToAdd];\n }\n\n protected onRowClick(\n event: MouseEvent | KeyboardEvent,\n clickedRow: TableRow<T>,\n rowIndex: number,\n ): void {\n const userOs = getUserOS();\n // meta (cmd) key for mac, control key for non-mac\n const macHoldingHotKey =\n userOs === UserOperatingSystem.MAC && event.metaKey;\n const nonMacHoldingHotKey =\n userOs !== UserOperatingSystem.MAC && event.ctrlKey;\n // if holding meta on mac or ctrl on windows/linux, toggle individual row selection\n if (macHoldingHotKey || nonMacHoldingHotKey) {\n this.toggleRowSelected(clickedRow.id);\n } else if (event.shiftKey) {\n // if holding shift, select rows between this selection and the last selection\n this.groupRowSelect(rowIndex);\n } else {\n // clicking a row will select just that row.\n this.selectedRowIds = [clickedRow.id];\n }\n this.filterSelectedRowsToExistingRows();\n // emit event so users can hook into this action\n this.emitEvent(\"row-click\", { row: clickedRow });\n }\n\n // filter selected down to rows that actually exist in the table\n protected filterSelectedRowsToExistingRows() {\n this.selectedRowIds = this.selectedRowIds.filter((id) =>\n this.rowIdsSet.has(id),\n );\n }\n\n protected onRowDoubleClick(clickedRow: TableRow<T>): void {\n // emit event so users can hook into this event\n this.emitEvent(\"row-double-click\", { row: clickedRow });\n }\n\n // default global keyboard events implemented through this method.\n // event.stopImmediatePropagation() in DOM keyboard event listeners will\n // prevent this method from being called.\n protected onKeyDown(event: KeyboardEvent): void {\n if (this.disableKeyboardNavigation) {\n return;\n }\n switch (event.key) {\n case \"ArrowUp\":\n case \"ArrowDown\":\n event.preventDefault();\n return this.onUpDownArrowKey(event);\n }\n }\n\n // listener applies when column has focus\n protected onColumnKeyDown(\n event: KeyboardEvent,\n column: TableColumn<T>,\n ): void {\n if (this.disableKeyboardNavigation) {\n return;\n }\n switch (event.key) {\n case \"Enter\":\n return this.onColumnClick(column);\n }\n }\n\n // listener applies when row has focus\n protected onRowKeyDown(\n event: KeyboardEvent,\n row: TableRow<T>,\n index: number,\n ): void {\n if (this.disableKeyboardNavigation) {\n return;\n }\n switch (event.key) {\n // enter to select, enter again to navigate within, shift + enter to deselect (and select), while in multiselect\n case \"Enter\":\n if (\n this.isSelected(row) &&\n !event.shiftKey &&\n this.selectedRows.length === 1\n ) {\n return this.onRowClick(event, row, index);\n } else {\n event.stopImmediatePropagation();\n return this.toggleRowSelected(row.id);\n }\n }\n }\n\n protected onUpDownArrowKey(event: KeyboardEvent): void {\n if (this.rows.length === 0) {\n // there are no rows to navigate or select with arrows. avoids array out of bounds.\n return;\n }\n const indexOffset = event.key === \"ArrowUp\" ? -1 : 1;\n const newSelectedRowIndex = this.constrainIndex(\n this.indexOfLastSelectedRow + indexOffset,\n );\n const newSelectedRowId = this.rows[newSelectedRowIndex].id;\n\n if (event.shiftKey) {\n // - focus and (maybe) select and focus the prev or next, if it exists\n this.groupRowSelect(newSelectedRowIndex);\n } else if (this.selectedRowIds.length === 0) {\n // select the first row if none are selected\n const firstRowId = this.rows[0] ? this.rows[0].id : undefined;\n if (firstRowId) {\n this.selectedRowIds = [firstRowId];\n }\n } else {\n // offset in the proper direction of the arrow\n this.selectedRowIds = [newSelectedRowId];\n }\n // always try to focus the next element in the direction of the arrow if you can\n this.getTableRowElementById(newSelectedRowId)?.focus();\n }\n\n // ensures index values are kept to the closest in-bounds index\n protected constrainIndex(index: number): number {\n return Math.max(Math.min(index, this.rows.length - 1), 0);\n }\n\n connectedCallback() {\n super.connectedCallback();\n // attach keyboard listener for arrow keys\n window.addEventListener(\"keydown\", (e: KeyboardEvent) => this.onKeyDown(e));\n }\n\n render() {\n return html`\n <table id=\"main-table\">\n <thead>\n <tr>\n ${this.visibleColumns.map(\n (column) => html`\n <th\n @click=${() => this.onColumnClick(column)}\n @keydown=${(e: KeyboardEvent) =>\n this.onColumnKeyDown(e, column)}\n class=${column.dataType.compare ? \"sortable\" : \"\"}\n style=${`flex: ${column.flexRatio}`}\n tabindex=\"0\"\n >\n ${column.label}\n ${column.dataType.compare\n ? html`<span>${this.renderArrowIcon(column.key)}</span>`\n : \"\"}\n </th>\n `,\n )}\n </tr>\n </thead>\n <tbody>\n ${!this.isLoading\n ? this.sortedRows.map(\n (row, index) => html`\n <tr\n @click=${(e: MouseEvent) => this.onRowClick(e, row, index)}\n @dblclick=${() => this.onRowDoubleClick(row)}\n @keydown=${(e: KeyboardEvent) =>\n this.onRowKeyDown(e, row, index)}\n class=${this.isSelected(row) ? \"row-selected\" : \"\"}\n data-row-selected=${this.isSelected(row)}\n data-id=${row.id}\n id=${\"row-\" + row.id}\n tabindex=\"0\"\n >\n ${this.visibleColumns.map(\n (column) => html`\n <td style=${`flex: ${column.flexRatio}`}>\n ${column.dataType.format(row.data)}\n </td>\n `,\n )}\n </tr>\n `,\n )\n : html`\n <tr>\n <td class=\"no-data\">Loading...</td>\n </tr>\n `}\n ${!this.isLoading && this.sortedRows.length === 0\n ? html`\n <tr>\n <td class=\"no-data\">${this.noDataText}</td>\n </tr>\n `\n : null}\n </tbody>\n </table>\n `;\n }\n\n static styles: CSSResultGroup = css`\n table {\n display: flex;\n flex-direction: column;\n user-select: none;\n border-collapse: collapse;\n }\n\n thead,\n tbody {\n display: flex;\n flex-direction: column;\n }\n\n thead {\n background: #2a282c;\n }\n\n tbody {\n scrollbar-gutter: stable;\n }\n\n tr {\n display: flex;\n width: 100%;\n min-height: 40px;\n flex-shrink: 0;\n }\n\n tr.row-selected {\n background: #ddebff;\n }\n\n td.no-data {\n font-style: italic;\n justify-content: center;\n }\n\n td,\n th {\n display: flex;\n flex: 1;\n justify-content: flex-start;\n align-items: center;\n padding: 0 12px;\n height: 40px;\n\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n }\n\n th {\n color: white;\n }\n\n th.sortable {\n cursor: pointer;\n }\n\n th.sortable:hover {\n background: #525252;\n }\n\n th span {\n padding-left: 5px;\n }\n\n td {\n border-bottom: 1px solid #bbbbbb;\n }\n `;\n}\n\n// a simple, generic, out-of-the box implementation of AdsTable\n@customElement(\"ads-simple-table\")\nexport class AdsSimpleTable<T> extends AdsTable<T> {\n // columns are exposed as a parameter like rows, not a class member to implement\n @property({ type: Array }) columns: TableColumn<T>[] = [];\n\n @property({ type: String }) secondarySortKey: keyof T | undefined = undefined;\n\n // sort key is automatically held in state\n @state() sortKey: keyof T | undefined = this.columns[0]?.key;\n\n protected override updated(changedProperties: PropertyValues) {\n super.updated(changedProperties);\n if (changedProperties.has(\"columns\")) {\n this.sortKey = this.columns[0]?.key;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"ads-table.js","sourceRoot":"","sources":["../src/ads-table.ts"],"names":[],"mappings":"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","sourcesContent":["// interface class for a Lit component class that contains table data\nimport {\n css,\n CSSResultGroup,\n html,\n LitElement,\n PropertyValues,\n TemplateResult,\n} from \"lit\";\nimport {\n SortComparisonFunction,\n TableColumn,\n TableDataType,\n TableRow,\n} from \"./types\";\nimport { property, state, query, customElement } from \"lit/decorators.js\";\nimport { EventHelpers } from \"@internetarchive/ads-library\";\nimport { getUserOS, UserOperatingSystem } from \"@internetarchive/ads-library\";\n\nexport abstract class AdsTable<T> extends LitElement {\n @query(\"#main-table\") tableElement: HTMLTableElement | undefined;\n\n // base list of data that this class sorts\n @property({ type: Array }) rows: TableRow<T>[] = [];\n\n @property({ type: Boolean }) disableKeyboardNavigation: boolean = false;\n\n // abstract members to override\n protected abstract columns: TableColumn<T>[];\n protected abstract sortKey: keyof T | undefined;\n protected abstract secondarySortKey: keyof T | undefined;\n\n protected noDataText: string = \"No items found\";\n\n protected readonly defaultSortDirection: \"ascending\" | \"descending\" =\n \"ascending\";\n\n @state() protected sortDirection: \"ascending\" | \"descending\" =\n this.defaultSortDirection;\n\n // list of selected rows in order of least to most recently added\n @state() protected selectedRowIds: string[] = [];\n\n @state() isLoading: boolean = false;\n\n protected override updated(changedProperties: PropertyValues) {\n super.updated(changedProperties);\n if (changedProperties.has(\"selectedRowIds\")) {\n // report selected rows to parent via an event\n this.emitEvent(\"row-select\", { selectedRows: this.selectedRows });\n }\n\n // if rows change, re-ensure selected rows exist in table\n if (this.rowsDidUpdate(changedProperties)) {\n this.filterSelectedRowsToExistingRows();\n }\n }\n\n // rather than compare references, determine if 'this.rows' has updated. an update occurs if:\n // - row list is a different size\n // - any elements in the sorted list may have changed place\n protected rowsDidUpdate(changedProperties: PropertyValues): boolean {\n // if the sort properties change, assume the elements have rearranged\n if (\n changedProperties.has(\"sortKey\") ||\n changedProperties.has(\"sortDirection\")\n ) {\n return true;\n }\n if (!changedProperties.has(\"rows\") || !changedProperties.get(\"rows\")) {\n return false;\n }\n const oldRowIds: string[] = (\n changedProperties.get(\"rows\") as TableRow<T>[]\n ).map((row: TableRow<T>) => row.id);\n // first check length. if list length changes, rows have changed.\n if (oldRowIds.length !== this.rows.length) {\n return true;\n }\n // otherwise, if they're the same size, compare individual items and ensure they're the same set of items\n const newRowsIdsSet: Set<string> = new Set(this.rows.map((row) => row.id));\n return !oldRowIds.every((id) => newRowsIdsSet.has(id));\n }\n\n protected emitEvent(eventName: string, detail = {}) {\n this.dispatchEvent(\n EventHelpers.createEvent(eventName, detail ? { detail } : {}),\n );\n }\n\n protected get visibleColumns(): TableColumn<T>[] {\n return this.columns.filter(({ isHidden }) => !isHidden);\n }\n\n protected get rowsById(): { [key: string]: TableRow<T> } {\n return Object.fromEntries<TableRow<T>>(\n this.rows.map((row) => [row.id, row]),\n );\n }\n\n protected get sortedRows(): TableRow<T>[] {\n // if sorting has been done already, return the rows as-is.\n if (this.selectedColumn.preSorted) {\n return this.rows;\n }\n const sortByPrimaryKey = this.getSortFunction(\n this.sortColumnDataType,\n this.sortDirection,\n );\n const sortBySecondaryKey = this.getSortFunction(\n this.secondarySortDataType,\n this.secondarySortDataType?.defaultSortDirection || this.sortDirection,\n );\n return this.rows.sort((rowA, rowB) => {\n // sort by primary key: the selected column and direction\n const sortResult = sortByPrimaryKey?.(rowA.data, rowB.data) || 0;\n // if sort result on primary sort key is inconclusive, use secondary sort data type\n if (sortResult === 0) {\n return sortBySecondaryKey?.(rowA.data, rowB.data) || 0;\n } else {\n return sortResult;\n }\n });\n }\n\n // rows highlighted by user\n protected get selectedRows(): TableRow<T>[] {\n return this.selectedRowIds.map((id) => this.rowsById[id]).filter((x) => x);\n }\n\n // the column you are currently sorting by\n protected get selectedColumn(): TableColumn<T> {\n return this.columnByKey[this.sortKey as string];\n }\n\n // handler for when a user clicks on a column header\n protected onColumnClick(\n column: TableColumn<T>,\n defaultSortDirection: \"ascending\" | \"descending\" = this\n .defaultSortDirection,\n ): void {\n if (this.sortKey === column.key) {\n // toggle the sort direction if the column you are clicking is already sorted\n this.sortDirection =\n this.sortDirection === \"ascending\" ? \"descending\" : \"ascending\";\n } else {\n // otherwise, sort by the column you clicked on, and in the default sort direction\n this.sortKey = column.key;\n this.sortDirection =\n column.dataType.defaultSortDirection || defaultSortDirection;\n }\n this.emitEvent(\"column-click\", {\n column,\n sortKey: this.sortKey,\n sortDirection: this.sortDirection,\n });\n }\n\n // a map of column keys to their respective data types so we don't have to call .find everywhere\n protected get columnByKey(): {\n [columnKey: string]: TableColumn<T>;\n } {\n return Object.fromEntries<TableColumn<T>>(\n this.columns.map((col) => [col.key, col]),\n );\n }\n\n // data type of the currently sorted column\n protected get sortColumnDataType(): TableDataType<T> | undefined {\n if (this.sortKey) {\n return this.columnByKey[this.sortKey as string].dataType;\n } else {\n return undefined;\n }\n }\n\n // data type of the secondary sort column\n protected get secondarySortDataType(): TableDataType<T> | undefined {\n if (this.secondarySortKey) {\n return this.columnByKey[this.secondarySortKey as string].dataType;\n } else {\n return undefined;\n }\n }\n\n // swaps the parameters of the sort function to reverse the sort direction\n protected getSortFunction(\n dataType: TableDataType<T> | undefined,\n sortDirection: \"ascending\" | \"descending\",\n ): SortComparisonFunction<T> | undefined {\n if (!dataType) {\n return undefined;\n }\n if (sortDirection === \"ascending\") {\n // return the original comparison function\n return dataType.compare;\n } else if (dataType.compare !== undefined) {\n // swap compare function parameters for descending\n return (a, b) => dataType.compare?.(b, a) || 0;\n } else {\n return undefined;\n }\n }\n\n protected renderArrowIcon(columnKey: keyof T): TemplateResult {\n if (columnKey !== this.sortKey) {\n return html``;\n } else if (this.sortDirection === \"ascending\") {\n return html`▲`;\n } else {\n return html`▼`;\n }\n }\n\n protected get selectedRowIdsSet(): Set<string> {\n return new Set(this.selectedRowIds);\n }\n\n protected get rowIdsSet(): Set<string> {\n return new Set(this.rows.map((row) => row.id));\n }\n\n protected isSelected(row: TableRow<T>): boolean {\n return this.selectedRowIdsSet.has(row.id);\n }\n\n protected toggleRowSelected(rowId: string): void {\n if (this.selectedRowIdsSet.has(rowId)) {\n // row is already selected: filter out clicked id\n this.selectedRowIds = this.selectedRowIds.filter((id) => id !== rowId);\n } else {\n // row is not yet selected: append clicked id\n this.selectedRowIds = [...this.selectedRowIds, rowId];\n }\n }\n\n protected get lastSelectedRowId(): string {\n return this.selectedRowIds[this.selectedRowIds.length - 1];\n }\n\n protected get indexOfLastSelectedRow(): number {\n return this.rows.findIndex((row) => row.id === this.lastSelectedRowId);\n }\n\n // select rows in order from the last selected element up til the given index\n protected groupRowSelect(rowIndex: number): void {\n const getRowsToAdd = (): TableRow<T>[] => {\n // get rows between index of last selected until index of selected row\n if (rowIndex > this.indexOfLastSelectedRow) {\n return this.rows.filter(\n (_, i) => rowIndex >= i && i >= this.indexOfLastSelectedRow,\n );\n } else {\n // reverse order of adding rows since clicked index is lower than last selected\n return this.rows\n .filter((_, i) => this.indexOfLastSelectedRow >= i && i >= rowIndex)\n .reverse();\n }\n };\n const rowIdsToAdd: string[] = getRowsToAdd().map((row) => row.id);\n const rowIdsSet: Set<string> = new Set(rowIdsToAdd);\n // first remove ids you are about to re-add, so they'll be in renewed order\n this.selectedRowIds = this.selectedRowIds.filter(\n (id) => !rowIdsSet.has(id),\n );\n // finally, add the new rows\n this.selectedRowIds = [...this.selectedRowIds, ...rowIdsToAdd];\n }\n\n protected onRowClick(\n event: MouseEvent | KeyboardEvent,\n clickedRow: TableRow<T>,\n rowIndex: number,\n ): void {\n const userOs = getUserOS();\n // meta (cmd) key for mac, control key for non-mac\n const macHoldingHotKey =\n userOs === UserOperatingSystem.MAC && event.metaKey;\n const nonMacHoldingHotKey =\n userOs !== UserOperatingSystem.MAC && event.ctrlKey;\n // if holding meta on mac or ctrl on windows/linux, toggle individual row selection\n if (macHoldingHotKey || nonMacHoldingHotKey) {\n this.toggleRowSelected(clickedRow.id);\n } else if (event.shiftKey) {\n // if holding shift, select rows between this selection and the last selection\n this.groupRowSelect(rowIndex);\n } else {\n // clicking a row will select just that row.\n this.selectedRowIds = [clickedRow.id];\n }\n this.filterSelectedRowsToExistingRows();\n // emit event so users can hook into this action\n this.emitEvent(\"row-click\", { row: clickedRow });\n }\n\n // filter selected down to rows that actually exist in the table\n protected filterSelectedRowsToExistingRows() {\n this.selectedRowIds = this.selectedRowIds.filter((id) =>\n this.rowIdsSet.has(id),\n );\n }\n\n protected onRowDoubleClick(clickedRow: TableRow<T>): void {\n // emit event so users can hook into this event\n this.emitEvent(\"row-double-click\", { row: clickedRow });\n }\n\n // default global keyboard events implemented through this method.\n // event.stopImmediatePropagation() in DOM keyboard event listeners will\n // prevent this method from being called.\n protected onKeyDown(event: KeyboardEvent): void {\n if (this.disableKeyboardNavigation) {\n return;\n }\n switch (event.key) {\n case \"ArrowUp\":\n case \"ArrowDown\":\n event.preventDefault();\n return this.onUpDownArrowKey(event);\n }\n }\n\n // listener applies only after table has focus\n protected onTableKeyDown(event: KeyboardEvent): void {\n if (this.disableKeyboardNavigation) {\n return;\n }\n // on esc or delete, emit an event\n switch (event.key) {\n case \"Escape\":\n return this.emitEvent(\"table-navigate-back\");\n case \"Backspace\":\n return this.emitEvent(\"table-navigate-back\");\n }\n }\n\n // listener applies when column has focus - does nothing since\n // column header cannot get focus right now.\n protected onColumnKeyDown(\n event: KeyboardEvent,\n column: TableColumn<T>,\n ): void {\n if (this.disableKeyboardNavigation) {\n return;\n }\n switch (event.key) {\n case \"Enter\":\n return this.onColumnClick(column);\n }\n }\n\n // listener applies when row has focus\n protected onRowKeyDown(\n event: KeyboardEvent,\n row: TableRow<T>,\n index: number,\n ): void {\n if (this.disableKeyboardNavigation) {\n return;\n }\n switch (event.key) {\n // enter to select, enter again to navigate within, shift + enter to deselect (and select), while in multiselect\n case \"Enter\":\n if (\n this.isSelected(row) &&\n !event.shiftKey &&\n this.selectedRows.length === 1\n ) {\n return this.onRowClick(event, row, index);\n } else {\n event.stopImmediatePropagation();\n return this.toggleRowSelected(row.id);\n }\n }\n }\n\n protected focusTableElement(): void {\n this.tableElement?.focus();\n }\n\n protected onUpDownArrowKey(event: KeyboardEvent): void {\n if (this.rows.length === 0) {\n // there are no rows to navigate or select with arrows. avoids array out of bounds.\n return;\n }\n // focus the main table element with each arrow key press\n this.focusTableElement();\n\n const indexOffset = event.key === \"ArrowUp\" ? -1 : 1;\n const newSelectedRowIndex = this.constrainIndex(\n this.indexOfLastSelectedRow + indexOffset,\n );\n const newSelectedRowId = this.rows[newSelectedRowIndex].id;\n\n if (this.selectedRowIds.length === 0) {\n // if none are selected, select the first row\n const firstRowId = this.rows[0] ? this.rows[0].id : undefined;\n if (firstRowId) {\n this.selectedRowIds = [firstRowId];\n }\n } else {\n // offset in the proper direction of the arrow\n this.selectedRowIds = [newSelectedRowId];\n }\n }\n\n // ensures index values are kept to the closest in-bounds index\n protected constrainIndex(index: number): number {\n return Math.max(Math.min(index, this.rows.length - 1), 0);\n }\n\n connectedCallback() {\n super.connectedCallback();\n // attach keyboard listener for arrow keys\n window.addEventListener(\"keydown\", (e: KeyboardEvent) => this.onKeyDown(e));\n }\n\n render() {\n return html`\n <table\n tabindex=\"0\"\n role=\"treegrid\"\n id=\"main-table\"\n @keydown=${(e: KeyboardEvent) => this.onTableKeyDown(e)}\n >\n <thead>\n <tr role=\"row\">\n ${this.visibleColumns.map(\n (column) => html`\n <th\n role=\"gridcell\"\n aria-label=${column.label}\n @click=${() => this.onColumnClick(column)}\n @keydown=${(e: KeyboardEvent) =>\n this.onColumnKeyDown(e, column)}\n class=${column.dataType.compare ? \"sortable\" : \"\"}\n style=${`flex: ${column.flexRatio}`}\n >\n ${column.label}\n ${column.dataType.compare\n ? html`<span>${this.renderArrowIcon(column.key)}</span>`\n : \"\"}\n </th>\n `,\n )}\n </tr>\n </thead>\n <tbody>\n ${!this.isLoading\n ? this.sortedRows.map(\n (row, index) => html`\n <tr\n role=\"row\"\n @click=${(e: MouseEvent) => this.onRowClick(e, row, index)}\n @dblclick=${() => this.onRowDoubleClick(row)}\n @keydown=${(e: KeyboardEvent) =>\n this.onRowKeyDown(e, row, index)}\n class=${this.isSelected(row) ? \"row-selected\" : \"\"}\n aria-selected=${this.isSelected(row)}\n data-row-selected=${this.isSelected(row)}\n data-id=${row.id}\n id=${\"row-\" + row.id}\n >\n ${this.visibleColumns.map(\n (column) => html`\n <td\n role=\"gridcell\"\n style=${`flex: ${column.flexRatio}`}\n >\n ${column.dataType.format(row.data)}\n </td>\n `,\n )}\n </tr>\n `,\n )\n : html`\n <tr role=\"row\">\n <td role=\"gridcell\" class=\"no-data\">Loading...</td>\n </tr>\n `}\n ${!this.isLoading && this.sortedRows.length === 0\n ? html`\n <tr role=\"row\">\n <td role=\"gridcell\" class=\"no-data\">${this.noDataText}</td>\n </tr>\n `\n : null}\n </tbody>\n </table>\n `;\n }\n\n static styles: CSSResultGroup = css`\n table {\n display: flex;\n flex-direction: column;\n user-select: none;\n border-collapse: collapse;\n }\n\n thead,\n tbody {\n display: flex;\n flex-direction: column;\n }\n\n thead {\n background: #2a282c;\n }\n\n tbody {\n scrollbar-gutter: stable;\n }\n\n tr {\n display: flex;\n width: 100%;\n min-height: 40px;\n flex-shrink: 0;\n }\n\n tr.row-selected {\n background: #ddebff;\n }\n\n td.no-data {\n font-style: italic;\n justify-content: center;\n }\n\n td,\n th {\n display: flex;\n flex: 1;\n justify-content: flex-start;\n align-items: center;\n padding: 0 12px;\n height: 40px;\n\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n }\n\n th {\n color: white;\n }\n\n th.sortable {\n cursor: pointer;\n }\n\n th.sortable:hover {\n background: #525252;\n }\n\n th span {\n padding-left: 5px;\n }\n\n td {\n border-bottom: 1px solid #bbbbbb;\n }\n `;\n}\n\n// a simple, generic, out-of-the box implementation of AdsTable\n@customElement(\"ads-simple-table\")\nexport class AdsSimpleTable<T> extends AdsTable<T> {\n // columns are exposed as a parameter like rows, not a class member to implement\n @property({ type: Array }) columns: TableColumn<T>[] = [];\n\n @property({ type: String }) secondarySortKey: keyof T | undefined = undefined;\n\n // sort key is automatically held in state\n @state() sortKey: keyof T | undefined = this.columns[0]?.key;\n\n protected override updated(changedProperties: PropertyValues) {\n super.updated(changedProperties);\n if (changedProperties.has(\"columns\")) {\n this.sortKey = this.columns[0]?.key;\n }\n }\n}\n"]}
package/dist/index.js CHANGED
@@ -32,20 +32,20 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
32
32
  * Copyright 2019 Google LLC
33
33
  * SPDX-License-Identifier: BSD-3-Clause
34
34
  */
35
- const t$2=globalThis,e$5=t$2.ShadowRoot&&(void 0===t$2.ShadyCSS||t$2.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,s$2=Symbol(),o$4=new WeakMap;let n$3 = class n{constructor(t,e,o){if(this._$cssResult$=true,o!==s$2)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e;}get styleSheet(){let t=this.o;const s=this.t;if(e$5&&void 0===t){const e=void 0!==s&&1===s.length;e&&(t=o$4.get(s)),void 0===t&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),e&&o$4.set(s,t));}return t}toString(){return this.cssText}};const r$5=t=>new n$3("string"==typeof t?t:t+"",void 0,s$2),i$3=(t,...e)=>{const o=1===t.length?t[0]:e.reduce(((e,s,o)=>e+(t=>{if(true===t._$cssResult$)return t.cssText;if("number"==typeof t)return t;throw Error("Value passed to 'css' function must be a 'css' function result: "+t+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(s)+t[o+1]),t[0]);return new n$3(o,t,s$2)},S$1=(s,o)=>{if(e$5)s.adoptedStyleSheets=o.map((t=>t instanceof CSSStyleSheet?t:t.styleSheet));else for(const e of o){const o=document.createElement("style"),n=t$2.litNonce;void 0!==n&&o.setAttribute("nonce",n),o.textContent=e.cssText,s.appendChild(o);}},c$2=e$5?t=>t:t=>t instanceof CSSStyleSheet?(t=>{let e="";for(const s of t.cssRules)e+=s.cssText;return r$5(e)})(t):t;
35
+ const t$2=globalThis,e$4=t$2.ShadowRoot&&(void 0===t$2.ShadyCSS||t$2.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,s$2=Symbol(),o$4=new WeakMap;let n$3 = class n{constructor(t,e,o){if(this._$cssResult$=true,o!==s$2)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e;}get styleSheet(){let t=this.o;const s=this.t;if(e$4&&void 0===t){const e=void 0!==s&&1===s.length;e&&(t=o$4.get(s)),void 0===t&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),e&&o$4.set(s,t));}return t}toString(){return this.cssText}};const r$4=t=>new n$3("string"==typeof t?t:t+"",void 0,s$2),i$3=(t,...e)=>{const o=1===t.length?t[0]:e.reduce(((e,s,o)=>e+(t=>{if(true===t._$cssResult$)return t.cssText;if("number"==typeof t)return t;throw Error("Value passed to 'css' function must be a 'css' function result: "+t+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(s)+t[o+1]),t[0]);return new n$3(o,t,s$2)},S$1=(s,o)=>{if(e$4)s.adoptedStyleSheets=o.map((t=>t instanceof CSSStyleSheet?t:t.styleSheet));else for(const e of o){const o=document.createElement("style"),n=t$2.litNonce;void 0!==n&&o.setAttribute("nonce",n),o.textContent=e.cssText,s.appendChild(o);}},c$2=e$4?t=>t:t=>t instanceof CSSStyleSheet?(t=>{let e="";for(const s of t.cssRules)e+=s.cssText;return r$4(e)})(t):t;
36
36
 
37
37
  /**
38
38
  * @license
39
39
  * Copyright 2017 Google LLC
40
40
  * SPDX-License-Identifier: BSD-3-Clause
41
- */const{is:i$2,defineProperty:e$4,getOwnPropertyDescriptor:h$1,getOwnPropertyNames:r$4,getOwnPropertySymbols:o$3,getPrototypeOf:n$2}=Object,a$1=globalThis,c$1=a$1.trustedTypes,l$1=c$1?c$1.emptyScript:"",p$1=a$1.reactiveElementPolyfillSupport,d$1=(t,s)=>t,u$1={toAttribute(t,s){switch(s){case Boolean:t=t?l$1:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t);}return t},fromAttribute(t,s){let i=t;switch(s){case Boolean:i=null!==t;break;case Number:i=null===t?null:Number(t);break;case Object:case Array:try{i=JSON.parse(t);}catch(t){i=null;}}return i}},f$1=(t,s)=>!i$2(t,s),b={attribute:true,type:String,converter:u$1,reflect:false,useDefault:false,hasChanged:f$1};Symbol.metadata??=Symbol("metadata"),a$1.litPropertyMetadata??=new WeakMap;let y$1 = class y extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t);}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,s=b){if(s.state&&(s.attribute=false),this._$Ei(),this.prototype.hasOwnProperty(t)&&((s=Object.create(s)).wrapped=true),this.elementProperties.set(t,s),!s.noAccessor){const i=Symbol(),h=this.getPropertyDescriptor(t,i,s);void 0!==h&&e$4(this.prototype,t,h);}}static getPropertyDescriptor(t,s,i){const{get:e,set:r}=h$1(this.prototype,t)??{get(){return this[s]},set(t){this[s]=t;}};return {get:e,set(s){const h=e?.call(this);r?.call(this,s),this.requestUpdate(t,h,i);},configurable:true,enumerable:true}}static getPropertyOptions(t){return this.elementProperties.get(t)??b}static _$Ei(){if(this.hasOwnProperty(d$1("elementProperties")))return;const t=n$2(this);t.finalize(),void 0!==t.l&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties);}static finalize(){if(this.hasOwnProperty(d$1("finalized")))return;if(this.finalized=true,this._$Ei(),this.hasOwnProperty(d$1("properties"))){const t=this.properties,s=[...r$4(t),...o$3(t)];for(const i of s)this.createProperty(i,t[i]);}const t=this[Symbol.metadata];if(null!==t){const s=litPropertyMetadata.get(t);if(void 0!==s)for(const[t,i]of s)this.elementProperties.set(t,i);}this._$Eh=new Map;for(const[t,s]of this.elementProperties){const i=this._$Eu(t,s);void 0!==i&&this._$Eh.set(i,t);}this.elementStyles=this.finalizeStyles(this.styles);}static finalizeStyles(s){const i=[];if(Array.isArray(s)){const e=new Set(s.flat(1/0).reverse());for(const s of e)i.unshift(c$2(s));}else void 0!==s&&i.push(c$2(s));return i}static _$Eu(t,s){const i=s.attribute;return false===i?void 0:"string"==typeof i?i:"string"==typeof t?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=false,this.hasUpdated=false,this._$Em=null,this._$Ev();}_$Ev(){this._$ES=new Promise((t=>this.enableUpdating=t)),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach((t=>t(this)));}addController(t){(this._$EO??=new Set).add(t),void 0!==this.renderRoot&&this.isConnected&&t.hostConnected?.();}removeController(t){this._$EO?.delete(t);}_$E_(){const t=new Map,s=this.constructor.elementProperties;for(const i of s.keys())this.hasOwnProperty(i)&&(t.set(i,this[i]),delete this[i]);t.size>0&&(this._$Ep=t);}createRenderRoot(){const t=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return S$1(t,this.constructor.elementStyles),t}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(true),this._$EO?.forEach((t=>t.hostConnected?.()));}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach((t=>t.hostDisconnected?.()));}attributeChangedCallback(t,s,i){this._$AK(t,i);}_$ET(t,s){const i=this.constructor.elementProperties.get(t),e=this.constructor._$Eu(t,i);if(void 0!==e&&true===i.reflect){const h=(void 0!==i.converter?.toAttribute?i.converter:u$1).toAttribute(s,i.type);this._$Em=t,null==h?this.removeAttribute(e):this.setAttribute(e,h),this._$Em=null;}}_$AK(t,s){const i=this.constructor,e=i._$Eh.get(t);if(void 0!==e&&this._$Em!==e){const t=i.getPropertyOptions(e),h="function"==typeof t.converter?{fromAttribute:t.converter}:void 0!==t.converter?.fromAttribute?t.converter:u$1;this._$Em=e;const r=h.fromAttribute(s,t.type);this[e]=r??this._$Ej?.get(e)??r,this._$Em=null;}}requestUpdate(t,s,i){if(void 0!==t){const e=this.constructor,h=this[t];if(i??=e.getPropertyOptions(t),!((i.hasChanged??f$1)(h,s)||i.useDefault&&i.reflect&&h===this._$Ej?.get(t)&&!this.hasAttribute(e._$Eu(t,i))))return;this.C(t,s,i);} false===this.isUpdatePending&&(this._$ES=this._$EP());}C(t,s,{useDefault:i,reflect:e,wrapped:h},r){i&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,r??s??this[t]),true!==h||void 0!==r)||(this._$AL.has(t)||(this.hasUpdated||i||(s=void 0),this._$AL.set(t,s)),true===e&&this._$Em!==t&&(this._$Eq??=new Set).add(t));}async _$EP(){this.isUpdatePending=true;try{await this._$ES;}catch(t){Promise.reject(t);}const t=this.scheduleUpdate();return null!=t&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[t,s]of this._$Ep)this[t]=s;this._$Ep=void 0;}const t=this.constructor.elementProperties;if(t.size>0)for(const[s,i]of t){const{wrapped:t}=i,e=this[s];true!==t||this._$AL.has(s)||void 0===e||this.C(s,void 0,i,e);}}let t=false;const s=this._$AL;try{t=this.shouldUpdate(s),t?(this.willUpdate(s),this._$EO?.forEach((t=>t.hostUpdate?.())),this.update(s)):this._$EM();}catch(s){throw t=false,this._$EM(),s}t&&this._$AE(s);}willUpdate(t){}_$AE(t){this._$EO?.forEach((t=>t.hostUpdated?.())),this.hasUpdated||(this.hasUpdated=true,this.firstUpdated(t)),this.updated(t);}_$EM(){this._$AL=new Map,this.isUpdatePending=false;}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return true}update(t){this._$Eq&&=this._$Eq.forEach((t=>this._$ET(t,this[t]))),this._$EM();}updated(t){}firstUpdated(t){}};y$1.elementStyles=[],y$1.shadowRootOptions={mode:"open"},y$1[d$1("elementProperties")]=new Map,y$1[d$1("finalized")]=new Map,p$1?.({ReactiveElement:y$1}),(a$1.reactiveElementVersions??=[]).push("2.1.1");
41
+ */const{is:i$2,defineProperty:e$3,getOwnPropertyDescriptor:h$1,getOwnPropertyNames:r$3,getOwnPropertySymbols:o$3,getPrototypeOf:n$2}=Object,a$1=globalThis,c$1=a$1.trustedTypes,l$1=c$1?c$1.emptyScript:"",p$1=a$1.reactiveElementPolyfillSupport,d$1=(t,s)=>t,u$1={toAttribute(t,s){switch(s){case Boolean:t=t?l$1:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t);}return t},fromAttribute(t,s){let i=t;switch(s){case Boolean:i=null!==t;break;case Number:i=null===t?null:Number(t);break;case Object:case Array:try{i=JSON.parse(t);}catch(t){i=null;}}return i}},f$1=(t,s)=>!i$2(t,s),b={attribute:true,type:String,converter:u$1,reflect:false,useDefault:false,hasChanged:f$1};Symbol.metadata??=Symbol("metadata"),a$1.litPropertyMetadata??=new WeakMap;let y$1 = class y extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t);}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,s=b){if(s.state&&(s.attribute=false),this._$Ei(),this.prototype.hasOwnProperty(t)&&((s=Object.create(s)).wrapped=true),this.elementProperties.set(t,s),!s.noAccessor){const i=Symbol(),h=this.getPropertyDescriptor(t,i,s);void 0!==h&&e$3(this.prototype,t,h);}}static getPropertyDescriptor(t,s,i){const{get:e,set:r}=h$1(this.prototype,t)??{get(){return this[s]},set(t){this[s]=t;}};return {get:e,set(s){const h=e?.call(this);r?.call(this,s),this.requestUpdate(t,h,i);},configurable:true,enumerable:true}}static getPropertyOptions(t){return this.elementProperties.get(t)??b}static _$Ei(){if(this.hasOwnProperty(d$1("elementProperties")))return;const t=n$2(this);t.finalize(),void 0!==t.l&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties);}static finalize(){if(this.hasOwnProperty(d$1("finalized")))return;if(this.finalized=true,this._$Ei(),this.hasOwnProperty(d$1("properties"))){const t=this.properties,s=[...r$3(t),...o$3(t)];for(const i of s)this.createProperty(i,t[i]);}const t=this[Symbol.metadata];if(null!==t){const s=litPropertyMetadata.get(t);if(void 0!==s)for(const[t,i]of s)this.elementProperties.set(t,i);}this._$Eh=new Map;for(const[t,s]of this.elementProperties){const i=this._$Eu(t,s);void 0!==i&&this._$Eh.set(i,t);}this.elementStyles=this.finalizeStyles(this.styles);}static finalizeStyles(s){const i=[];if(Array.isArray(s)){const e=new Set(s.flat(1/0).reverse());for(const s of e)i.unshift(c$2(s));}else void 0!==s&&i.push(c$2(s));return i}static _$Eu(t,s){const i=s.attribute;return false===i?void 0:"string"==typeof i?i:"string"==typeof t?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=false,this.hasUpdated=false,this._$Em=null,this._$Ev();}_$Ev(){this._$ES=new Promise((t=>this.enableUpdating=t)),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach((t=>t(this)));}addController(t){(this._$EO??=new Set).add(t),void 0!==this.renderRoot&&this.isConnected&&t.hostConnected?.();}removeController(t){this._$EO?.delete(t);}_$E_(){const t=new Map,s=this.constructor.elementProperties;for(const i of s.keys())this.hasOwnProperty(i)&&(t.set(i,this[i]),delete this[i]);t.size>0&&(this._$Ep=t);}createRenderRoot(){const t=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return S$1(t,this.constructor.elementStyles),t}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(true),this._$EO?.forEach((t=>t.hostConnected?.()));}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach((t=>t.hostDisconnected?.()));}attributeChangedCallback(t,s,i){this._$AK(t,i);}_$ET(t,s){const i=this.constructor.elementProperties.get(t),e=this.constructor._$Eu(t,i);if(void 0!==e&&true===i.reflect){const h=(void 0!==i.converter?.toAttribute?i.converter:u$1).toAttribute(s,i.type);this._$Em=t,null==h?this.removeAttribute(e):this.setAttribute(e,h),this._$Em=null;}}_$AK(t,s){const i=this.constructor,e=i._$Eh.get(t);if(void 0!==e&&this._$Em!==e){const t=i.getPropertyOptions(e),h="function"==typeof t.converter?{fromAttribute:t.converter}:void 0!==t.converter?.fromAttribute?t.converter:u$1;this._$Em=e;const r=h.fromAttribute(s,t.type);this[e]=r??this._$Ej?.get(e)??r,this._$Em=null;}}requestUpdate(t,s,i){if(void 0!==t){const e=this.constructor,h=this[t];if(i??=e.getPropertyOptions(t),!((i.hasChanged??f$1)(h,s)||i.useDefault&&i.reflect&&h===this._$Ej?.get(t)&&!this.hasAttribute(e._$Eu(t,i))))return;this.C(t,s,i);} false===this.isUpdatePending&&(this._$ES=this._$EP());}C(t,s,{useDefault:i,reflect:e,wrapped:h},r){i&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,r??s??this[t]),true!==h||void 0!==r)||(this._$AL.has(t)||(this.hasUpdated||i||(s=void 0),this._$AL.set(t,s)),true===e&&this._$Em!==t&&(this._$Eq??=new Set).add(t));}async _$EP(){this.isUpdatePending=true;try{await this._$ES;}catch(t){Promise.reject(t);}const t=this.scheduleUpdate();return null!=t&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[t,s]of this._$Ep)this[t]=s;this._$Ep=void 0;}const t=this.constructor.elementProperties;if(t.size>0)for(const[s,i]of t){const{wrapped:t}=i,e=this[s];true!==t||this._$AL.has(s)||void 0===e||this.C(s,void 0,i,e);}}let t=false;const s=this._$AL;try{t=this.shouldUpdate(s),t?(this.willUpdate(s),this._$EO?.forEach((t=>t.hostUpdate?.())),this.update(s)):this._$EM();}catch(s){throw t=false,this._$EM(),s}t&&this._$AE(s);}willUpdate(t){}_$AE(t){this._$EO?.forEach((t=>t.hostUpdated?.())),this.hasUpdated||(this.hasUpdated=true,this.firstUpdated(t)),this.updated(t);}_$EM(){this._$AL=new Map,this.isUpdatePending=false;}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return true}update(t){this._$Eq&&=this._$Eq.forEach((t=>this._$ET(t,this[t]))),this._$EM();}updated(t){}firstUpdated(t){}};y$1.elementStyles=[],y$1.shadowRootOptions={mode:"open"},y$1[d$1("elementProperties")]=new Map,y$1[d$1("finalized")]=new Map,p$1?.({ReactiveElement:y$1}),(a$1.reactiveElementVersions??=[]).push("2.1.1");
42
42
 
43
43
  /**
44
44
  * @license
45
45
  * Copyright 2017 Google LLC
46
46
  * SPDX-License-Identifier: BSD-3-Clause
47
47
  */
48
- const t$1=globalThis,i$1=t$1.trustedTypes,s$1=i$1?i$1.createPolicy("lit-html",{createHTML:t=>t}):void 0,e$3="$lit$",h=`lit$${Math.random().toFixed(9).slice(2)}$`,o$2="?"+h,n$1=`<${o$2}>`,r$3=document,l=()=>r$3.createComment(""),c=t=>null===t||"object"!=typeof t&&"function"!=typeof t,a=Array.isArray,u=t=>a(t)||"function"==typeof t?.[Symbol.iterator],d="[ \t\n\f\r]",f=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,v=/-->/g,_=/>/g,m=RegExp(`>|${d}(?:([^\\s"'>=/]+)(${d}*=${d}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),p=/'/g,g=/"/g,$=/^(?:script|style|textarea|title)$/i,y=t=>(i,...s)=>({_$litType$:t,strings:i,values:s}),x=y(1),T=Symbol.for("lit-noChange"),E=Symbol.for("lit-nothing"),A=new WeakMap,C=r$3.createTreeWalker(r$3,129);function P(t,i){if(!a(t)||!t.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==s$1?s$1.createHTML(i):i}const V=(t,i)=>{const s=t.length-1,o=[];let r,l=2===i?"<svg>":3===i?"<math>":"",c=f;for(let i=0;i<s;i++){const s=t[i];let a,u,d=-1,y=0;for(;y<s.length&&(c.lastIndex=y,u=c.exec(s),null!==u);)y=c.lastIndex,c===f?"!--"===u[1]?c=v:void 0!==u[1]?c=_:void 0!==u[2]?($.test(u[2])&&(r=RegExp("</"+u[2],"g")),c=m):void 0!==u[3]&&(c=m):c===m?">"===u[0]?(c=r??f,d=-1):void 0===u[1]?d=-2:(d=c.lastIndex-u[2].length,a=u[1],c=void 0===u[3]?m:'"'===u[3]?g:p):c===g||c===p?c=m:c===v||c===_?c=f:(c=m,r=void 0);const x=c===m&&t[i+1].startsWith("/>")?" ":"";l+=c===f?s+n$1:d>=0?(o.push(a),s.slice(0,d)+e$3+s.slice(d)+h+x):s+h+(-2===d?i:x);}return [P(t,l+(t[s]||"<?>")+(2===i?"</svg>":3===i?"</math>":"")),o]};class N{constructor({strings:t,_$litType$:s},n){let r;this.parts=[];let c=0,a=0;const u=t.length-1,d=this.parts,[f,v]=V(t,s);if(this.el=N.createElement(f,n),C.currentNode=this.el.content,2===s||3===s){const t=this.el.content.firstChild;t.replaceWith(...t.childNodes);}for(;null!==(r=C.nextNode())&&d.length<u;){if(1===r.nodeType){if(r.hasAttributes())for(const t of r.getAttributeNames())if(t.endsWith(e$3)){const i=v[a++],s=r.getAttribute(t).split(h),e=/([.?@])?(.*)/.exec(i);d.push({type:1,index:c,name:e[2],strings:s,ctor:"."===e[1]?H:"?"===e[1]?I:"@"===e[1]?L:k}),r.removeAttribute(t);}else t.startsWith(h)&&(d.push({type:6,index:c}),r.removeAttribute(t));if($.test(r.tagName)){const t=r.textContent.split(h),s=t.length-1;if(s>0){r.textContent=i$1?i$1.emptyScript:"";for(let i=0;i<s;i++)r.append(t[i],l()),C.nextNode(),d.push({type:2,index:++c});r.append(t[s],l());}}}else if(8===r.nodeType)if(r.data===o$2)d.push({type:2,index:c});else {let t=-1;for(;-1!==(t=r.data.indexOf(h,t+1));)d.push({type:7,index:c}),t+=h.length-1;}c++;}}static createElement(t,i){const s=r$3.createElement("template");return s.innerHTML=t,s}}function S(t,i,s=t,e){if(i===T)return i;let h=void 0!==e?s._$Co?.[e]:s._$Cl;const o=c(i)?void 0:i._$litDirective$;return h?.constructor!==o&&(h?._$AO?.(false),void 0===o?h=void 0:(h=new o(t),h._$AT(t,s,e)),void 0!==e?(s._$Co??=[])[e]=h:s._$Cl=h),void 0!==h&&(i=S(t,h._$AS(t,i.values),h,e)),i}class M{constructor(t,i){this._$AV=[],this._$AN=void 0,this._$AD=t,this._$AM=i;}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(t){const{el:{content:i},parts:s}=this._$AD,e=(t?.creationScope??r$3).importNode(i,true);C.currentNode=e;let h=C.nextNode(),o=0,n=0,l=s[0];for(;void 0!==l;){if(o===l.index){let i;2===l.type?i=new R(h,h.nextSibling,this,t):1===l.type?i=new l.ctor(h,l.name,l.strings,this,t):6===l.type&&(i=new z(h,this,t)),this._$AV.push(i),l=s[++n];}o!==l?.index&&(h=C.nextNode(),o++);}return C.currentNode=r$3,e}p(t){let i=0;for(const s of this._$AV) void 0!==s&&(void 0!==s.strings?(s._$AI(t,s,i),i+=s.strings.length-2):s._$AI(t[i])),i++;}}class R{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(t,i,s,e){this.type=2,this._$AH=E,this._$AN=void 0,this._$AA=t,this._$AB=i,this._$AM=s,this.options=e,this._$Cv=e?.isConnected??true;}get parentNode(){let t=this._$AA.parentNode;const i=this._$AM;return void 0!==i&&11===t?.nodeType&&(t=i.parentNode),t}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(t,i=this){t=S(this,t,i),c(t)?t===E||null==t||""===t?(this._$AH!==E&&this._$AR(),this._$AH=E):t!==this._$AH&&t!==T&&this._(t):void 0!==t._$litType$?this.$(t):void 0!==t.nodeType?this.T(t):u(t)?this.k(t):this._(t);}O(t){return this._$AA.parentNode.insertBefore(t,this._$AB)}T(t){this._$AH!==t&&(this._$AR(),this._$AH=this.O(t));}_(t){this._$AH!==E&&c(this._$AH)?this._$AA.nextSibling.data=t:this.T(r$3.createTextNode(t)),this._$AH=t;}$(t){const{values:i,_$litType$:s}=t,e="number"==typeof s?this._$AC(t):(void 0===s.el&&(s.el=N.createElement(P(s.h,s.h[0]),this.options)),s);if(this._$AH?._$AD===e)this._$AH.p(i);else {const t=new M(e,this),s=t.u(this.options);t.p(i),this.T(s),this._$AH=t;}}_$AC(t){let i=A.get(t.strings);return void 0===i&&A.set(t.strings,i=new N(t)),i}k(t){a(this._$AH)||(this._$AH=[],this._$AR());const i=this._$AH;let s,e=0;for(const h of t)e===i.length?i.push(s=new R(this.O(l()),this.O(l()),this,this.options)):s=i[e],s._$AI(h),e++;e<i.length&&(this._$AR(s&&s._$AB.nextSibling,e),i.length=e);}_$AR(t=this._$AA.nextSibling,i){for(this._$AP?.(false,true,i);t!==this._$AB;){const i=t.nextSibling;t.remove(),t=i;}}setConnected(t){ void 0===this._$AM&&(this._$Cv=t,this._$AP?.(t));}}class k{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(t,i,s,e,h){this.type=1,this._$AH=E,this._$AN=void 0,this.element=t,this.name=i,this._$AM=e,this.options=h,s.length>2||""!==s[0]||""!==s[1]?(this._$AH=Array(s.length-1).fill(new String),this.strings=s):this._$AH=E;}_$AI(t,i=this,s,e){const h=this.strings;let o=false;if(void 0===h)t=S(this,t,i,0),o=!c(t)||t!==this._$AH&&t!==T,o&&(this._$AH=t);else {const e=t;let n,r;for(t=h[0],n=0;n<h.length-1;n++)r=S(this,e[s+n],i,n),r===T&&(r=this._$AH[n]),o||=!c(r)||r!==this._$AH[n],r===E?t=E:t!==E&&(t+=(r??"")+h[n+1]),this._$AH[n]=r;}o&&!e&&this.j(t);}j(t){t===E?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,t??"");}}class H extends k{constructor(){super(...arguments),this.type=3;}j(t){this.element[this.name]=t===E?void 0:t;}}class I extends k{constructor(){super(...arguments),this.type=4;}j(t){this.element.toggleAttribute(this.name,!!t&&t!==E);}}class L extends k{constructor(t,i,s,e,h){super(t,i,s,e,h),this.type=5;}_$AI(t,i=this){if((t=S(this,t,i,0)??E)===T)return;const s=this._$AH,e=t===E&&s!==E||t.capture!==s.capture||t.once!==s.once||t.passive!==s.passive,h=t!==E&&(s===E||e);e&&this.element.removeEventListener(this.name,this,s),h&&this.element.addEventListener(this.name,this,t),this._$AH=t;}handleEvent(t){"function"==typeof this._$AH?this._$AH.call(this.options?.host??this.element,t):this._$AH.handleEvent(t);}}class z{constructor(t,i,s){this.element=t,this.type=6,this._$AN=void 0,this._$AM=i,this.options=s;}get _$AU(){return this._$AM._$AU}_$AI(t){S(this,t);}}const j=t$1.litHtmlPolyfillSupport;j?.(N,R),(t$1.litHtmlVersions??=[]).push("3.3.1");const B=(t,i,s)=>{const e=s?.renderBefore??i;let h=e._$litPart$;if(void 0===h){const t=s?.renderBefore??null;e._$litPart$=h=new R(i.insertBefore(l(),t),t,void 0,s??{});}return h._$AI(t),h};
48
+ const t$1=globalThis,i$1=t$1.trustedTypes,s$1=i$1?i$1.createPolicy("lit-html",{createHTML:t=>t}):void 0,e$2="$lit$",h=`lit$${Math.random().toFixed(9).slice(2)}$`,o$2="?"+h,n$1=`<${o$2}>`,r$2=document,l=()=>r$2.createComment(""),c=t=>null===t||"object"!=typeof t&&"function"!=typeof t,a=Array.isArray,u=t=>a(t)||"function"==typeof t?.[Symbol.iterator],d="[ \t\n\f\r]",f=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,v=/-->/g,_=/>/g,m=RegExp(`>|${d}(?:([^\\s"'>=/]+)(${d}*=${d}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),p=/'/g,g=/"/g,$=/^(?:script|style|textarea|title)$/i,y=t=>(i,...s)=>({_$litType$:t,strings:i,values:s}),x=y(1),T=Symbol.for("lit-noChange"),E=Symbol.for("lit-nothing"),A=new WeakMap,C=r$2.createTreeWalker(r$2,129);function P(t,i){if(!a(t)||!t.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==s$1?s$1.createHTML(i):i}const V=(t,i)=>{const s=t.length-1,o=[];let r,l=2===i?"<svg>":3===i?"<math>":"",c=f;for(let i=0;i<s;i++){const s=t[i];let a,u,d=-1,y=0;for(;y<s.length&&(c.lastIndex=y,u=c.exec(s),null!==u);)y=c.lastIndex,c===f?"!--"===u[1]?c=v:void 0!==u[1]?c=_:void 0!==u[2]?($.test(u[2])&&(r=RegExp("</"+u[2],"g")),c=m):void 0!==u[3]&&(c=m):c===m?">"===u[0]?(c=r??f,d=-1):void 0===u[1]?d=-2:(d=c.lastIndex-u[2].length,a=u[1],c=void 0===u[3]?m:'"'===u[3]?g:p):c===g||c===p?c=m:c===v||c===_?c=f:(c=m,r=void 0);const x=c===m&&t[i+1].startsWith("/>")?" ":"";l+=c===f?s+n$1:d>=0?(o.push(a),s.slice(0,d)+e$2+s.slice(d)+h+x):s+h+(-2===d?i:x);}return [P(t,l+(t[s]||"<?>")+(2===i?"</svg>":3===i?"</math>":"")),o]};class N{constructor({strings:t,_$litType$:s},n){let r;this.parts=[];let c=0,a=0;const u=t.length-1,d=this.parts,[f,v]=V(t,s);if(this.el=N.createElement(f,n),C.currentNode=this.el.content,2===s||3===s){const t=this.el.content.firstChild;t.replaceWith(...t.childNodes);}for(;null!==(r=C.nextNode())&&d.length<u;){if(1===r.nodeType){if(r.hasAttributes())for(const t of r.getAttributeNames())if(t.endsWith(e$2)){const i=v[a++],s=r.getAttribute(t).split(h),e=/([.?@])?(.*)/.exec(i);d.push({type:1,index:c,name:e[2],strings:s,ctor:"."===e[1]?H:"?"===e[1]?I:"@"===e[1]?L:k}),r.removeAttribute(t);}else t.startsWith(h)&&(d.push({type:6,index:c}),r.removeAttribute(t));if($.test(r.tagName)){const t=r.textContent.split(h),s=t.length-1;if(s>0){r.textContent=i$1?i$1.emptyScript:"";for(let i=0;i<s;i++)r.append(t[i],l()),C.nextNode(),d.push({type:2,index:++c});r.append(t[s],l());}}}else if(8===r.nodeType)if(r.data===o$2)d.push({type:2,index:c});else {let t=-1;for(;-1!==(t=r.data.indexOf(h,t+1));)d.push({type:7,index:c}),t+=h.length-1;}c++;}}static createElement(t,i){const s=r$2.createElement("template");return s.innerHTML=t,s}}function S(t,i,s=t,e){if(i===T)return i;let h=void 0!==e?s._$Co?.[e]:s._$Cl;const o=c(i)?void 0:i._$litDirective$;return h?.constructor!==o&&(h?._$AO?.(false),void 0===o?h=void 0:(h=new o(t),h._$AT(t,s,e)),void 0!==e?(s._$Co??=[])[e]=h:s._$Cl=h),void 0!==h&&(i=S(t,h._$AS(t,i.values),h,e)),i}class M{constructor(t,i){this._$AV=[],this._$AN=void 0,this._$AD=t,this._$AM=i;}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(t){const{el:{content:i},parts:s}=this._$AD,e=(t?.creationScope??r$2).importNode(i,true);C.currentNode=e;let h=C.nextNode(),o=0,n=0,l=s[0];for(;void 0!==l;){if(o===l.index){let i;2===l.type?i=new R(h,h.nextSibling,this,t):1===l.type?i=new l.ctor(h,l.name,l.strings,this,t):6===l.type&&(i=new z(h,this,t)),this._$AV.push(i),l=s[++n];}o!==l?.index&&(h=C.nextNode(),o++);}return C.currentNode=r$2,e}p(t){let i=0;for(const s of this._$AV) void 0!==s&&(void 0!==s.strings?(s._$AI(t,s,i),i+=s.strings.length-2):s._$AI(t[i])),i++;}}class R{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(t,i,s,e){this.type=2,this._$AH=E,this._$AN=void 0,this._$AA=t,this._$AB=i,this._$AM=s,this.options=e,this._$Cv=e?.isConnected??true;}get parentNode(){let t=this._$AA.parentNode;const i=this._$AM;return void 0!==i&&11===t?.nodeType&&(t=i.parentNode),t}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(t,i=this){t=S(this,t,i),c(t)?t===E||null==t||""===t?(this._$AH!==E&&this._$AR(),this._$AH=E):t!==this._$AH&&t!==T&&this._(t):void 0!==t._$litType$?this.$(t):void 0!==t.nodeType?this.T(t):u(t)?this.k(t):this._(t);}O(t){return this._$AA.parentNode.insertBefore(t,this._$AB)}T(t){this._$AH!==t&&(this._$AR(),this._$AH=this.O(t));}_(t){this._$AH!==E&&c(this._$AH)?this._$AA.nextSibling.data=t:this.T(r$2.createTextNode(t)),this._$AH=t;}$(t){const{values:i,_$litType$:s}=t,e="number"==typeof s?this._$AC(t):(void 0===s.el&&(s.el=N.createElement(P(s.h,s.h[0]),this.options)),s);if(this._$AH?._$AD===e)this._$AH.p(i);else {const t=new M(e,this),s=t.u(this.options);t.p(i),this.T(s),this._$AH=t;}}_$AC(t){let i=A.get(t.strings);return void 0===i&&A.set(t.strings,i=new N(t)),i}k(t){a(this._$AH)||(this._$AH=[],this._$AR());const i=this._$AH;let s,e=0;for(const h of t)e===i.length?i.push(s=new R(this.O(l()),this.O(l()),this,this.options)):s=i[e],s._$AI(h),e++;e<i.length&&(this._$AR(s&&s._$AB.nextSibling,e),i.length=e);}_$AR(t=this._$AA.nextSibling,i){for(this._$AP?.(false,true,i);t!==this._$AB;){const i=t.nextSibling;t.remove(),t=i;}}setConnected(t){ void 0===this._$AM&&(this._$Cv=t,this._$AP?.(t));}}class k{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(t,i,s,e,h){this.type=1,this._$AH=E,this._$AN=void 0,this.element=t,this.name=i,this._$AM=e,this.options=h,s.length>2||""!==s[0]||""!==s[1]?(this._$AH=Array(s.length-1).fill(new String),this.strings=s):this._$AH=E;}_$AI(t,i=this,s,e){const h=this.strings;let o=false;if(void 0===h)t=S(this,t,i,0),o=!c(t)||t!==this._$AH&&t!==T,o&&(this._$AH=t);else {const e=t;let n,r;for(t=h[0],n=0;n<h.length-1;n++)r=S(this,e[s+n],i,n),r===T&&(r=this._$AH[n]),o||=!c(r)||r!==this._$AH[n],r===E?t=E:t!==E&&(t+=(r??"")+h[n+1]),this._$AH[n]=r;}o&&!e&&this.j(t);}j(t){t===E?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,t??"");}}class H extends k{constructor(){super(...arguments),this.type=3;}j(t){this.element[this.name]=t===E?void 0:t;}}class I extends k{constructor(){super(...arguments),this.type=4;}j(t){this.element.toggleAttribute(this.name,!!t&&t!==E);}}class L extends k{constructor(t,i,s,e,h){super(t,i,s,e,h),this.type=5;}_$AI(t,i=this){if((t=S(this,t,i,0)??E)===T)return;const s=this._$AH,e=t===E&&s!==E||t.capture!==s.capture||t.once!==s.once||t.passive!==s.passive,h=t!==E&&(s===E||e);e&&this.element.removeEventListener(this.name,this,s),h&&this.element.addEventListener(this.name,this,t),this._$AH=t;}handleEvent(t){"function"==typeof this._$AH?this._$AH.call(this.options?.host??this.element,t):this._$AH.handleEvent(t);}}class z{constructor(t,i,s){this.element=t,this.type=6,this._$AN=void 0,this._$AM=i,this.options=s;}get _$AU(){return this._$AM._$AU}_$AI(t){S(this,t);}}const j=t$1.litHtmlPolyfillSupport;j?.(N,R),(t$1.litHtmlVersions??=[]).push("3.3.1");const B=(t,i,s)=>{const e=s?.renderBefore??i;let h=e._$litPart$;if(void 0===h){const t=s?.renderBefore??null;e._$litPart$=h=new R(i.insertBefore(l(),t),t,void 0,s??{});}return h._$AI(t),h};
49
49
 
50
50
  /**
51
51
  * @license
@@ -64,33 +64,26 @@ const t=t=>(e,o)=>{ void 0!==o?o.addInitializer((()=>{customElements.define(t,e)
64
64
  * @license
65
65
  * Copyright 2017 Google LLC
66
66
  * SPDX-License-Identifier: BSD-3-Clause
67
- */const o={attribute:true,type:String,converter:u$1,reflect:false,hasChanged:f$1},r$2=(t=o,e,r)=>{const{kind:n,metadata:i}=r;let s=globalThis.litPropertyMetadata.get(i);if(void 0===s&&globalThis.litPropertyMetadata.set(i,s=new Map),"setter"===n&&((t=Object.create(t)).wrapped=true),s.set(r.name,t),"accessor"===n){const{name:o}=r;return {set(r){const n=e.get.call(this);e.set.call(this,r),this.requestUpdate(o,n,t);},init(e){return void 0!==e&&this.C(o,void 0,t,e),e}}}if("setter"===n){const{name:o}=r;return function(r){const n=this[o];e.call(this,r),this.requestUpdate(o,n,t);}}throw Error("Unsupported decorator location: "+n)};function n(t){return (e,o)=>"object"==typeof o?r$2(t,e,o):((t,e,o)=>{const r=e.hasOwnProperty(o);return e.constructor.createProperty(o,t),r?Object.getOwnPropertyDescriptor(e,o):void 0})(t,e,o)}
67
+ */const o={attribute:true,type:String,converter:u$1,reflect:false,hasChanged:f$1},r$1=(t=o,e,r)=>{const{kind:n,metadata:i}=r;let s=globalThis.litPropertyMetadata.get(i);if(void 0===s&&globalThis.litPropertyMetadata.set(i,s=new Map),"setter"===n&&((t=Object.create(t)).wrapped=true),s.set(r.name,t),"accessor"===n){const{name:o}=r;return {set(r){const n=e.get.call(this);e.set.call(this,r),this.requestUpdate(o,n,t);},init(e){return void 0!==e&&this.C(o,void 0,t,e),e}}}if("setter"===n){const{name:o}=r;return function(r){const n=this[o];e.call(this,r),this.requestUpdate(o,n,t);}}throw Error("Unsupported decorator location: "+n)};function n(t){return (e,o)=>"object"==typeof o?r$1(t,e,o):((t,e,o)=>{const r=e.hasOwnProperty(o);return e.constructor.createProperty(o,t),r?Object.getOwnPropertyDescriptor(e,o):void 0})(t,e,o)}
68
68
 
69
69
  /**
70
70
  * @license
71
71
  * Copyright 2017 Google LLC
72
72
  * SPDX-License-Identifier: BSD-3-Clause
73
- */function r$1(r){return n({...r,state:true,attribute:false})}
73
+ */function r(r){return n({...r,state:true,attribute:false})}
74
74
 
75
75
  /**
76
76
  * @license
77
77
  * Copyright 2017 Google LLC
78
78
  * SPDX-License-Identifier: BSD-3-Clause
79
79
  */
80
- const e$2=(e,t,c)=>(c.configurable=true,c.enumerable=true,Reflect.decorate&&"object"!=typeof t&&Object.defineProperty(e,t,c),c);
80
+ const e$1=(e,t,c)=>(c.configurable=true,c.enumerable=true,Reflect.decorate&&"object"!=typeof t&&Object.defineProperty(e,t,c),c);
81
81
 
82
82
  /**
83
83
  * @license
84
84
  * Copyright 2017 Google LLC
85
85
  * SPDX-License-Identifier: BSD-3-Clause
86
- */function e$1(e,r){return (n,s,i)=>{const o=t=>t.renderRoot?.querySelector(e)??null;return e$2(n,s,{get(){return o(this)}})}}
87
-
88
- /**
89
- * @license
90
- * Copyright 2017 Google LLC
91
- * SPDX-License-Identifier: BSD-3-Clause
92
- */
93
- let e;function r(r){return (n,o)=>e$2(n,o,{get(){return (this.renderRoot??(e??=document.createDocumentFragment())).querySelectorAll(r)}})}
86
+ */function e(e,r){return (n,s,i)=>{const o=t=>t.renderRoot?.querySelector(e)??null;return e$1(n,s,{get(){return o(this)}})}}
94
87
 
95
88
  // static class that encapsulates shorthands and utilities for emitting events.
96
89
  class EventHelpers {
@@ -475,9 +468,6 @@ class AdsTable extends i {
475
468
  this.selectedRowIds = [];
476
469
  this.isLoading = false;
477
470
  }
478
- getTableRowElementById(id) {
479
- return Array.from(this.tableRows || []).find((row) => row.id === `row-${id}`);
480
- }
481
471
  updated(changedProperties) {
482
472
  super.updated(changedProperties);
483
473
  if (changedProperties.has("selectedRowIds")) {
@@ -706,7 +696,21 @@ class AdsTable extends i {
706
696
  return this.onUpDownArrowKey(event);
707
697
  }
708
698
  }
709
- // listener applies when column has focus
699
+ // listener applies only after table has focus
700
+ onTableKeyDown(event) {
701
+ if (this.disableKeyboardNavigation) {
702
+ return;
703
+ }
704
+ // on esc or delete, emit an event
705
+ switch (event.key) {
706
+ case "Escape":
707
+ return this.emitEvent("table-navigate-back");
708
+ case "Backspace":
709
+ return this.emitEvent("table-navigate-back");
710
+ }
711
+ }
712
+ // listener applies when column has focus - does nothing since
713
+ // column header cannot get focus right now.
710
714
  onColumnKeyDown(event, column) {
711
715
  if (this.disableKeyboardNavigation) {
712
716
  return;
@@ -735,21 +739,22 @@ class AdsTable extends i {
735
739
  }
736
740
  }
737
741
  }
738
- onUpDownArrowKey(event) {
742
+ focusTableElement() {
739
743
  var _a;
744
+ (_a = this.tableElement) === null || _a === void 0 ? void 0 : _a.focus();
745
+ }
746
+ onUpDownArrowKey(event) {
740
747
  if (this.rows.length === 0) {
741
748
  // there are no rows to navigate or select with arrows. avoids array out of bounds.
742
749
  return;
743
750
  }
751
+ // focus the main table element with each arrow key press
752
+ this.focusTableElement();
744
753
  const indexOffset = event.key === "ArrowUp" ? -1 : 1;
745
754
  const newSelectedRowIndex = this.constrainIndex(this.indexOfLastSelectedRow + indexOffset);
746
755
  const newSelectedRowId = this.rows[newSelectedRowIndex].id;
747
- if (event.shiftKey) {
748
- // - focus and (maybe) select and focus the prev or next, if it exists
749
- this.groupRowSelect(newSelectedRowIndex);
750
- }
751
- else if (this.selectedRowIds.length === 0) {
752
- // select the first row if none are selected
756
+ if (this.selectedRowIds.length === 0) {
757
+ // if none are selected, select the first row
753
758
  const firstRowId = this.rows[0] ? this.rows[0].id : undefined;
754
759
  if (firstRowId) {
755
760
  this.selectedRowIds = [firstRowId];
@@ -759,8 +764,6 @@ class AdsTable extends i {
759
764
  // offset in the proper direction of the arrow
760
765
  this.selectedRowIds = [newSelectedRowId];
761
766
  }
762
- // always try to focus the next element in the direction of the arrow if you can
763
- (_a = this.getTableRowElementById(newSelectedRowId)) === null || _a === void 0 ? void 0 : _a.focus();
764
767
  }
765
768
  // ensures index values are kept to the closest in-bounds index
766
769
  constrainIndex(index) {
@@ -773,16 +776,22 @@ class AdsTable extends i {
773
776
  }
774
777
  render() {
775
778
  return x `
776
- <table id="main-table">
779
+ <table
780
+ tabindex="0"
781
+ role="treegrid"
782
+ id="main-table"
783
+ @keydown=${(e) => this.onTableKeyDown(e)}
784
+ >
777
785
  <thead>
778
- <tr>
786
+ <tr role="row">
779
787
  ${this.visibleColumns.map((column) => x `
780
788
  <th
789
+ role="gridcell"
790
+ aria-label=${column.label}
781
791
  @click=${() => this.onColumnClick(column)}
782
792
  @keydown=${(e) => this.onColumnKeyDown(e, column)}
783
793
  class=${column.dataType.compare ? "sortable" : ""}
784
794
  style=${`flex: ${column.flexRatio}`}
785
- tabindex="0"
786
795
  >
787
796
  ${column.label}
788
797
  ${column.dataType.compare
@@ -796,31 +805,35 @@ class AdsTable extends i {
796
805
  ${!this.isLoading
797
806
  ? this.sortedRows.map((row, index) => x `
798
807
  <tr
808
+ role="row"
799
809
  @click=${(e) => this.onRowClick(e, row, index)}
800
810
  @dblclick=${() => this.onRowDoubleClick(row)}
801
811
  @keydown=${(e) => this.onRowKeyDown(e, row, index)}
802
812
  class=${this.isSelected(row) ? "row-selected" : ""}
813
+ aria-selected=${this.isSelected(row)}
803
814
  data-row-selected=${this.isSelected(row)}
804
815
  data-id=${row.id}
805
816
  id=${"row-" + row.id}
806
- tabindex="0"
807
817
  >
808
818
  ${this.visibleColumns.map((column) => x `
809
- <td style=${`flex: ${column.flexRatio}`}>
819
+ <td
820
+ role="gridcell"
821
+ style=${`flex: ${column.flexRatio}`}
822
+ >
810
823
  ${column.dataType.format(row.data)}
811
824
  </td>
812
825
  `)}
813
826
  </tr>
814
827
  `)
815
828
  : x `
816
- <tr>
817
- <td class="no-data">Loading...</td>
829
+ <tr role="row">
830
+ <td role="gridcell" class="no-data">Loading...</td>
818
831
  </tr>
819
832
  `}
820
833
  ${!this.isLoading && this.sortedRows.length === 0
821
834
  ? x `
822
- <tr>
823
- <td class="no-data">${this.noDataText}</td>
835
+ <tr role="row">
836
+ <td role="gridcell" class="no-data">${this.noDataText}</td>
824
837
  </tr>
825
838
  `
826
839
  : null}
@@ -903,11 +916,8 @@ AdsTable.styles = i$3 `
903
916
  }
904
917
  `;
905
918
  __decorate([
906
- e$1("#main-table")
919
+ e("#main-table")
907
920
  ], AdsTable.prototype, "tableElement", void 0);
908
- __decorate([
909
- r("table tr")
910
- ], AdsTable.prototype, "tableRows", void 0);
911
921
  __decorate([
912
922
  n({ type: Array })
913
923
  ], AdsTable.prototype, "rows", void 0);
@@ -915,13 +925,13 @@ __decorate([
915
925
  n({ type: Boolean })
916
926
  ], AdsTable.prototype, "disableKeyboardNavigation", void 0);
917
927
  __decorate([
918
- r$1()
928
+ r()
919
929
  ], AdsTable.prototype, "sortDirection", void 0);
920
930
  __decorate([
921
- r$1()
931
+ r()
922
932
  ], AdsTable.prototype, "selectedRowIds", void 0);
923
933
  __decorate([
924
- r$1()
934
+ r()
925
935
  ], AdsTable.prototype, "isLoading", void 0);
926
936
  // a simple, generic, out-of-the box implementation of AdsTable
927
937
  let AdsSimpleTable = class AdsSimpleTable extends AdsTable {
@@ -949,7 +959,7 @@ __decorate([
949
959
  n({ type: String })
950
960
  ], AdsSimpleTable.prototype, "secondarySortKey", void 0);
951
961
  __decorate([
952
- r$1()
962
+ r()
953
963
  ], AdsSimpleTable.prototype, "sortKey", void 0);
954
964
  AdsSimpleTable = __decorate([
955
965
  t("ads-simple-table")