@tartaguti/ui-components 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/LICENSE +21 -0
- package/README.md +192 -2
- package/THIRD-PARTY-NOTICES.md +29 -0
- package/custom-elements.json +16899 -0
- package/dist/accordion/tt-accordion-item.d.ts +32 -0
- package/dist/accordion/tt-accordion-item.d.ts.map +1 -0
- package/dist/accordion/tt-accordion-item.js +247 -0
- package/dist/accordion/tt-accordion-item.js.map +1 -0
- package/dist/accordion/tt-accordion.d.ts +28 -0
- package/dist/accordion/tt-accordion.d.ts.map +1 -0
- package/dist/accordion/tt-accordion.js +148 -0
- package/dist/accordion/tt-accordion.js.map +1 -0
- package/dist/bento/tt-bento-item.d.ts +35 -0
- package/dist/bento/tt-bento-item.d.ts.map +1 -0
- package/dist/bento/tt-bento-item.js +201 -0
- package/dist/bento/tt-bento-item.js.map +1 -0
- package/dist/bento/tt-bento.d.ts +25 -0
- package/dist/bento/tt-bento.d.ts.map +1 -0
- package/dist/bento/tt-bento.js +314 -0
- package/dist/bento/tt-bento.js.map +1 -0
- package/dist/floating.d.ts +61 -0
- package/dist/floating.d.ts.map +1 -0
- package/dist/floating.js +120 -0
- package/dist/floating.js.map +1 -0
- package/dist/index.d.ts +92 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +96 -0
- package/dist/index.js.map +1 -0
- package/dist/interaction/tt-draggable.d.ts +29 -0
- package/dist/interaction/tt-draggable.d.ts.map +1 -0
- package/dist/interaction/tt-draggable.js +66 -0
- package/dist/interaction/tt-draggable.js.map +1 -0
- package/dist/interaction/tt-droppable.d.ts +37 -0
- package/dist/interaction/tt-droppable.d.ts.map +1 -0
- package/dist/interaction/tt-droppable.js +108 -0
- package/dist/interaction/tt-droppable.js.map +1 -0
- package/dist/interaction/tt-resizable.d.ts +45 -0
- package/dist/interaction/tt-resizable.d.ts.map +1 -0
- package/dist/interaction/tt-resizable.js +210 -0
- package/dist/interaction/tt-resizable.js.map +1 -0
- package/dist/interaction/tt-reveal.d.ts +54 -0
- package/dist/interaction/tt-reveal.d.ts.map +1 -0
- package/dist/interaction/tt-reveal.js +302 -0
- package/dist/interaction/tt-reveal.js.map +1 -0
- package/dist/motion.d.ts +8 -0
- package/dist/motion.d.ts.map +1 -0
- package/dist/motion.js +49 -0
- package/dist/motion.js.map +1 -0
- package/dist/overlay.d.ts +7 -0
- package/dist/overlay.d.ts.map +1 -0
- package/dist/overlay.js +121 -0
- package/dist/overlay.js.map +1 -0
- package/dist/safe-url.d.ts +14 -0
- package/dist/safe-url.d.ts.map +1 -0
- package/dist/safe-url.js +46 -0
- package/dist/safe-url.js.map +1 -0
- package/dist/scroll-lock.d.ts +22 -0
- package/dist/scroll-lock.d.ts.map +1 -0
- package/dist/scroll-lock.js +56 -0
- package/dist/scroll-lock.js.map +1 -0
- package/dist/sidebar/tt-menu-group.d.ts +69 -0
- package/dist/sidebar/tt-menu-group.d.ts.map +1 -0
- package/dist/sidebar/tt-menu-group.js +358 -0
- package/dist/sidebar/tt-menu-group.js.map +1 -0
- package/dist/sidebar/tt-menu-item.d.ts +70 -0
- package/dist/sidebar/tt-menu-item.d.ts.map +1 -0
- package/dist/sidebar/tt-menu-item.js +502 -0
- package/dist/sidebar/tt-menu-item.js.map +1 -0
- package/dist/sidebar/tt-sidebar-footer.d.ts +39 -0
- package/dist/sidebar/tt-sidebar-footer.d.ts.map +1 -0
- package/dist/sidebar/tt-sidebar-footer.js +205 -0
- package/dist/sidebar/tt-sidebar-footer.js.map +1 -0
- package/dist/sidebar/tt-sidebar-header.d.ts +31 -0
- package/dist/sidebar/tt-sidebar-header.d.ts.map +1 -0
- package/dist/sidebar/tt-sidebar-header.js +150 -0
- package/dist/sidebar/tt-sidebar-header.js.map +1 -0
- package/dist/sidebar/tt-sidebar.d.ts +72 -0
- package/dist/sidebar/tt-sidebar.d.ts.map +1 -0
- package/dist/sidebar/tt-sidebar.js +539 -0
- package/dist/sidebar/tt-sidebar.js.map +1 -0
- package/dist/sr-only.d.ts +15 -0
- package/dist/sr-only.d.ts.map +1 -0
- package/dist/sr-only.js +27 -0
- package/dist/sr-only.js.map +1 -0
- package/dist/tokens.css +1124 -0
- package/dist/tt-alert.d.ts +26 -0
- package/dist/tt-alert.d.ts.map +1 -0
- package/dist/tt-alert.js +165 -0
- package/dist/tt-alert.js.map +1 -0
- package/dist/tt-aspect-ratio.d.ts +40 -0
- package/dist/tt-aspect-ratio.d.ts.map +1 -0
- package/dist/tt-aspect-ratio.js +98 -0
- package/dist/tt-aspect-ratio.js.map +1 -0
- package/dist/tt-auth.d.ts +75 -0
- package/dist/tt-auth.d.ts.map +1 -0
- package/dist/tt-auth.js +520 -0
- package/dist/tt-auth.js.map +1 -0
- package/dist/tt-avatar.d.ts +26 -0
- package/dist/tt-avatar.d.ts.map +1 -0
- package/dist/tt-avatar.js +169 -0
- package/dist/tt-avatar.js.map +1 -0
- package/dist/tt-badge.d.ts +36 -0
- package/dist/tt-badge.d.ts.map +1 -0
- package/dist/tt-badge.js +135 -0
- package/dist/tt-badge.js.map +1 -0
- package/dist/tt-breadcrumbs.d.ts +22 -0
- package/dist/tt-breadcrumbs.d.ts.map +1 -0
- package/dist/tt-breadcrumbs.js +144 -0
- package/dist/tt-breadcrumbs.js.map +1 -0
- package/dist/tt-button-group.d.ts +32 -0
- package/dist/tt-button-group.d.ts.map +1 -0
- package/dist/tt-button-group.js +132 -0
- package/dist/tt-button-group.js.map +1 -0
- package/dist/tt-button.d.ts +31 -0
- package/dist/tt-button.d.ts.map +1 -0
- package/dist/tt-button.js +483 -0
- package/dist/tt-button.js.map +1 -0
- package/dist/tt-card.d.ts +26 -0
- package/dist/tt-card.d.ts.map +1 -0
- package/dist/tt-card.js +429 -0
- package/dist/tt-card.js.map +1 -0
- package/dist/tt-chart.d.ts +36 -0
- package/dist/tt-chart.d.ts.map +1 -0
- package/dist/tt-chart.js +332 -0
- package/dist/tt-chart.js.map +1 -0
- package/dist/tt-checkbox-group.d.ts +38 -0
- package/dist/tt-checkbox-group.d.ts.map +1 -0
- package/dist/tt-checkbox-group.js +243 -0
- package/dist/tt-checkbox-group.js.map +1 -0
- package/dist/tt-checkbox.d.ts +35 -0
- package/dist/tt-checkbox.d.ts.map +1 -0
- package/dist/tt-checkbox.js +354 -0
- package/dist/tt-checkbox.js.map +1 -0
- package/dist/tt-code-block.d.ts +37 -0
- package/dist/tt-code-block.d.ts.map +1 -0
- package/dist/tt-code-block.js +409 -0
- package/dist/tt-code-block.js.map +1 -0
- package/dist/tt-collapsible.d.ts +71 -0
- package/dist/tt-collapsible.d.ts.map +1 -0
- package/dist/tt-collapsible.js +206 -0
- package/dist/tt-collapsible.js.map +1 -0
- package/dist/tt-combobox.d.ts +107 -0
- package/dist/tt-combobox.d.ts.map +1 -0
- package/dist/tt-combobox.js +816 -0
- package/dist/tt-combobox.js.map +1 -0
- package/dist/tt-company-card.d.ts +30 -0
- package/dist/tt-company-card.d.ts.map +1 -0
- package/dist/tt-company-card.js +382 -0
- package/dist/tt-company-card.js.map +1 -0
- package/dist/tt-comparison-table.d.ts +59 -0
- package/dist/tt-comparison-table.d.ts.map +1 -0
- package/dist/tt-comparison-table.js +441 -0
- package/dist/tt-comparison-table.js.map +1 -0
- package/dist/tt-component-doc.d.ts +63 -0
- package/dist/tt-component-doc.d.ts.map +1 -0
- package/dist/tt-component-doc.js +585 -0
- package/dist/tt-component-doc.js.map +1 -0
- package/dist/tt-confirm.d.ts +45 -0
- package/dist/tt-confirm.d.ts.map +1 -0
- package/dist/tt-confirm.js +151 -0
- package/dist/tt-confirm.js.map +1 -0
- package/dist/tt-contact-list.d.ts +18 -0
- package/dist/tt-contact-list.d.ts.map +1 -0
- package/dist/tt-contact-list.js +101 -0
- package/dist/tt-contact-list.js.map +1 -0
- package/dist/tt-copy-button.d.ts +25 -0
- package/dist/tt-copy-button.d.ts.map +1 -0
- package/dist/tt-copy-button.js +194 -0
- package/dist/tt-copy-button.js.map +1 -0
- package/dist/tt-data-table.d.ts +96 -0
- package/dist/tt-data-table.d.ts.map +1 -0
- package/dist/tt-data-table.js +812 -0
- package/dist/tt-data-table.js.map +1 -0
- package/dist/tt-divider.d.ts +19 -0
- package/dist/tt-divider.d.ts.map +1 -0
- package/dist/tt-divider.js +104 -0
- package/dist/tt-divider.js.map +1 -0
- package/dist/tt-drawer.d.ts +38 -0
- package/dist/tt-drawer.d.ts.map +1 -0
- package/dist/tt-drawer.js +433 -0
- package/dist/tt-drawer.js.map +1 -0
- package/dist/tt-dropdown-menu.d.ts +57 -0
- package/dist/tt-dropdown-menu.d.ts.map +1 -0
- package/dist/tt-dropdown-menu.js +631 -0
- package/dist/tt-dropdown-menu.js.map +1 -0
- package/dist/tt-empty-state.d.ts +13 -0
- package/dist/tt-empty-state.d.ts.map +1 -0
- package/dist/tt-empty-state.js +94 -0
- package/dist/tt-empty-state.js.map +1 -0
- package/dist/tt-example.d.ts +33 -0
- package/dist/tt-example.d.ts.map +1 -0
- package/dist/tt-example.js +250 -0
- package/dist/tt-example.js.map +1 -0
- package/dist/tt-file-upload.d.ts +85 -0
- package/dist/tt-file-upload.d.ts.map +1 -0
- package/dist/tt-file-upload.js +662 -0
- package/dist/tt-file-upload.js.map +1 -0
- package/dist/tt-filter.d.ts +62 -0
- package/dist/tt-filter.d.ts.map +1 -0
- package/dist/tt-filter.js +393 -0
- package/dist/tt-filter.js.map +1 -0
- package/dist/tt-form.d.ts +33 -0
- package/dist/tt-form.d.ts.map +1 -0
- package/dist/tt-form.js +202 -0
- package/dist/tt-form.js.map +1 -0
- package/dist/tt-grid.d.ts +22 -0
- package/dist/tt-grid.d.ts.map +1 -0
- package/dist/tt-grid.js +106 -0
- package/dist/tt-grid.js.map +1 -0
- package/dist/tt-icon.d.ts +20 -0
- package/dist/tt-icon.d.ts.map +1 -0
- package/dist/tt-icon.js +510 -0
- package/dist/tt-icon.js.map +1 -0
- package/dist/tt-image.d.ts +59 -0
- package/dist/tt-image.d.ts.map +1 -0
- package/dist/tt-image.js +314 -0
- package/dist/tt-image.js.map +1 -0
- package/dist/tt-inbox.d.ts +45 -0
- package/dist/tt-inbox.d.ts.map +1 -0
- package/dist/tt-inbox.js +275 -0
- package/dist/tt-inbox.js.map +1 -0
- package/dist/tt-input.d.ts +43 -0
- package/dist/tt-input.d.ts.map +1 -0
- package/dist/tt-input.js +476 -0
- package/dist/tt-input.js.map +1 -0
- package/dist/tt-kbd.d.ts +39 -0
- package/dist/tt-kbd.d.ts.map +1 -0
- package/dist/tt-kbd.js +145 -0
- package/dist/tt-kbd.js.map +1 -0
- package/dist/tt-key-values.d.ts +17 -0
- package/dist/tt-key-values.d.ts.map +1 -0
- package/dist/tt-key-values.js +126 -0
- package/dist/tt-key-values.js.map +1 -0
- package/dist/tt-knowledge-doc.d.ts +24 -0
- package/dist/tt-knowledge-doc.d.ts.map +1 -0
- package/dist/tt-knowledge-doc.js +120 -0
- package/dist/tt-knowledge-doc.js.map +1 -0
- package/dist/tt-layout.d.ts +36 -0
- package/dist/tt-layout.d.ts.map +1 -0
- package/dist/tt-layout.js +318 -0
- package/dist/tt-layout.js.map +1 -0
- package/dist/tt-modal.d.ts +32 -0
- package/dist/tt-modal.d.ts.map +1 -0
- package/dist/tt-modal.js +553 -0
- package/dist/tt-modal.js.map +1 -0
- package/dist/tt-navbar.d.ts +33 -0
- package/dist/tt-navbar.d.ts.map +1 -0
- package/dist/tt-navbar.js +390 -0
- package/dist/tt-navbar.js.map +1 -0
- package/dist/tt-page-header.d.ts +28 -0
- package/dist/tt-page-header.d.ts.map +1 -0
- package/dist/tt-page-header.js +166 -0
- package/dist/tt-page-header.js.map +1 -0
- package/dist/tt-page.d.ts +14 -0
- package/dist/tt-page.d.ts.map +1 -0
- package/dist/tt-page.js +163 -0
- package/dist/tt-page.js.map +1 -0
- package/dist/tt-pagination.d.ts +27 -0
- package/dist/tt-pagination.d.ts.map +1 -0
- package/dist/tt-pagination.js +194 -0
- package/dist/tt-pagination.js.map +1 -0
- package/dist/tt-preview.d.ts +11 -0
- package/dist/tt-preview.d.ts.map +1 -0
- package/dist/tt-preview.js +68 -0
- package/dist/tt-preview.js.map +1 -0
- package/dist/tt-product.d.ts +40 -0
- package/dist/tt-product.d.ts.map +1 -0
- package/dist/tt-product.js +590 -0
- package/dist/tt-product.js.map +1 -0
- package/dist/tt-profile-card.d.ts +23 -0
- package/dist/tt-profile-card.d.ts.map +1 -0
- package/dist/tt-profile-card.js +199 -0
- package/dist/tt-profile-card.js.map +1 -0
- package/dist/tt-progress.d.ts +26 -0
- package/dist/tt-progress.d.ts.map +1 -0
- package/dist/tt-progress.js +156 -0
- package/dist/tt-progress.js.map +1 -0
- package/dist/tt-quantity.d.ts +36 -0
- package/dist/tt-quantity.d.ts.map +1 -0
- package/dist/tt-quantity.js +396 -0
- package/dist/tt-quantity.js.map +1 -0
- package/dist/tt-radio-group.d.ts +50 -0
- package/dist/tt-radio-group.d.ts.map +1 -0
- package/dist/tt-radio-group.js +372 -0
- package/dist/tt-radio-group.js.map +1 -0
- package/dist/tt-rating.d.ts +54 -0
- package/dist/tt-rating.d.ts.map +1 -0
- package/dist/tt-rating.js +312 -0
- package/dist/tt-rating.js.map +1 -0
- package/dist/tt-search.d.ts +47 -0
- package/dist/tt-search.d.ts.map +1 -0
- package/dist/tt-search.js +360 -0
- package/dist/tt-search.js.map +1 -0
- package/dist/tt-section.d.ts +13 -0
- package/dist/tt-section.d.ts.map +1 -0
- package/dist/tt-section.js +98 -0
- package/dist/tt-section.js.map +1 -0
- package/dist/tt-select.d.ts +62 -0
- package/dist/tt-select.d.ts.map +1 -0
- package/dist/tt-select.js +662 -0
- package/dist/tt-select.js.map +1 -0
- package/dist/tt-skeleton.d.ts +20 -0
- package/dist/tt-skeleton.d.ts.map +1 -0
- package/dist/tt-skeleton.js +143 -0
- package/dist/tt-skeleton.js.map +1 -0
- package/dist/tt-slider.d.ts +74 -0
- package/dist/tt-slider.d.ts.map +1 -0
- package/dist/tt-slider.js +426 -0
- package/dist/tt-slider.js.map +1 -0
- package/dist/tt-social-links.d.ts +34 -0
- package/dist/tt-social-links.d.ts.map +1 -0
- package/dist/tt-social-links.js +242 -0
- package/dist/tt-social-links.js.map +1 -0
- package/dist/tt-sparkline.d.ts +19 -0
- package/dist/tt-sparkline.d.ts.map +1 -0
- package/dist/tt-sparkline.js +191 -0
- package/dist/tt-sparkline.js.map +1 -0
- package/dist/tt-spinner.d.ts +19 -0
- package/dist/tt-spinner.d.ts.map +1 -0
- package/dist/tt-spinner.js +93 -0
- package/dist/tt-spinner.js.map +1 -0
- package/dist/tt-stack.d.ts +42 -0
- package/dist/tt-stack.d.ts.map +1 -0
- package/dist/tt-stack.js +158 -0
- package/dist/tt-stack.js.map +1 -0
- package/dist/tt-stat.d.ts +17 -0
- package/dist/tt-stat.d.ts.map +1 -0
- package/dist/tt-stat.js +134 -0
- package/dist/tt-stat.js.map +1 -0
- package/dist/tt-switch.d.ts +39 -0
- package/dist/tt-switch.d.ts.map +1 -0
- package/dist/tt-switch.js +254 -0
- package/dist/tt-switch.js.map +1 -0
- package/dist/tt-switcher.d.ts +23 -0
- package/dist/tt-switcher.d.ts.map +1 -0
- package/dist/tt-switcher.js +203 -0
- package/dist/tt-switcher.js.map +1 -0
- package/dist/tt-table-cell.d.ts +26 -0
- package/dist/tt-table-cell.d.ts.map +1 -0
- package/dist/tt-table-cell.js +121 -0
- package/dist/tt-table-cell.js.map +1 -0
- package/dist/tt-table-row.d.ts +31 -0
- package/dist/tt-table-row.d.ts.map +1 -0
- package/dist/tt-table-row.js +72 -0
- package/dist/tt-table-row.js.map +1 -0
- package/dist/tt-table.d.ts +44 -0
- package/dist/tt-table.d.ts.map +1 -0
- package/dist/tt-table.js +270 -0
- package/dist/tt-table.js.map +1 -0
- package/dist/tt-tabs.d.ts +31 -0
- package/dist/tt-tabs.d.ts.map +1 -0
- package/dist/tt-tabs.js +223 -0
- package/dist/tt-tabs.js.map +1 -0
- package/dist/tt-tag-list.d.ts +19 -0
- package/dist/tt-tag-list.d.ts.map +1 -0
- package/dist/tt-tag-list.js +136 -0
- package/dist/tt-tag-list.js.map +1 -0
- package/dist/tt-text.d.ts +52 -0
- package/dist/tt-text.d.ts.map +1 -0
- package/dist/tt-text.js +337 -0
- package/dist/tt-text.js.map +1 -0
- package/dist/tt-textarea.d.ts +43 -0
- package/dist/tt-textarea.d.ts.map +1 -0
- package/dist/tt-textarea.js +356 -0
- package/dist/tt-textarea.js.map +1 -0
- package/dist/tt-thread.d.ts +62 -0
- package/dist/tt-thread.d.ts.map +1 -0
- package/dist/tt-thread.js +374 -0
- package/dist/tt-thread.js.map +1 -0
- package/dist/tt-toast.d.ts +49 -0
- package/dist/tt-toast.d.ts.map +1 -0
- package/dist/tt-toast.js +440 -0
- package/dist/tt-toast.js.map +1 -0
- package/dist/tt-toggle-group.d.ts +73 -0
- package/dist/tt-toggle-group.d.ts.map +1 -0
- package/dist/tt-toggle-group.js +273 -0
- package/dist/tt-toggle-group.js.map +1 -0
- package/dist/tt-toggle.d.ts +54 -0
- package/dist/tt-toggle.d.ts.map +1 -0
- package/dist/tt-toggle.js +232 -0
- package/dist/tt-toggle.js.map +1 -0
- package/dist/tt-toolbar.d.ts +26 -0
- package/dist/tt-toolbar.d.ts.map +1 -0
- package/dist/tt-toolbar.js +164 -0
- package/dist/tt-toolbar.js.map +1 -0
- package/dist/tt-tooltip.d.ts +42 -0
- package/dist/tt-tooltip.d.ts.map +1 -0
- package/dist/tt-tooltip.js +299 -0
- package/dist/tt-tooltip.js.map +1 -0
- package/package.json +84 -4
- package/vscode.html-custom-data.json +2911 -0
|
@@ -0,0 +1,812 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { LitElement, html, css } from "lit";
|
|
8
|
+
import { customElement, property, query, state } from "lit/decorators.js";
|
|
9
|
+
import { ifDefined } from "lit/directives/if-defined.js";
|
|
10
|
+
import { repeat } from "lit/directives/repeat.js";
|
|
11
|
+
import "./tt-checkbox.js";
|
|
12
|
+
import "./tt-skeleton.js";
|
|
13
|
+
import "./tt-empty-state.js";
|
|
14
|
+
import "./tt-dropdown-menu.js";
|
|
15
|
+
import "./tt-icon.js";
|
|
16
|
+
import { srOnly } from "./sr-only.js";
|
|
17
|
+
/*
|
|
18
|
+
Rows kept in the page above and below the visible ones while
|
|
19
|
+
virtualized, so a fast scroll or a Tab to the next row lands on a row
|
|
20
|
+
that already exists instead of a blank.
|
|
21
|
+
*/
|
|
22
|
+
const OVERSCAN = 5;
|
|
23
|
+
/** A row's height before the first one is measured: the default density. */
|
|
24
|
+
const ROW_ESTIMATE = 49;
|
|
25
|
+
/**
|
|
26
|
+
* Working table: sorting, selection, row actions, sticky header, and
|
|
27
|
+
* loading and empty states. With visible-rows it is virtualized: a box
|
|
28
|
+
* that many rows tall, holding only the rows in view, so ten thousand
|
|
29
|
+
* rows scroll as smoothly as ten.
|
|
30
|
+
*
|
|
31
|
+
* It owns nothing. Sort state and selection come in as properties and
|
|
32
|
+
* changes go out as events, so the page stays the single source of truth
|
|
33
|
+
* and can put either in a URL. Sorting itself is the page's job too: it
|
|
34
|
+
* knows whether the data is an in-memory array or a server query.
|
|
35
|
+
*/
|
|
36
|
+
let TTDataTable = class TTDataTable extends LitElement {
|
|
37
|
+
constructor() {
|
|
38
|
+
super(...arguments);
|
|
39
|
+
this.columns = [];
|
|
40
|
+
this.rows = [];
|
|
41
|
+
/*
|
|
42
|
+
The table's name for screen readers, announced on entering it
|
|
43
|
+
("Team members, table"). Same word and job as tt-table's label. A
|
|
44
|
+
heading above the table names it for sighted readers only.
|
|
45
|
+
*/
|
|
46
|
+
this.label = "";
|
|
47
|
+
this.selectable = false;
|
|
48
|
+
this.selected = [];
|
|
49
|
+
// Same menu on every row. Leave empty for no actions column.
|
|
50
|
+
this.rowActions = [];
|
|
51
|
+
this.loading = false;
|
|
52
|
+
this.loadingRows = 5;
|
|
53
|
+
this.emptyHeading = "Nothing here yet";
|
|
54
|
+
this.emptyDescription = "";
|
|
55
|
+
// Rows respond to clicks. Only set this when there is somewhere to go.
|
|
56
|
+
this.clickableRows = false;
|
|
57
|
+
/*
|
|
58
|
+
How many rows tall the table is, as a box that scrolls. Only the rows
|
|
59
|
+
in view (plus a few spare) exist in the page, so the cost of a scroll
|
|
60
|
+
stays the same at 10,000 rows as at 10. 0, the default, shows every
|
|
61
|
+
row as a plain table.
|
|
62
|
+
|
|
63
|
+
Virtualized rows need one height each, so their cells stay on one
|
|
64
|
+
line and long values end in an ellipsis.
|
|
65
|
+
*/
|
|
66
|
+
this.visibleRows = 0;
|
|
67
|
+
// The row at the top of the scroll box, from its scroll position.
|
|
68
|
+
this.firstInView = 0;
|
|
69
|
+
// Measured from the rendered page, so density, touch and themes all count.
|
|
70
|
+
this.rowHeight = 0;
|
|
71
|
+
this.headerHeight = 0;
|
|
72
|
+
/*
|
|
73
|
+
Column widths, measured once and then fixed. A table sizes columns
|
|
74
|
+
from the rows it holds, and a virtualized one holds different rows at
|
|
75
|
+
every scroll, so unfixed columns would jump sideways while scrolling.
|
|
76
|
+
|
|
77
|
+
A table that fits its box keeps them as shares (%), so it still fits
|
|
78
|
+
when the box narrows. One wider than its box keeps pixels and scrolls
|
|
79
|
+
sideways, as the plain table does, rather than squeezing every column
|
|
80
|
+
into an ellipsis on a phone.
|
|
81
|
+
*/
|
|
82
|
+
this.columnWidths = [];
|
|
83
|
+
this.widthUnit = "%";
|
|
84
|
+
this.frame = 0;
|
|
85
|
+
this.wrapWidth = 0;
|
|
86
|
+
this.lastRange = "";
|
|
87
|
+
this.handleScroll = () => {
|
|
88
|
+
if (!this.virtual || this.frame)
|
|
89
|
+
return;
|
|
90
|
+
this.frame = requestAnimationFrame(() => {
|
|
91
|
+
this.frame = 0;
|
|
92
|
+
this.syncToScroll();
|
|
93
|
+
this.announceRange();
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/*
|
|
98
|
+
What a row's selection checkbox is called.
|
|
99
|
+
|
|
100
|
+
"Select row" repeated twenty times tells a screen-reader user which
|
|
101
|
+
control they are on but nothing about what it does. The first column
|
|
102
|
+
is the closest thing to a row's name that a generic table can know,
|
|
103
|
+
so "Select Adriatik" comes out of the data rather than a guess.
|
|
104
|
+
*/
|
|
105
|
+
rowLabel(row) {
|
|
106
|
+
const name = this.rowName(row);
|
|
107
|
+
return name ? `Select ${name}` : "Select row";
|
|
108
|
+
}
|
|
109
|
+
/*
|
|
110
|
+
Only plain text names a row. A rich first cell (a template with an
|
|
111
|
+
avatar and two lines) stringified to "[object Object]", which a screen
|
|
112
|
+
reader then read out on every row.
|
|
113
|
+
*/
|
|
114
|
+
rowName(row) {
|
|
115
|
+
const first = this.columns[0];
|
|
116
|
+
const value = first ? row[first.key] : undefined;
|
|
117
|
+
return typeof value === "string" || typeof value === "number" ? String(value) : "";
|
|
118
|
+
}
|
|
119
|
+
get virtual() {
|
|
120
|
+
return this.visibleRows > 0 && !this.loading && this.rows.length > 0;
|
|
121
|
+
}
|
|
122
|
+
/** The slice of rows in the page: the ones in view plus OVERSCAN each side. */
|
|
123
|
+
get inPage() {
|
|
124
|
+
const count = this.rows.length;
|
|
125
|
+
if (!this.virtual)
|
|
126
|
+
return { start: 0, end: count };
|
|
127
|
+
// Clamped, because rows can shrink while the box is scrolled far down.
|
|
128
|
+
const first = Math.max(0, Math.min(this.firstInView, count - this.visibleRows));
|
|
129
|
+
return {
|
|
130
|
+
start: Math.max(0, first - OVERSCAN),
|
|
131
|
+
end: Math.min(count, first + this.visibleRows + OVERSCAN),
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
connectedCallback() {
|
|
135
|
+
super.connectedCallback();
|
|
136
|
+
// Measured again after the first render (firstUpdated) or a reconnect.
|
|
137
|
+
if (this.hasUpdated)
|
|
138
|
+
this.observeWidth();
|
|
139
|
+
}
|
|
140
|
+
disconnectedCallback() {
|
|
141
|
+
super.disconnectedCallback();
|
|
142
|
+
cancelAnimationFrame(this.frame);
|
|
143
|
+
this.frame = 0;
|
|
144
|
+
this.resizeObserver?.disconnect();
|
|
145
|
+
}
|
|
146
|
+
firstUpdated() {
|
|
147
|
+
this.observeWidth();
|
|
148
|
+
}
|
|
149
|
+
updated() {
|
|
150
|
+
if (this.virtual)
|
|
151
|
+
this.measureSoon();
|
|
152
|
+
else if (this.columnWidths.length > 0)
|
|
153
|
+
this.columnWidths = [];
|
|
154
|
+
}
|
|
155
|
+
/* A new width makes the fixed column widths wrong: measure them again. */
|
|
156
|
+
observeWidth() {
|
|
157
|
+
if (typeof ResizeObserver === "undefined" || !this.wrap)
|
|
158
|
+
return;
|
|
159
|
+
this.resizeObserver?.disconnect();
|
|
160
|
+
this.resizeObserver = new ResizeObserver(([entry]) => {
|
|
161
|
+
const width = Math.round(entry.contentRect.width);
|
|
162
|
+
if (width === this.wrapWidth)
|
|
163
|
+
return;
|
|
164
|
+
this.wrapWidth = width;
|
|
165
|
+
if (this.columnWidths.length > 0)
|
|
166
|
+
this.columnWidths = [];
|
|
167
|
+
});
|
|
168
|
+
this.resizeObserver.observe(this.wrap);
|
|
169
|
+
}
|
|
170
|
+
/*
|
|
171
|
+
Measuring happens a frame after rendering, never inside updated():
|
|
172
|
+
each measurement can change state, and a change during an update
|
|
173
|
+
would schedule another update straight away.
|
|
174
|
+
*/
|
|
175
|
+
measureSoon() {
|
|
176
|
+
if (this.frame)
|
|
177
|
+
return;
|
|
178
|
+
this.frame = requestAnimationFrame(() => {
|
|
179
|
+
this.frame = 0;
|
|
180
|
+
this.measure();
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
measure() {
|
|
184
|
+
if (!this.virtual)
|
|
185
|
+
return;
|
|
186
|
+
const changed = (a, b) => Math.abs(a - b) > 0.5;
|
|
187
|
+
const row = this.renderRoot.querySelector("tbody tr.row");
|
|
188
|
+
const rowHeight = row?.getBoundingClientRect().height ?? 0;
|
|
189
|
+
if (rowHeight > 0 && changed(rowHeight, this.rowHeight))
|
|
190
|
+
this.rowHeight = rowHeight;
|
|
191
|
+
const header = this.renderRoot.querySelector("thead tr");
|
|
192
|
+
const headerHeight = header?.getBoundingClientRect().height ?? 0;
|
|
193
|
+
if (headerHeight > 0 && changed(headerHeight, this.headerHeight))
|
|
194
|
+
this.headerHeight = headerHeight;
|
|
195
|
+
if (this.columnWidths.length === 0) {
|
|
196
|
+
const widths = [...this.renderRoot.querySelectorAll("thead th")].map((cell) => cell.getBoundingClientRect().width);
|
|
197
|
+
const total = widths.reduce((sum, width) => sum + width, 0);
|
|
198
|
+
if (widths.length > 0 && widths.every((width) => width > 0)) {
|
|
199
|
+
const fits = total <= (this.wrap?.clientWidth ?? 0) + 1;
|
|
200
|
+
this.widthUnit = fits ? "%" : "px";
|
|
201
|
+
this.columnWidths = fits ? widths.map((width) => (width / total) * 100) : widths;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// The scroll position can move without a scroll the table hears
|
|
205
|
+
// about: rows shrinking under it clamp it.
|
|
206
|
+
this.syncToScroll();
|
|
207
|
+
this.announceRange();
|
|
208
|
+
}
|
|
209
|
+
syncToScroll() {
|
|
210
|
+
if (!this.wrap)
|
|
211
|
+
return;
|
|
212
|
+
// Half a pixel of slack: scrollTop is rounded, rows are not, and 300
|
|
213
|
+
// rows down must not read as 299.
|
|
214
|
+
const first = Math.floor((this.wrap.scrollTop + 0.5) / (this.rowHeight || ROW_ESTIMATE));
|
|
215
|
+
if (first !== this.firstInView)
|
|
216
|
+
this.firstInView = first;
|
|
217
|
+
}
|
|
218
|
+
/*
|
|
219
|
+
Which rows are in view, as indexes into rows (end excluded), each time
|
|
220
|
+
that changes. Enough to fetch the next page from a server before the
|
|
221
|
+
person scrolls into it.
|
|
222
|
+
*/
|
|
223
|
+
announceRange() {
|
|
224
|
+
const count = this.rows.length;
|
|
225
|
+
const start = Math.max(0, Math.min(this.firstInView, count - this.visibleRows));
|
|
226
|
+
const end = Math.min(count, start + this.visibleRows);
|
|
227
|
+
const key = `${start}:${end}:${count}`;
|
|
228
|
+
if (key === this.lastRange)
|
|
229
|
+
return;
|
|
230
|
+
this.lastRange = key;
|
|
231
|
+
this.dispatchEvent(new CustomEvent("tt-range-change", {
|
|
232
|
+
detail: { start, end, total: count },
|
|
233
|
+
bubbles: true,
|
|
234
|
+
composed: true,
|
|
235
|
+
}));
|
|
236
|
+
}
|
|
237
|
+
get hasActions() {
|
|
238
|
+
return this.rowActions.length > 0;
|
|
239
|
+
}
|
|
240
|
+
get columnCount() {
|
|
241
|
+
return (this.columns.length + (this.selectable ? 1 : 0) + (this.hasActions ? 1 : 0));
|
|
242
|
+
}
|
|
243
|
+
/*
|
|
244
|
+
Both answer for the rows ON SCREEN, compared by id, never by count.
|
|
245
|
+
|
|
246
|
+
`selected` can hold ids that are not in `rows`: picked before a filter
|
|
247
|
+
hid them, or on another page. Comparing lengths then lies. Pick three
|
|
248
|
+
rows, filter to three different ones, and the header claimed "all
|
|
249
|
+
selected" while nothing visible was ticked.
|
|
250
|
+
*/
|
|
251
|
+
get allSelected() {
|
|
252
|
+
return (this.rows.length > 0 &&
|
|
253
|
+
this.rows.every((row) => this.selected.includes(row.id)));
|
|
254
|
+
}
|
|
255
|
+
get someSelected() {
|
|
256
|
+
return (!this.allSelected &&
|
|
257
|
+
this.rows.some((row) => this.selected.includes(row.id)));
|
|
258
|
+
}
|
|
259
|
+
emitSelection(next) {
|
|
260
|
+
this.dispatchEvent(new CustomEvent("tt-selection-change", {
|
|
261
|
+
detail: { selected: next },
|
|
262
|
+
bubbles: true,
|
|
263
|
+
composed: true,
|
|
264
|
+
}));
|
|
265
|
+
}
|
|
266
|
+
toggleAll(event) {
|
|
267
|
+
// tt-checkbox emits its own composed tt-change. Without this it would
|
|
268
|
+
// reach the page too, arriving after ours with no `selected` in it.
|
|
269
|
+
event.stopPropagation();
|
|
270
|
+
/*
|
|
271
|
+
Select-all applies to what is currently on screen, which is what a
|
|
272
|
+
user means by "all" when a filter is active. It adds or removes ONLY
|
|
273
|
+
those rows: a selection made before the filter, now hidden, is not
|
|
274
|
+
the header checkbox's to throw away.
|
|
275
|
+
*/
|
|
276
|
+
const visible = this.rows.map((r) => r.id);
|
|
277
|
+
this.emitSelection(this.allSelected
|
|
278
|
+
? this.selected.filter((id) => !visible.includes(id))
|
|
279
|
+
: [...this.selected, ...visible.filter((id) => !this.selected.includes(id))]);
|
|
280
|
+
}
|
|
281
|
+
toggleRow(id, event) {
|
|
282
|
+
event.stopPropagation();
|
|
283
|
+
this.emitSelection(this.selected.includes(id)
|
|
284
|
+
? this.selected.filter((s) => s !== id)
|
|
285
|
+
: [...this.selected, id]);
|
|
286
|
+
}
|
|
287
|
+
/*
|
|
288
|
+
Cycles ascending, descending, then off. The third state matters: once
|
|
289
|
+
sorted there is otherwise no way back to the original order, which is
|
|
290
|
+
usually meaningful (newest first, or whatever the server chose).
|
|
291
|
+
*/
|
|
292
|
+
toggleSort(column) {
|
|
293
|
+
if (!column.sortable)
|
|
294
|
+
return;
|
|
295
|
+
let next;
|
|
296
|
+
if (this.sort?.key !== column.key) {
|
|
297
|
+
next = { key: column.key, direction: "asc" };
|
|
298
|
+
}
|
|
299
|
+
else if (this.sort.direction === "asc") {
|
|
300
|
+
next = { key: column.key, direction: "desc" };
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
next = undefined;
|
|
304
|
+
}
|
|
305
|
+
this.dispatchEvent(new CustomEvent("tt-sort", {
|
|
306
|
+
detail: { sort: next },
|
|
307
|
+
bubbles: true,
|
|
308
|
+
composed: true,
|
|
309
|
+
}));
|
|
310
|
+
}
|
|
311
|
+
clickRow(row) {
|
|
312
|
+
if (!this.clickableRows)
|
|
313
|
+
return;
|
|
314
|
+
this.dispatchEvent(new CustomEvent("tt-row-click", {
|
|
315
|
+
detail: { row },
|
|
316
|
+
bubbles: true,
|
|
317
|
+
composed: true,
|
|
318
|
+
}));
|
|
319
|
+
}
|
|
320
|
+
chooseAction(row, event) {
|
|
321
|
+
// The menu's tt-menu-select is generic. Re-emit it as something the page
|
|
322
|
+
// can act on: which action, on which row.
|
|
323
|
+
event.stopPropagation();
|
|
324
|
+
const { value } = event.detail;
|
|
325
|
+
this.dispatchEvent(new CustomEvent("tt-row-action", {
|
|
326
|
+
detail: { action: value, row },
|
|
327
|
+
bubbles: true,
|
|
328
|
+
composed: true,
|
|
329
|
+
}));
|
|
330
|
+
}
|
|
331
|
+
static { this.styles = [
|
|
332
|
+
srOnly,
|
|
333
|
+
css `
|
|
334
|
+
/* The browser's own [hidden] rule loses to any :host display, so a
|
|
335
|
+
hidden element would still show. Important, so it always wins. */
|
|
336
|
+
:host([hidden]) {
|
|
337
|
+
display: none !important;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
:host {
|
|
341
|
+
display: block;
|
|
342
|
+
font-family: var(--tt-font-sans);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.wrap {
|
|
346
|
+
width: 100%;
|
|
347
|
+
overflow-x: auto;
|
|
348
|
+
box-sizing: border-box;
|
|
349
|
+
|
|
350
|
+
background: var(--tt-card);
|
|
351
|
+
border: 1px solid var(--tt-border);
|
|
352
|
+
border-radius: var(--tt-radius-lg);
|
|
353
|
+
|
|
354
|
+
-webkit-overflow-scrolling: touch;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
table {
|
|
358
|
+
width: 100%;
|
|
359
|
+
border-collapse: collapse;
|
|
360
|
+
font-size: var(--tt-text-sm);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/*
|
|
364
|
+
Sticky header: the column labels stay put while the body scrolls,
|
|
365
|
+
so you never lose track of what a column means in a long list.
|
|
366
|
+
|
|
367
|
+
It sticks to .wrap, not to the page. overflow-x: auto turns .wrap
|
|
368
|
+
into a scroll container on BOTH axes, and sticky always pins to the
|
|
369
|
+
nearest one. So it only works once the consumer gives the wrap a
|
|
370
|
+
height (::part(wrap) { max-height }). There is no way to scroll
|
|
371
|
+
sideways inside a box AND stick to the page's scroll; that is CSS,
|
|
372
|
+
not a choice made here.
|
|
373
|
+
*/
|
|
374
|
+
thead th {
|
|
375
|
+
position: sticky;
|
|
376
|
+
top: 0;
|
|
377
|
+
z-index: 1;
|
|
378
|
+
|
|
379
|
+
/* The same pair as tt-table, so a colour theme tints every table header. */
|
|
380
|
+
background: var(--tt-table-header);
|
|
381
|
+
color: var(--tt-table-header-foreground);
|
|
382
|
+
|
|
383
|
+
padding: var(--tt-space-3) var(--tt-space-4);
|
|
384
|
+
|
|
385
|
+
font-size: var(--tt-text-xs);
|
|
386
|
+
font-weight: var(--tt-weight-semibold);
|
|
387
|
+
text-align: left;
|
|
388
|
+
text-transform: uppercase;
|
|
389
|
+
letter-spacing: 0.05em;
|
|
390
|
+
white-space: nowrap;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
th.end,
|
|
394
|
+
td.end {
|
|
395
|
+
text-align: right;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
td {
|
|
399
|
+
padding: var(--tt-space-3) var(--tt-space-4);
|
|
400
|
+
border-top: 1px solid var(--tt-border);
|
|
401
|
+
color: var(--tt-foreground);
|
|
402
|
+
line-height: var(--tt-leading-snug);
|
|
403
|
+
vertical-align: middle;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
tbody tr {
|
|
407
|
+
transition: background var(--tt-duration-fast) var(--tt-ease);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
tbody tr:hover {
|
|
411
|
+
background: var(--tt-accent);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
tbody tr.clickable {
|
|
415
|
+
cursor: pointer;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/* Selected sits after hover so it wins, and gets its own darker
|
|
419
|
+
hover so a selected row still reacts to the pointer. */
|
|
420
|
+
tbody tr.selected {
|
|
421
|
+
background: color-mix(in srgb, var(--tt-primary) 8%, transparent);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
tbody tr.selected:hover {
|
|
425
|
+
background: color-mix(in srgb, var(--tt-primary) 14%, transparent);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
tbody tr:focus-visible {
|
|
429
|
+
outline: var(--tt-ring-width) solid var(--tt-ring);
|
|
430
|
+
outline-offset: var(--tt-ring-offset);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/* Sort controls are real buttons so the header is keyboard reachable.
|
|
434
|
+
A th with a click handler is not. */
|
|
435
|
+
.sort {
|
|
436
|
+
display: inline-flex;
|
|
437
|
+
align-items: center;
|
|
438
|
+
gap: var(--tt-space-1);
|
|
439
|
+
|
|
440
|
+
padding: 0;
|
|
441
|
+
border: none;
|
|
442
|
+
background: transparent;
|
|
443
|
+
color: inherit;
|
|
444
|
+
|
|
445
|
+
font: inherit;
|
|
446
|
+
font-size: inherit;
|
|
447
|
+
font-weight: inherit;
|
|
448
|
+
letter-spacing: inherit;
|
|
449
|
+
text-transform: inherit;
|
|
450
|
+
|
|
451
|
+
cursor: pointer;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
.sort:hover {
|
|
455
|
+
color: var(--tt-foreground);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
.sort:focus-visible {
|
|
459
|
+
outline: var(--tt-ring-width) solid var(--tt-ring);
|
|
460
|
+
outline-offset: var(--tt-ring-offset);
|
|
461
|
+
border-radius: var(--tt-radius-sm);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/* Reserve the arrow's space always, so a header does not shift
|
|
465
|
+
sideways the moment you sort by it. The icon is always rendered and
|
|
466
|
+
only faded, so it holds its own width. */
|
|
467
|
+
.arrow {
|
|
468
|
+
display: inline-flex;
|
|
469
|
+
opacity: 0;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
.sorted {
|
|
473
|
+
color: var(--tt-foreground);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
.sorted .arrow {
|
|
477
|
+
opacity: 1;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/* width:1% on a table cell means "as narrow as the content allows".
|
|
481
|
+
The other columns absorb the leftover space. */
|
|
482
|
+
.select-cell,
|
|
483
|
+
.actions-cell {
|
|
484
|
+
width: 1%;
|
|
485
|
+
white-space: nowrap;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
.select-cell {
|
|
489
|
+
padding-right: 0;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
.actions-cell {
|
|
493
|
+
text-align: right;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
.state {
|
|
497
|
+
padding: var(--tt-space-6);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/* Virtualized: a box that scrolls on its own, and does not hand the
|
|
501
|
+
scroll on to the page when it reaches an end. */
|
|
502
|
+
.wrap.virtual {
|
|
503
|
+
overflow-y: auto;
|
|
504
|
+
overscroll-behavior: contain;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
table.fixed {
|
|
508
|
+
table-layout: fixed;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/* One line per cell, so every row is the one height the window math
|
|
512
|
+
assumes. Data cells only: the checkbox and menu keep their focus
|
|
513
|
+
rings. */
|
|
514
|
+
.virtual td.cell {
|
|
515
|
+
overflow: hidden;
|
|
516
|
+
text-overflow: ellipsis;
|
|
517
|
+
white-space: nowrap;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
tr.spacer td {
|
|
521
|
+
padding: 0;
|
|
522
|
+
border: 0;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/* Tighter sides on phones: a third column fits instead of scrolling. */
|
|
526
|
+
@media (max-width: 480px) {
|
|
527
|
+
thead th,
|
|
528
|
+
td {
|
|
529
|
+
padding-inline: var(--tt-space-3);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
tr.spacer td {
|
|
533
|
+
padding: 0;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
tbody tr.spacer:hover {
|
|
538
|
+
background: transparent;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
`,
|
|
542
|
+
]; }
|
|
543
|
+
renderHeader() {
|
|
544
|
+
return html `
|
|
545
|
+
<thead>
|
|
546
|
+
<tr aria-rowindex=${ifDefined(this.virtual ? 1 : undefined)}>
|
|
547
|
+
${this.selectable
|
|
548
|
+
? html `
|
|
549
|
+
<th class="select-cell">
|
|
550
|
+
<!--
|
|
551
|
+
The checkbox names ITSELF, but its label lives in a
|
|
552
|
+
nested shadow root, and a table header cell is judged
|
|
553
|
+
on its own text. Same pattern as the actions column
|
|
554
|
+
above: the column gets a name, the control gets a name,
|
|
555
|
+
and they are not the same sentence.
|
|
556
|
+
-->
|
|
557
|
+
<span class="sr-only">Select</span>
|
|
558
|
+
<tt-checkbox
|
|
559
|
+
label="Select all rows"
|
|
560
|
+
label-hidden
|
|
561
|
+
.checked=${this.allSelected}
|
|
562
|
+
.indeterminate=${this.someSelected}
|
|
563
|
+
@tt-change=${this.toggleAll}
|
|
564
|
+
></tt-checkbox>
|
|
565
|
+
</th>
|
|
566
|
+
`
|
|
567
|
+
: ""}
|
|
568
|
+
${this.columns.map((column) => {
|
|
569
|
+
const isSorted = this.sort?.key === column.key;
|
|
570
|
+
const direction = this.sort?.direction;
|
|
571
|
+
return html `
|
|
572
|
+
<th
|
|
573
|
+
class=${column.align === "end" ? "end" : ""}
|
|
574
|
+
style=${ifDefined(column.width ? `width:${column.width}` : undefined)}
|
|
575
|
+
aria-sort=${ifDefined(!column.sortable
|
|
576
|
+
? undefined
|
|
577
|
+
: !isSorted
|
|
578
|
+
? "none"
|
|
579
|
+
: direction === "asc"
|
|
580
|
+
? "ascending"
|
|
581
|
+
: "descending")}
|
|
582
|
+
>
|
|
583
|
+
${column.sortable
|
|
584
|
+
? html `
|
|
585
|
+
<button
|
|
586
|
+
class="sort ${isSorted ? "sorted" : ""}"
|
|
587
|
+
type="button"
|
|
588
|
+
@click=${() => this.toggleSort(column)}
|
|
589
|
+
>
|
|
590
|
+
${column.label}
|
|
591
|
+
<span class="arrow" aria-hidden="true">
|
|
592
|
+
<tt-icon
|
|
593
|
+
name=${direction === "desc" ? "arrow-down" : "arrow-up"}
|
|
594
|
+
size="12px"
|
|
595
|
+
></tt-icon>
|
|
596
|
+
</span>
|
|
597
|
+
</button>
|
|
598
|
+
`
|
|
599
|
+
: column.label}
|
|
600
|
+
</th>
|
|
601
|
+
`;
|
|
602
|
+
})}
|
|
603
|
+
${this.hasActions
|
|
604
|
+
? html `<th class="actions-cell">
|
|
605
|
+
<span class="sr-only">Actions</span>
|
|
606
|
+
</th>`
|
|
607
|
+
: ""}
|
|
608
|
+
</tr>
|
|
609
|
+
</thead>
|
|
610
|
+
`;
|
|
611
|
+
}
|
|
612
|
+
renderLoading() {
|
|
613
|
+
return html `
|
|
614
|
+
<tbody aria-busy="true">
|
|
615
|
+
${Array.from({ length: this.loadingRows }, () => html `
|
|
616
|
+
<tr>
|
|
617
|
+
<td colspan=${this.columnCount}>
|
|
618
|
+
<tt-skeleton variant="text"></tt-skeleton>
|
|
619
|
+
</td>
|
|
620
|
+
</tr>
|
|
621
|
+
`)}
|
|
622
|
+
</tbody>
|
|
623
|
+
`;
|
|
624
|
+
}
|
|
625
|
+
renderRow(row, index) {
|
|
626
|
+
const isSelected = this.selected.includes(row.id);
|
|
627
|
+
return html `
|
|
628
|
+
<tr
|
|
629
|
+
class="row ${this.clickableRows ? "clickable" : ""} ${isSelected
|
|
630
|
+
? "selected"
|
|
631
|
+
: ""}"
|
|
632
|
+
aria-rowindex=${ifDefined(this.virtual ? index + 2 : undefined)}
|
|
633
|
+
tabindex=${ifDefined(this.clickableRows ? 0 : undefined)}
|
|
634
|
+
@click=${() => this.clickRow(row)}
|
|
635
|
+
@keydown=${(e) => {
|
|
636
|
+
/*
|
|
637
|
+
Only a key pressed on the row ITSELF. Keys bubble, so Enter on
|
|
638
|
+
the row's checkbox or its actions menu reaches this handler
|
|
639
|
+
too, and opening the menu would also navigate away. target is
|
|
640
|
+
where the key was pressed; currentTarget is this <tr>.
|
|
641
|
+
*/
|
|
642
|
+
if (e.target !== e.currentTarget)
|
|
643
|
+
return;
|
|
644
|
+
if (this.clickableRows && e.key === "Enter")
|
|
645
|
+
this.clickRow(row);
|
|
646
|
+
}}
|
|
647
|
+
>
|
|
648
|
+
${this.selectable
|
|
649
|
+
? html `
|
|
650
|
+
<td class="select-cell" @click=${(e) => e.stopPropagation()}>
|
|
651
|
+
<tt-checkbox
|
|
652
|
+
.label=${this.rowLabel(row)}
|
|
653
|
+
label-hidden
|
|
654
|
+
.checked=${isSelected}
|
|
655
|
+
@tt-change=${(e) => this.toggleRow(row.id, e)}
|
|
656
|
+
></tt-checkbox>
|
|
657
|
+
</td>
|
|
658
|
+
`
|
|
659
|
+
: ""}
|
|
660
|
+
${this.columns.map((column) => html `
|
|
661
|
+
<td class="cell ${column.align === "end" ? "end" : ""}">
|
|
662
|
+
${row[column.key] ?? ""}
|
|
663
|
+
</td>
|
|
664
|
+
`)}
|
|
665
|
+
${this.hasActions
|
|
666
|
+
? html `
|
|
667
|
+
<td
|
|
668
|
+
class="actions-cell"
|
|
669
|
+
@click=${(e) => e.stopPropagation()}
|
|
670
|
+
>
|
|
671
|
+
<tt-dropdown-menu
|
|
672
|
+
.items=${this.rowActions}
|
|
673
|
+
label=${this.rowName(row) ? `Actions for ${this.rowName(row)}` : "Actions"}
|
|
674
|
+
@tt-menu-select=${(e) => this.chooseAction(row, e)}
|
|
675
|
+
></tt-dropdown-menu>
|
|
676
|
+
</td>
|
|
677
|
+
`
|
|
678
|
+
: ""}
|
|
679
|
+
</tr>
|
|
680
|
+
`;
|
|
681
|
+
}
|
|
682
|
+
/*
|
|
683
|
+
The rows in view, with a spacer row above and below standing in for
|
|
684
|
+
the rest, so the scrollbar is as long as the whole table. Keyed by id,
|
|
685
|
+
so a row keeps its element (and its focus, its open menu) while the
|
|
686
|
+
window slides over it.
|
|
687
|
+
*/
|
|
688
|
+
renderRows() {
|
|
689
|
+
const { start, end } = this.inPage;
|
|
690
|
+
const height = this.rowHeight || ROW_ESTIMATE;
|
|
691
|
+
const spacer = (rows) => rows > 0
|
|
692
|
+
? html `<tr class="spacer" aria-hidden="true" style="height: ${rows * height}px">
|
|
693
|
+
<td colspan=${this.columnCount}></td>
|
|
694
|
+
</tr>`
|
|
695
|
+
: "";
|
|
696
|
+
return html `
|
|
697
|
+
${spacer(start)}
|
|
698
|
+
${repeat(this.rows.slice(start, end), (row) => row.id, (row, offset) => this.renderRow(row, start + offset))}
|
|
699
|
+
${spacer(this.rows.length - end)}
|
|
700
|
+
`;
|
|
701
|
+
}
|
|
702
|
+
render() {
|
|
703
|
+
const virtual = this.virtual;
|
|
704
|
+
const fixed = virtual && this.columnWidths.length > 0;
|
|
705
|
+
// The header, the rows in view and the two borders of .wrap.
|
|
706
|
+
const boxHeight = (this.headerHeight || ROW_ESTIMATE) + this.visibleRows * (this.rowHeight || ROW_ESTIMATE) + 2;
|
|
707
|
+
return html `
|
|
708
|
+
<div
|
|
709
|
+
class="wrap ${virtual ? "virtual" : ""}"
|
|
710
|
+
part="wrap"
|
|
711
|
+
style=${ifDefined(virtual ? `max-height: ${boxHeight}px` : undefined)}
|
|
712
|
+
@scroll=${this.handleScroll}
|
|
713
|
+
>
|
|
714
|
+
<table
|
|
715
|
+
part="table"
|
|
716
|
+
class=${fixed ? "fixed" : ""}
|
|
717
|
+
aria-label=${ifDefined(this.label || undefined)}
|
|
718
|
+
aria-rowcount=${ifDefined(virtual ? this.rows.length + 1 : undefined)}
|
|
719
|
+
>
|
|
720
|
+
${fixed
|
|
721
|
+
? html `<colgroup>
|
|
722
|
+
${this.columnWidths.map((width) => html `<col style="width: ${width}${this.widthUnit}" />`)}
|
|
723
|
+
</colgroup>`
|
|
724
|
+
: ""}
|
|
725
|
+
${this.renderHeader()}
|
|
726
|
+
${this.loading
|
|
727
|
+
? this.renderLoading()
|
|
728
|
+
: html `
|
|
729
|
+
<tbody>
|
|
730
|
+
${this.rows.length === 0
|
|
731
|
+
? html `
|
|
732
|
+
<tr>
|
|
733
|
+
<td class="state" colspan=${this.columnCount}>
|
|
734
|
+
<tt-empty-state
|
|
735
|
+
heading=${this.emptyHeading}
|
|
736
|
+
description=${this.emptyDescription}
|
|
737
|
+
>
|
|
738
|
+
<slot name="empty-actions" slot="actions"></slot>
|
|
739
|
+
</tt-empty-state>
|
|
740
|
+
</td>
|
|
741
|
+
</tr>
|
|
742
|
+
`
|
|
743
|
+
: this.renderRows()}
|
|
744
|
+
</tbody>
|
|
745
|
+
`}
|
|
746
|
+
</table>
|
|
747
|
+
</div>
|
|
748
|
+
`;
|
|
749
|
+
}
|
|
750
|
+
};
|
|
751
|
+
__decorate([
|
|
752
|
+
property({ type: Array })
|
|
753
|
+
], TTDataTable.prototype, "columns", void 0);
|
|
754
|
+
__decorate([
|
|
755
|
+
property({ type: Array })
|
|
756
|
+
], TTDataTable.prototype, "rows", void 0);
|
|
757
|
+
__decorate([
|
|
758
|
+
property({ type: String })
|
|
759
|
+
], TTDataTable.prototype, "label", void 0);
|
|
760
|
+
__decorate([
|
|
761
|
+
property({ type: Object })
|
|
762
|
+
], TTDataTable.prototype, "sort", void 0);
|
|
763
|
+
__decorate([
|
|
764
|
+
property({ type: Boolean })
|
|
765
|
+
], TTDataTable.prototype, "selectable", void 0);
|
|
766
|
+
__decorate([
|
|
767
|
+
property({ type: Array })
|
|
768
|
+
], TTDataTable.prototype, "selected", void 0);
|
|
769
|
+
__decorate([
|
|
770
|
+
property({ type: Array, attribute: "row-actions" })
|
|
771
|
+
], TTDataTable.prototype, "rowActions", void 0);
|
|
772
|
+
__decorate([
|
|
773
|
+
property({ type: Boolean })
|
|
774
|
+
], TTDataTable.prototype, "loading", void 0);
|
|
775
|
+
__decorate([
|
|
776
|
+
property({ type: Number, attribute: "loading-rows" })
|
|
777
|
+
], TTDataTable.prototype, "loadingRows", void 0);
|
|
778
|
+
__decorate([
|
|
779
|
+
property({ type: String, attribute: "empty-heading" })
|
|
780
|
+
], TTDataTable.prototype, "emptyHeading", void 0);
|
|
781
|
+
__decorate([
|
|
782
|
+
property({ type: String, attribute: "empty-description" })
|
|
783
|
+
], TTDataTable.prototype, "emptyDescription", void 0);
|
|
784
|
+
__decorate([
|
|
785
|
+
property({ type: Boolean, attribute: "clickable-rows" })
|
|
786
|
+
], TTDataTable.prototype, "clickableRows", void 0);
|
|
787
|
+
__decorate([
|
|
788
|
+
property({ type: Number, attribute: "visible-rows" })
|
|
789
|
+
], TTDataTable.prototype, "visibleRows", void 0);
|
|
790
|
+
__decorate([
|
|
791
|
+
state()
|
|
792
|
+
], TTDataTable.prototype, "firstInView", void 0);
|
|
793
|
+
__decorate([
|
|
794
|
+
state()
|
|
795
|
+
], TTDataTable.prototype, "rowHeight", void 0);
|
|
796
|
+
__decorate([
|
|
797
|
+
state()
|
|
798
|
+
], TTDataTable.prototype, "headerHeight", void 0);
|
|
799
|
+
__decorate([
|
|
800
|
+
state()
|
|
801
|
+
], TTDataTable.prototype, "columnWidths", void 0);
|
|
802
|
+
__decorate([
|
|
803
|
+
state()
|
|
804
|
+
], TTDataTable.prototype, "widthUnit", void 0);
|
|
805
|
+
__decorate([
|
|
806
|
+
query(".wrap")
|
|
807
|
+
], TTDataTable.prototype, "wrap", void 0);
|
|
808
|
+
TTDataTable = __decorate([
|
|
809
|
+
customElement("tt-data-table")
|
|
810
|
+
], TTDataTable);
|
|
811
|
+
export { TTDataTable };
|
|
812
|
+
//# sourceMappingURL=tt-data-table.js.map
|