@esri/calcite-components
Version:
Web Components for Esri's Calcite Design System.
107 lines (106 loc) • 8.04 kB
JavaScript
/*! All material copyright ESRI, All Rights Reserved, unless otherwise specified.
See https://github.com/Esri/calcite-design-system/blob/dev/LICENSE.md for details.
v3.2.1 */
import { c as customElement } from "../../chunks/runtime.js";
import { nothing, html } from "lit";
import { createRef, ref } from "lit-html/directives/ref.js";
import { LitElement, safeClassMap } from "@arcgis/lumina";
import { c as componentFocusable, g as getIconScale } from "../../chunks/component.js";
import { u as useT9n } from "../../chunks/useT9n.js";
import { css } from "@lit/reactive-element/css-tag.js";
const CSS = {
contentCell: "content-cell",
numberCell: "number-cell",
selectionCell: "selection-cell",
bodyRow: "body-row",
footerRow: "footer-row",
heading: "heading",
description: "description",
multipleSelectionCell: "cell--multiple-selection",
assistiveText: "assistive-text",
active: "active",
selectedCell: "selected-cell",
lastCell: "last-cell",
staticCell: "static-cell"
};
const ICONS = {
checked: "check-square-f",
indeterminate: "minus-square-f",
unchecked: "square"
};
const styles = css`:host{--calcite-internal-table-header-background: var(--calcite-table-header-background, var(--calcite-color-foreground-2));--calcite-internal-table-header-border-color: var(--calcite-table-border-color, var(--calcite-color-border-3));display:contents}:host([alignment=center]) th{text-align:center}:host([alignment=end]) th{text-align:end}.assistive-text{position:absolute;inline-size:1px;block-size:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}th{white-space:normal;text-align:start;font-weight:var(--calcite-font-weight-medium);color:var(--calcite-color-text-1);font-size:var(--calcite-internal-table-cell-font-size);border-inline-end:1px solid var(--calcite-internal-table-header-border-color);border-block-end:1px solid var(--calcite-internal-table-header-border-color);padding-block:calc(var(--calcite-internal-table-cell-padding) * 1.5);padding-inline:var(--calcite-internal-table-cell-padding);background-color:var(--calcite-internal-table-header-background)}th:not(.static-cell){outline-color:transparent}th:not(.static-cell):not(.static-cell):focus-within{outline:2px solid var(--calcite-color-focus, var(--calcite-ui-focus-color, var(--calcite-color-brand)));outline-offset:calc(-2px*(1 - (2*clamp(0,var(--calcite-offset-invert-focus),1))))}th:not(.center):not(.end).content-cell{vertical-align:top}th.center{vertical-align:middle}th.end.content-cell{vertical-align:bottom}th.body-row,th.footer-row{padding-block:var(--calcite-internal-table-cell-padding);border-block-end:0}th.footer-row{border-block-start:1px solid var(--calcite-internal-table-header-border-color)}th.last-cell{border-inline-end:0}.cell--multiple-selection{cursor:pointer;vertical-align:middle;color:var(--calcite-color-text-3)}.cell--multiple-selection:not(.end){vertical-align:middle}.selected-cell:not(.number-cell):not(.footer-cell){--calcite-internal-table-header-background: var(--calcite-color-foreground-current)}.number-cell,.selection-cell{color:var(--calcite-color-text-2);inline-size:2rem;min-inline-size:2rem}.selection-cell calcite-icon.active{color:var(--calcite-color-brand)}.number-cell calcite-icon,.selection-cell calcite-icon{margin-inline-start:auto;margin-inline-end:auto;vertical-align:middle}.heading{color:var(--calcite-color-text-1)}.description{color:var(--calcite-color-text-3);font-size:var(--calcite-internal-table-cell-font-size-secondary)}`;
class TableHeader extends LitElement {
constructor() {
super(...arguments);
this.containerEl = createRef();
this.messages = useT9n({ blocking: true });
this.focused = false;
this.screenReaderText = "";
this.alignment = "start";
this.interactionMode = "interactive";
this.numberCell = false;
this.parentRowAlignment = "start";
this.selectionCell = false;
}
static {
this.properties = { focused: [16, {}, { state: true }], screenReaderText: [16, {}, { state: true }], alignment: [3, {}, { reflect: true }], bodyRowCount: [9, {}, { type: Number }], colSpan: [11, {}, { reflect: true, type: Number }], description: [3, {}, { reflect: true }], heading: [3, {}, { reflect: true }], interactionMode: 1, lastCell: [5, {}, { type: Boolean }], messageOverrides: [0, {}, { attribute: false }], numberCell: [5, {}, { type: Boolean }], parentRowAlignment: 1, parentRowIsSelected: [5, {}, { type: Boolean }], parentRowType: 1, positionInRow: [9, {}, { type: Number }], rowSpan: [11, {}, { reflect: true, type: Number }], scale: 1, selectedRowCount: [9, {}, { type: Number }], selectedRowCountLocalized: 1, selectionCell: [5, {}, { type: Boolean }], selectionMode: 1 };
}
static {
this.styles = styles;
}
async setFocus() {
await componentFocusable(this);
this.containerEl.value.focus();
}
async load() {
this.updateScreenReaderText();
}
willUpdate(changes) {
if (changes.has("selectedRowCount") || changes.has("selectedRowCountLocalized")) {
this.updateScreenReaderText();
}
}
updateScreenReaderText() {
let text = "";
const sharedText = `${this.selectedRowCountLocalized} ${this.messages?.selected}`;
if (this.numberCell) {
text = this.messages?.rowNumber;
} else if (this.selectionMode === "single") {
text = `${this.messages?.selectionColumn}. ${sharedText}`;
} else if (this.bodyRowCount === this.selectedRowCount) {
text = `${this.messages?.selectionColumn}. ${this.messages?.all} ${sharedText} ${this.messages?.keyboardDeselectAll}`;
} else {
text = `${this.messages?.selectionColumn}. ${sharedText} ${this.messages?.keyboardSelectAll}`;
}
this.screenReaderText = text;
}
onContainerBlur() {
this.focused = false;
}
onContainerFocus() {
this.focused = true;
}
render() {
const scope = this.rowSpan ? "rowgroup" : this.colSpan ? "colgroup" : this.parentRowType === "body" ? "row" : "col";
const checked = this.selectedRowCount === this.bodyRowCount;
const indeterminate = this.selectedRowCount > 0;
const selectionIcon = checked ? ICONS.checked : indeterminate ? ICONS.indeterminate : ICONS.unchecked;
const staticCell = this.interactionMode === "static" && !this.selectionCell;
return html`<th .ariaColIndex=${this.parentRowType === "head" ? this.positionInRow : void 0} class=${safeClassMap({
[CSS.bodyRow]: this.parentRowType === "body",
[CSS.footerRow]: this.parentRowType === "foot",
[CSS.contentCell]: !this.numberCell && !this.selectionCell,
[CSS.numberCell]: this.numberCell,
[CSS.selectionCell]: this.selectionCell,
[CSS.selectedCell]: this.parentRowIsSelected,
[CSS.multipleSelectionCell]: this.selectionMode === "multiple",
[CSS.staticCell]: staticCell,
[CSS.lastCell]: this.lastCell && (!this.rowSpan || this.colSpan && !!this.rowSpan),
[this.parentRowAlignment]: this.parentRowAlignment === "center" || this.parentRowAlignment === "end"
})} colSpan=${this.colSpan ?? nothing} @blur=${this.onContainerBlur} @focus=${this.onContainerFocus} .role=${this.parentRowType === "head" ? "columnheader" : "rowheader"} rowSpan=${this.rowSpan ?? nothing} scope=${scope ?? nothing} .tabIndex=${this.selectionCell ? 0 : staticCell ? -1 : 0} ${ref(this.containerEl)}>${this.heading && html`<div class=${safeClassMap(CSS.heading)}>${this.heading}</div>` || ""}${this.description && html`<div class=${safeClassMap(CSS.description)}>${this.description}</div>` || ""}${this.selectionCell && this.selectionMode === "multiple" && html`<calcite-icon class=${safeClassMap({ [CSS.active]: indeterminate || checked })} .icon=${selectionIcon} .scale=${getIconScale(this.scale)}></calcite-icon>` || ""}${(this.selectionCell || this.numberCell) && html`<span .ariaLive=${this.focused ? "polite" : "off"} class=${safeClassMap(CSS.assistiveText)}>${this.screenReaderText}</span>` || ""}</th>`;
}
}
customElement("calcite-table-header", TableHeader);
export {
TableHeader
};