UNPKG

@esri/calcite-components

Version:

Web Components for Esri's Calcite Design System.

107 lines (106 loc) • 8.04 kB
/*! 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 };