Improve item range selection.
This commit is contained in:
@@ -36,6 +36,13 @@ class TpTableItem extends BaseElement {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Rows are click targets in row-click/ctrl-click selection modes —
|
||||||
|
a shift+click range gesture must not select their text. Checkbox
|
||||||
|
tables keep text selectable (selection lives in the checkbox). */
|
||||||
|
:host([data-selection-mode]) {
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
.wrap {
|
.wrap {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 0.5fr 3fr 0.5fr 0.5fr 0.5fr; /* Overridden by javascript */
|
grid-template-columns: 0.5fr 3fr 0.5fr 0.5fr 0.5fr; /* Overridden by javascript */
|
||||||
|
|||||||
+34
-5
@@ -187,6 +187,7 @@ export class TpTable extends DomQuery(LitElement) {
|
|||||||
${this.renderTableHeader(columns, showCheckboxColumn)}
|
${this.renderTableHeader(columns, showCheckboxColumn)}
|
||||||
<div class="list"
|
<div class="list"
|
||||||
@row-selection-changed=${(e) => this._selectionChanged(e)}
|
@row-selection-changed=${(e) => this._selectionChanged(e)}
|
||||||
|
@mousedown=${(e) => this._listMousedown(e)}
|
||||||
@click=${(e) => this._handleRowClick(e)}>
|
@click=${(e) => this._handleRowClick(e)}>
|
||||||
${!Array.isArray(items) || items.length === 0 ? html`
|
${!Array.isArray(items) || items.length === 0 ? html`
|
||||||
<div class="empty-message">
|
<div class="empty-message">
|
||||||
@@ -311,6 +312,7 @@ export class TpTable extends DomQuery(LitElement) {
|
|||||||
super();
|
super();
|
||||||
this._selItems = new Map();
|
this._selItems = new Map();
|
||||||
this._lastSelectedId = null;
|
this._lastSelectedId = null;
|
||||||
|
this._shiftDownItem = null;
|
||||||
this.selectionMode = 'checkbox';
|
this.selectionMode = 'checkbox';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -632,18 +634,42 @@ export class TpTable extends DomQuery(LitElement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Text selection starts on MOUSEDOWN — preventing it at click is too
|
||||||
|
// late: the browser has already selected and the click may even retarget
|
||||||
|
// to a common ancestor instead of the row. Shift/ctrl/meta clicks are
|
||||||
|
// selection gestures in row-click mode, so the browser must not start a
|
||||||
|
// text selection from them.
|
||||||
|
_listMousedown(e) {
|
||||||
|
if (this.selectionMode !== 'row-click' || !this.selectable) return;
|
||||||
|
|
||||||
|
if (e.shiftKey || e.ctrlKey || e.metaKey) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remember the row the shift gesture started on: if the click
|
||||||
|
// retargets (row re-rendered between mousedown and mouseup), its
|
||||||
|
// composed path no longer contains a row and the range would
|
||||||
|
// silently collapse to the previously selected rows.
|
||||||
|
this._shiftDownItem = e.shiftKey
|
||||||
|
? e.composedPath().find(n => n?.hasAttribute && n.hasAttribute('item')) || null
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
_handleRowClick(e) {
|
_handleRowClick(e) {
|
||||||
if (this.selectionMode !== 'row-click' || !this.selectable) return;
|
if (this.selectionMode !== 'row-click' || !this.selectable) return;
|
||||||
|
|
||||||
// Prevent the browser's native shift+click text selection since we're
|
|
||||||
// using shift+click for range selection.
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
// Walk through composedPath to find the <tp-table-item> host, since
|
// Walk through composedPath to find the <tp-table-item> host, since
|
||||||
// lit-virtualizer puts rows in a shadow tree.
|
// lit-virtualizer puts rows in a shadow tree.
|
||||||
const itemEl = e.composedPath().find(
|
let itemEl = e.composedPath().find(
|
||||||
n => n?.hasAttribute && n.hasAttribute('item')
|
n => n?.hasAttribute && n.hasAttribute('item')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!itemEl && e.shiftKey && this._shiftDownItem) {
|
||||||
|
itemEl = this._shiftDownItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._shiftDownItem = null;
|
||||||
|
|
||||||
if (!itemEl || !itemEl.item) return;
|
if (!itemEl || !itemEl.item) return;
|
||||||
|
|
||||||
const id = this.getItemId(itemEl.item);
|
const id = this.getItemId(itemEl.item);
|
||||||
@@ -661,6 +687,9 @@ export class TpTable extends DomQuery(LitElement) {
|
|||||||
const it = items[i];
|
const it = items[i];
|
||||||
this._selItems.set(this.getItemId(it), it);
|
this._selItems.set(this.getItemId(it), it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stray text selection from before the gesture must not survive.
|
||||||
|
window.getSelection?.()?.removeAllRanges?.();
|
||||||
}
|
}
|
||||||
} else if (e.ctrlKey || e.metaKey) {
|
} else if (e.ctrlKey || e.metaKey) {
|
||||||
// Toggle individual row.
|
// Toggle individual row.
|
||||||
|
|||||||
Reference in New Issue
Block a user