@design.estate/dees-catalog 3.61.2 → 3.63.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/dist_bundle/bundle.js +677 -128
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/00group-dataview/dees-table/data.d.ts +8 -2
- package/dist_ts_web/elements/00group-dataview/dees-table/data.js +40 -22
- package/dist_ts_web/elements/00group-dataview/dees-table/dees-table.d.ts +110 -6
- package/dist_ts_web/elements/00group-dataview/dees-table/dees-table.demo.js +39 -1
- package/dist_ts_web/elements/00group-dataview/dees-table/dees-table.js +629 -114
- package/dist_ts_web/elements/00group-dataview/dees-table/styles.js +72 -18
- package/dist_ts_web/elements/00group-dataview/dees-table/types.d.ts +8 -0
- package/dist_watch/bundle.js +675 -126
- package/dist_watch/bundle.js.map +3 -3
- package/package.json +1 -1
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/00group-dataview/dees-table/data.ts +33 -17
- package/ts_web/elements/00group-dataview/dees-table/dees-table.demo.ts +38 -0
- package/ts_web/elements/00group-dataview/dees-table/dees-table.ts +656 -92
- package/ts_web/elements/00group-dataview/dees-table/styles.ts +71 -17
- package/ts_web/elements/00group-dataview/dees-table/types.ts +9 -0
package/dist_watch/bundle.js
CHANGED
|
@@ -168991,6 +168991,44 @@ var demoFunc29 = /* @__PURE__ */ __name(() => b2`
|
|
|
168991
168991
|
></dees-table>
|
|
168992
168992
|
</div>
|
|
168993
168993
|
|
|
168994
|
+
<div class="demo-section">
|
|
168995
|
+
<h2 class="demo-title">Multi-Column Sort</h2>
|
|
168996
|
+
<p class="demo-description">
|
|
168997
|
+
Click any column header for a single-column sort. Hold Shift while clicking to add the
|
|
168998
|
+
column to a multi-sort cascade (or cycle its direction). Right-click any sortable header
|
|
168999
|
+
to open a menu where you can pin a column to a specific priority slot, remove it, or
|
|
169000
|
+
clear the cascade.
|
|
169001
|
+
</p>
|
|
169002
|
+
<dees-table
|
|
169003
|
+
heading1="People Directory"
|
|
169004
|
+
heading2="Pre-seeded with department ▲ 1, name ▲ 2"
|
|
169005
|
+
.sortBy=${[
|
|
169006
|
+
{ key: "department", dir: "asc" },
|
|
169007
|
+
{ key: "name", dir: "asc" }
|
|
169008
|
+
]}
|
|
169009
|
+
.columns=${[
|
|
169010
|
+
{ key: "department", header: "Department", sortable: true },
|
|
169011
|
+
{ key: "name", header: "Name", sortable: true },
|
|
169012
|
+
{ key: "role", header: "Role", sortable: true },
|
|
169013
|
+
{ key: "createdAt", header: "Created", sortable: true },
|
|
169014
|
+
{ key: "location", header: "Location", sortable: true },
|
|
169015
|
+
{ key: "status", header: "Status", sortable: true }
|
|
169016
|
+
]}
|
|
169017
|
+
.data=${[
|
|
169018
|
+
{ department: "R&D", name: "Alice Johnson", role: "Engineer", createdAt: "2023-01-12", location: "Berlin", status: "Active" },
|
|
169019
|
+
{ department: "R&D", name: "Diana Martinez", role: "Engineer", createdAt: "2020-06-30", location: "Madrid", status: "Active" },
|
|
169020
|
+
{ department: "R&D", name: "Mark Lee", role: "Engineer", createdAt: "2024-03-04", location: "Berlin", status: "Active" },
|
|
169021
|
+
{ department: "Design", name: "Bob Smith", role: "Designer", createdAt: "2022-11-05", location: "Paris", status: "Active" },
|
|
169022
|
+
{ department: "Design", name: "Sara Kim", role: "Designer", createdAt: "2021-08-19", location: "Paris", status: "On Leave" },
|
|
169023
|
+
{ department: "Ops", name: "Charlie Davis", role: "Manager", createdAt: "2021-04-21", location: "London", status: "On Leave" },
|
|
169024
|
+
{ department: "Ops", name: "Helena Voss", role: "SRE", createdAt: "2023-07-22", location: "London", status: "Active" },
|
|
169025
|
+
{ department: "QA", name: "Fiona Clark", role: "QA", createdAt: "2022-03-14", location: "Vienna", status: "Active" },
|
|
169026
|
+
{ department: "QA", name: "Tom\xE1s Rivera", role: "QA", createdAt: "2024-01-09", location: "Madrid", status: "Active" },
|
|
169027
|
+
{ department: "CS", name: "Ethan Brown", role: "Support", createdAt: "2019-09-18", location: "Rome", status: "Inactive" }
|
|
169028
|
+
]}
|
|
169029
|
+
></dees-table>
|
|
169030
|
+
</div>
|
|
169031
|
+
|
|
168994
169032
|
<div class="demo-section">
|
|
168995
169033
|
<h2 class="demo-title">Wide Properties + Many Actions</h2>
|
|
168996
169034
|
<p class="demo-description">A table with many columns and rich actions to stress test layout and sticky Actions.</p>
|
|
@@ -169222,29 +169260,48 @@ var tableStyles = [
|
|
|
169222
169260
|
border-bottom-width: 0px;
|
|
169223
169261
|
}
|
|
169224
169262
|
|
|
169263
|
+
/* Default mode (Mode B, page sticky): horizontal scroll lives on
|
|
169264
|
+
.tableScroll (so wide tables don't get clipped by an ancestor
|
|
169265
|
+
overflow:hidden such as dees-tile). Vertical sticky is handled by
|
|
169266
|
+
a JS-managed floating header (.floatingHeader, position:fixed),
|
|
169267
|
+
which is unaffected by ancestor overflow. */
|
|
169225
169268
|
.tableScroll {
|
|
169226
|
-
|
|
169269
|
+
position: relative;
|
|
169227
169270
|
overflow-x: auto;
|
|
169228
|
-
|
|
169229
|
-
|
|
169230
|
-
|
|
169271
|
+
overflow-y: visible;
|
|
169272
|
+
scrollbar-gutter: stable;
|
|
169273
|
+
}
|
|
169274
|
+
/* Mode A, internal scroll: opt-in via fixed-height attribute.
|
|
169275
|
+
The table scrolls inside its own box and the header sticks via plain CSS sticky. */
|
|
169276
|
+
:host([fixed-height]) .tableScroll {
|
|
169277
|
+
max-height: var(--table-max-height, 360px);
|
|
169278
|
+
overflow: auto;
|
|
169231
169279
|
scrollbar-gutter: stable both-edges;
|
|
169232
169280
|
}
|
|
169233
|
-
|
|
169234
|
-
|
|
169235
|
-
|
|
169236
|
-
|
|
169281
|
+
:host([fixed-height]) .tableScroll::-webkit-scrollbar:horizontal {
|
|
169282
|
+
height: 0px;
|
|
169283
|
+
}
|
|
169284
|
+
|
|
169285
|
+
/* Floating header overlay (Mode B). Position is managed by JS so it
|
|
169286
|
+
escapes any ancestor overflow:hidden (position:fixed is not clipped
|
|
169287
|
+
by overflow ancestors). */
|
|
169288
|
+
.floatingHeader {
|
|
169289
|
+
position: fixed;
|
|
169290
|
+
top: 0;
|
|
169291
|
+
left: 0;
|
|
169292
|
+
z-index: 100;
|
|
169293
|
+
visibility: hidden;
|
|
169294
|
+
overflow: hidden;
|
|
169295
|
+
pointer-events: none;
|
|
169237
169296
|
}
|
|
169238
|
-
|
|
169239
|
-
|
|
169297
|
+
.floatingHeader.active {
|
|
169298
|
+
visibility: visible;
|
|
169240
169299
|
}
|
|
169241
|
-
|
|
169242
|
-
|
|
169243
|
-
height: 0px;
|
|
169300
|
+
.floatingHeader table {
|
|
169301
|
+
margin: 0;
|
|
169244
169302
|
}
|
|
169245
|
-
|
|
169246
|
-
|
|
169247
|
-
overflow: auto;
|
|
169303
|
+
.floatingHeader th {
|
|
169304
|
+
pointer-events: auto;
|
|
169248
169305
|
}
|
|
169249
169306
|
|
|
169250
169307
|
table {
|
|
@@ -169267,11 +169324,20 @@ var tableStyles = [
|
|
|
169267
169324
|
background: ${cssManager.bdTheme("hsl(210 40% 96.1%)", "hsl(0 0% 9%)")};
|
|
169268
169325
|
border-bottom: 1px solid var(--dees-color-border-strong);
|
|
169269
169326
|
}
|
|
169270
|
-
|
|
169327
|
+
/* th needs its own background so sticky cells paint over scrolled rows
|
|
169328
|
+
(browsers don't paint the <thead> box behind a sticky <th>). */
|
|
169329
|
+
th {
|
|
169330
|
+
background: ${cssManager.bdTheme("hsl(210 40% 96.1%)", "hsl(0 0% 9%)")};
|
|
169331
|
+
}
|
|
169332
|
+
/* Mode A — internal scroll sticky */
|
|
169333
|
+
:host([fixed-height]) thead th {
|
|
169271
169334
|
position: sticky;
|
|
169272
169335
|
top: 0;
|
|
169273
169336
|
z-index: 2;
|
|
169274
169337
|
}
|
|
169338
|
+
:host([fixed-height]) thead tr.filtersRow th {
|
|
169339
|
+
top: 36px; /* matches th { height: 36px } below */
|
|
169340
|
+
}
|
|
169275
169341
|
|
|
169276
169342
|
tbody tr {
|
|
169277
169343
|
transition: background-color 0.15s ease;
|
|
@@ -169384,6 +169450,32 @@ var tableStyles = [
|
|
|
169384
169450
|
color: ${cssManager.bdTheme("hsl(215.4 16.3% 46.9%)", "hsl(215 20.2% 65.1%)")};
|
|
169385
169451
|
letter-spacing: -0.01em;
|
|
169386
169452
|
}
|
|
169453
|
+
|
|
169454
|
+
th[role='columnheader']:hover {
|
|
169455
|
+
color: var(--dees-color-text-primary);
|
|
169456
|
+
}
|
|
169457
|
+
|
|
169458
|
+
th .sortArrow {
|
|
169459
|
+
display: inline-block;
|
|
169460
|
+
margin-left: 6px;
|
|
169461
|
+
font-size: 10px;
|
|
169462
|
+
line-height: 1;
|
|
169463
|
+
opacity: 0.7;
|
|
169464
|
+
vertical-align: middle;
|
|
169465
|
+
}
|
|
169466
|
+
|
|
169467
|
+
th .sortBadge {
|
|
169468
|
+
display: inline-block;
|
|
169469
|
+
margin-left: 3px;
|
|
169470
|
+
padding: 1px 5px;
|
|
169471
|
+
font-size: 10px;
|
|
169472
|
+
font-weight: 600;
|
|
169473
|
+
line-height: 1;
|
|
169474
|
+
color: ${cssManager.bdTheme("hsl(222.2 47.4% 30%)", "hsl(217.2 91.2% 75%)")};
|
|
169475
|
+
background: ${cssManager.bdTheme("hsl(222.2 47.4% 51.2% / 0.12)", "hsl(217.2 91.2% 59.8% / 0.18)")};
|
|
169476
|
+
border-radius: 999px;
|
|
169477
|
+
vertical-align: middle;
|
|
169478
|
+
}
|
|
169387
169479
|
|
|
169388
169480
|
:host([show-vertical-lines]) th {
|
|
169389
169481
|
border-right: 1px solid var(--dees-color-border-default);
|
|
@@ -169575,7 +169667,23 @@ function getCellValue(row, col, displayFunction) {
|
|
|
169575
169667
|
return col.value ? col.value(row) : row[col.key];
|
|
169576
169668
|
}
|
|
169577
169669
|
__name(getCellValue, "getCellValue");
|
|
169578
|
-
function
|
|
169670
|
+
function compareCellValues(va, vb) {
|
|
169671
|
+
if (va == null && vb == null) return 0;
|
|
169672
|
+
if (va == null) return -1;
|
|
169673
|
+
if (vb == null) return 1;
|
|
169674
|
+
if (typeof va === "number" && typeof vb === "number") {
|
|
169675
|
+
if (va < vb) return -1;
|
|
169676
|
+
if (va > vb) return 1;
|
|
169677
|
+
return 0;
|
|
169678
|
+
}
|
|
169679
|
+
const sa = String(va).toLowerCase();
|
|
169680
|
+
const sb = String(vb).toLowerCase();
|
|
169681
|
+
if (sa < sb) return -1;
|
|
169682
|
+
if (sa > sb) return 1;
|
|
169683
|
+
return 0;
|
|
169684
|
+
}
|
|
169685
|
+
__name(compareCellValues, "compareCellValues");
|
|
169686
|
+
function getViewData(data, effectiveColumns, sortBy, filterText, columnFilters, filterMode = "table", lucenePredicate) {
|
|
169579
169687
|
let arr = data.slice();
|
|
169580
169688
|
const ft = (filterText || "").trim().toLowerCase();
|
|
169581
169689
|
const cf = columnFilters || {};
|
|
@@ -169589,9 +169697,9 @@ function getViewData(data, effectiveColumns, sortKey, sortDir, filterText, colum
|
|
|
169589
169697
|
const needle = String(cf[k4]).toLowerCase();
|
|
169590
169698
|
if (!s10.includes(needle)) return false;
|
|
169591
169699
|
} else {
|
|
169592
|
-
const
|
|
169593
|
-
if (!
|
|
169594
|
-
const val = getCellValue(row,
|
|
169700
|
+
const col = effectiveColumns.find((c11) => String(c11.key) === k4);
|
|
169701
|
+
if (!col || col.hidden || col.filterable === false) continue;
|
|
169702
|
+
const val = getCellValue(row, col);
|
|
169595
169703
|
const s10 = String(val ?? "").toLowerCase();
|
|
169596
169704
|
const needle = String(cf[k4]).toLowerCase();
|
|
169597
169705
|
if (!s10.includes(needle)) return false;
|
|
@@ -169612,9 +169720,9 @@ function getViewData(data, effectiveColumns, sortKey, sortDir, filterText, colum
|
|
|
169612
169720
|
}
|
|
169613
169721
|
}
|
|
169614
169722
|
} else {
|
|
169615
|
-
for (const
|
|
169616
|
-
if (
|
|
169617
|
-
const val = getCellValue(row,
|
|
169723
|
+
for (const col of effectiveColumns) {
|
|
169724
|
+
if (col.hidden) continue;
|
|
169725
|
+
const val = getCellValue(row, col);
|
|
169618
169726
|
const s10 = String(val ?? "").toLowerCase();
|
|
169619
169727
|
if (s10.includes(ft)) {
|
|
169620
169728
|
any = true;
|
|
@@ -169627,21 +169735,14 @@ function getViewData(data, effectiveColumns, sortKey, sortDir, filterText, colum
|
|
|
169627
169735
|
return true;
|
|
169628
169736
|
});
|
|
169629
169737
|
}
|
|
169630
|
-
if (!
|
|
169631
|
-
const
|
|
169632
|
-
if (
|
|
169633
|
-
const dir = sortDir === "asc" ? 1 : -1;
|
|
169738
|
+
if (!sortBy || sortBy.length === 0) return arr;
|
|
169739
|
+
const resolved2 = sortBy.map((desc) => ({ desc, col: effectiveColumns.find((c11) => String(c11.key) === desc.key) })).filter((entry) => !!entry.col);
|
|
169740
|
+
if (resolved2.length === 0) return arr;
|
|
169634
169741
|
arr.sort((a5, b5) => {
|
|
169635
|
-
const
|
|
169636
|
-
|
|
169637
|
-
|
|
169638
|
-
|
|
169639
|
-
if (vb == null) return 1 * dir;
|
|
169640
|
-
if (typeof va === "number" && typeof vb === "number") return (va - vb) * dir;
|
|
169641
|
-
const sa = String(va).toLowerCase();
|
|
169642
|
-
const sb = String(vb).toLowerCase();
|
|
169643
|
-
if (sa < sb) return -1 * dir;
|
|
169644
|
-
if (sa > sb) return 1 * dir;
|
|
169742
|
+
for (const { desc, col } of resolved2) {
|
|
169743
|
+
const cmp2 = compareCellValues(getCellValue(a5, col), getCellValue(b5, col));
|
|
169744
|
+
if (cmp2 !== 0) return desc.dir === "asc" ? cmp2 : -cmp2;
|
|
169745
|
+
}
|
|
169645
169746
|
return 0;
|
|
169646
169747
|
});
|
|
169647
169748
|
return arr;
|
|
@@ -169794,7 +169895,13 @@ __name(compileLucenePredicate, "compileLucenePredicate");
|
|
|
169794
169895
|
init_dist_ts30();
|
|
169795
169896
|
init_dist_ts29();
|
|
169796
169897
|
init_theme();
|
|
169797
|
-
var _selectedIds_dec, _selectionMode_dec, _searchMode_dec,
|
|
169898
|
+
var _selectedIds_dec, _selectionMode_dec, _searchMode_dec, _fixedHeight_dec, _showColumnFilters_dec, _columnFilters_dec, _filterText_dec, _sortBy_dec, _showGrid_dec, _showHorizontalLines_dec, _showVerticalLines_dec, _editableFields_dec, _selectedDataRow_dec, _reverseDisplayFunction_dec, _displayFunction_dec, _augmentFromDisplayFunction_dec, _rowKey_dec, _columns_dec, _dataActions_dec, _searchable_dec, _dataName_dec, _required_dec3, _disabled_dec3, _label_dec3, _key_dec2, _data_dec, _heading2_dec, _heading1_dec, _a42, _DeesTable_decorators, _init39, _heading1, _heading22, _data, _key2, _label3, _disabled3, _required3, _dataName, _searchable, _dataActions, _columns, _rowKey, _augmentFromDisplayFunction, _displayFunction, _reverseDisplayFunction, _selectedDataRow, _editableFields, _showVerticalLines, _showHorizontalLines, _showGrid, _sortBy, _filterText, _columnFilters, _showColumnFilters, _fixedHeight, _searchMode, _selectionMode, _selectedIds;
|
|
169899
|
+
function ordinalLabel(n12) {
|
|
169900
|
+
const s10 = ["th", "st", "nd", "rd"];
|
|
169901
|
+
const v5 = n12 % 100;
|
|
169902
|
+
return n12 + (s10[(v5 - 20) % 10] || s10[v5] || s10[0]);
|
|
169903
|
+
}
|
|
169904
|
+
__name(ordinalLabel, "ordinalLabel");
|
|
169798
169905
|
_DeesTable_decorators = [customElement("dees-table")];
|
|
169799
169906
|
var _DeesTable = class _DeesTable extends (_a42 = DeesElement, _heading1_dec = [n5({
|
|
169800
169907
|
type: String
|
|
@@ -169837,7 +169944,7 @@ var _DeesTable = class _DeesTable extends (_a42 = DeesElement, _heading1_dec = [
|
|
|
169837
169944
|
type: Boolean,
|
|
169838
169945
|
reflect: true,
|
|
169839
169946
|
attribute: "show-grid"
|
|
169840
|
-
})],
|
|
169947
|
+
})], _sortBy_dec = [n5({ attribute: false })], _filterText_dec = [n5({ type: String })], _columnFilters_dec = [n5({ attribute: false })], _showColumnFilters_dec = [n5({ type: Boolean, attribute: "show-column-filters" })], _fixedHeight_dec = [n5({ type: Boolean, reflect: true, attribute: "fixed-height" })], _searchMode_dec = [n5({ type: String })], _selectionMode_dec = [n5({ type: String })], _selectedIds_dec = [n5({ attribute: false })], _a42) {
|
|
169841
169948
|
constructor() {
|
|
169842
169949
|
super();
|
|
169843
169950
|
__privateAdd(this, _heading1, __runInitializers(_init39, 8, this, "heading 1")), __runInitializers(_init39, 11, this);
|
|
@@ -169864,19 +169971,23 @@ var _DeesTable = class _DeesTable extends (_a42 = DeesElement, _heading1_dec = [
|
|
|
169864
169971
|
__publicField(this, "files", []);
|
|
169865
169972
|
__publicField(this, "fileWeakMap", /* @__PURE__ */ new WeakMap());
|
|
169866
169973
|
__publicField(this, "dataChangeSubject", new domtools_pluginexports_exports.smartrx.rxjs.Subject());
|
|
169867
|
-
__privateAdd(this,
|
|
169868
|
-
__privateAdd(this,
|
|
169869
|
-
__privateAdd(this,
|
|
169870
|
-
__privateAdd(this,
|
|
169871
|
-
__privateAdd(this,
|
|
169872
|
-
__privateAdd(this,
|
|
169873
|
-
__privateAdd(this, _searchMode, __runInitializers(_init39, 112, this, "table")), __runInitializers(_init39, 115, this);
|
|
169974
|
+
__privateAdd(this, _sortBy, __runInitializers(_init39, 88, this, [])), __runInitializers(_init39, 91, this);
|
|
169975
|
+
__privateAdd(this, _filterText, __runInitializers(_init39, 92, this, "")), __runInitializers(_init39, 95, this);
|
|
169976
|
+
__privateAdd(this, _columnFilters, __runInitializers(_init39, 96, this, {})), __runInitializers(_init39, 99, this);
|
|
169977
|
+
__privateAdd(this, _showColumnFilters, __runInitializers(_init39, 100, this, false)), __runInitializers(_init39, 103, this);
|
|
169978
|
+
__privateAdd(this, _fixedHeight, __runInitializers(_init39, 104, this, false)), __runInitializers(_init39, 107, this);
|
|
169979
|
+
__privateAdd(this, _searchMode, __runInitializers(_init39, 108, this, "table")), __runInitializers(_init39, 111, this);
|
|
169874
169980
|
__publicField(this, "__searchTextSub");
|
|
169875
169981
|
__publicField(this, "__searchModeSub");
|
|
169876
|
-
__privateAdd(this, _selectionMode, __runInitializers(_init39,
|
|
169877
|
-
__privateAdd(this, _selectedIds, __runInitializers(_init39,
|
|
169982
|
+
__privateAdd(this, _selectionMode, __runInitializers(_init39, 112, this, "none")), __runInitializers(_init39, 115, this);
|
|
169983
|
+
__privateAdd(this, _selectedIds, __runInitializers(_init39, 116, this, /* @__PURE__ */ new Set())), __runInitializers(_init39, 119, this);
|
|
169878
169984
|
__publicField(this, "_rowIdMap", /* @__PURE__ */ new WeakMap());
|
|
169879
169985
|
__publicField(this, "_rowIdCounter", 0);
|
|
169986
|
+
// ─── Floating header (page-sticky) lifecycle ─────────────────────────
|
|
169987
|
+
__publicField(this, "__floatingResizeObserver");
|
|
169988
|
+
__publicField(this, "__floatingScrollHandler");
|
|
169989
|
+
__publicField(this, "__floatingActive", false);
|
|
169990
|
+
__publicField(this, "__scrollAncestors", []);
|
|
169880
169991
|
__publicField(this, "__debounceTimer");
|
|
169881
169992
|
}
|
|
169882
169993
|
get value() {
|
|
@@ -169895,8 +170006,7 @@ var _DeesTable = class _DeesTable extends (_a42 = DeesElement, _heading1_dec = [
|
|
|
169895
170006
|
const viewData = getViewData(
|
|
169896
170007
|
this.data,
|
|
169897
170008
|
effectiveColumns,
|
|
169898
|
-
this.
|
|
169899
|
-
this.sortDir,
|
|
170009
|
+
this.sortBy,
|
|
169900
170010
|
this.filterText,
|
|
169901
170011
|
this.columnFilters,
|
|
169902
170012
|
this.searchMode === "data" ? "data" : "table",
|
|
@@ -169968,57 +170078,7 @@ var _DeesTable = class _DeesTable extends (_a42 = DeesElement, _heading1_dec = [
|
|
|
169968
170078
|
<div class="tableScroll">
|
|
169969
170079
|
<table>
|
|
169970
170080
|
<thead>
|
|
169971
|
-
|
|
169972
|
-
${this.selectionMode !== "none" ? b2`
|
|
169973
|
-
<th style="width:42px; text-align:center;">
|
|
169974
|
-
${this.selectionMode === "multi" ? b2`
|
|
169975
|
-
<dees-input-checkbox
|
|
169976
|
-
.value=${this.areAllVisibleSelected()}
|
|
169977
|
-
.indeterminate=${this.isVisibleSelectionIndeterminate()}
|
|
169978
|
-
@newValue=${(e11) => {
|
|
169979
|
-
e11.stopPropagation();
|
|
169980
|
-
this.setSelectVisible(e11.detail === true);
|
|
169981
|
-
}}
|
|
169982
|
-
></dees-input-checkbox>
|
|
169983
|
-
` : b2``}
|
|
169984
|
-
</th>
|
|
169985
|
-
` : b2``}
|
|
169986
|
-
${effectiveColumns.filter((c11) => !c11.hidden).map((col) => {
|
|
169987
|
-
const isSortable = !!col.sortable;
|
|
169988
|
-
const ariaSort = this.getAriaSort(col);
|
|
169989
|
-
return b2`
|
|
169990
|
-
<th
|
|
169991
|
-
role="columnheader"
|
|
169992
|
-
aria-sort=${ariaSort}
|
|
169993
|
-
style="${isSortable ? "cursor: pointer;" : ""}"
|
|
169994
|
-
@click=${() => isSortable ? this.toggleSort(col) : null}
|
|
169995
|
-
>
|
|
169996
|
-
${col.header ?? col.key}
|
|
169997
|
-
${this.renderSortIndicator(col)}
|
|
169998
|
-
</th>`;
|
|
169999
|
-
})}
|
|
170000
|
-
${(() => {
|
|
170001
|
-
if (this.dataActions && this.dataActions.length > 0) {
|
|
170002
|
-
return b2` <th class="actionsCol">Actions</th> `;
|
|
170003
|
-
}
|
|
170004
|
-
})()}
|
|
170005
|
-
</tr>
|
|
170006
|
-
${this.showColumnFilters ? b2`<tr class="filtersRow">
|
|
170007
|
-
${this.selectionMode !== "none" ? b2`<th style="width:42px;"></th>` : b2``}
|
|
170008
|
-
${effectiveColumns.filter((c11) => !c11.hidden).map((col) => {
|
|
170009
|
-
const key2 = String(col.key);
|
|
170010
|
-
if (col.filterable === false) return b2`<th></th>`;
|
|
170011
|
-
return b2`<th>
|
|
170012
|
-
<input type="text" placeholder="Filter..." .value=${this.columnFilters[key2] || ""}
|
|
170013
|
-
@input=${(e11) => this.setColumnFilter(key2, e11.target.value)} />
|
|
170014
|
-
</th>`;
|
|
170015
|
-
})}
|
|
170016
|
-
${(() => {
|
|
170017
|
-
if (this.dataActions && this.dataActions.length > 0) {
|
|
170018
|
-
return b2` <th></th> `;
|
|
170019
|
-
}
|
|
170020
|
-
})()}
|
|
170021
|
-
</tr>` : b2``}
|
|
170081
|
+
${this.renderHeaderRows(effectiveColumns)}
|
|
170022
170082
|
</thead>
|
|
170023
170083
|
<tbody>
|
|
170024
170084
|
${viewData.map((itemArg, rowIndex) => {
|
|
@@ -170152,6 +170212,13 @@ var _DeesTable = class _DeesTable extends (_a42 = DeesElement, _heading1_dec = [
|
|
|
170152
170212
|
</tbody>
|
|
170153
170213
|
</table>
|
|
170154
170214
|
</div>
|
|
170215
|
+
<div class="floatingHeader" aria-hidden="true">
|
|
170216
|
+
<table>
|
|
170217
|
+
<thead>
|
|
170218
|
+
${this.renderHeaderRows(effectiveColumns)}
|
|
170219
|
+
</thead>
|
|
170220
|
+
</table>
|
|
170221
|
+
</div>
|
|
170155
170222
|
` : b2` <div class="noDataSet">No data set!</div> `}
|
|
170156
170223
|
<div slot="footer" class="footer">
|
|
170157
170224
|
<div class="tableStatistics">
|
|
@@ -170186,11 +170253,226 @@ var _DeesTable = class _DeesTable extends (_a42 = DeesElement, _heading1_dec = [
|
|
|
170186
170253
|
</dees-tile>
|
|
170187
170254
|
`;
|
|
170188
170255
|
}
|
|
170256
|
+
/**
|
|
170257
|
+
* Renders the header rows. Used twice per render: once inside the real
|
|
170258
|
+
* `<thead>` and once inside the floating-header clone, so sort indicators
|
|
170259
|
+
* and filter inputs stay in sync automatically.
|
|
170260
|
+
*/
|
|
170261
|
+
renderHeaderRows(effectiveColumns) {
|
|
170262
|
+
return b2`
|
|
170263
|
+
<tr>
|
|
170264
|
+
${this.selectionMode !== "none" ? b2`
|
|
170265
|
+
<th style="width:42px; text-align:center;">
|
|
170266
|
+
${this.selectionMode === "multi" ? b2`
|
|
170267
|
+
<dees-input-checkbox
|
|
170268
|
+
.value=${this.areAllVisibleSelected()}
|
|
170269
|
+
.indeterminate=${this.isVisibleSelectionIndeterminate()}
|
|
170270
|
+
@newValue=${(e11) => {
|
|
170271
|
+
e11.stopPropagation();
|
|
170272
|
+
this.setSelectVisible(e11.detail === true);
|
|
170273
|
+
}}
|
|
170274
|
+
></dees-input-checkbox>
|
|
170275
|
+
` : b2``}
|
|
170276
|
+
</th>
|
|
170277
|
+
` : b2``}
|
|
170278
|
+
${effectiveColumns.filter((c11) => !c11.hidden).map((col) => {
|
|
170279
|
+
const isSortable = !!col.sortable;
|
|
170280
|
+
const ariaSort = this.getAriaSort(col);
|
|
170281
|
+
return b2`
|
|
170282
|
+
<th
|
|
170283
|
+
role="columnheader"
|
|
170284
|
+
aria-sort=${ariaSort}
|
|
170285
|
+
style="${isSortable ? "cursor: pointer;" : ""}"
|
|
170286
|
+
@click=${(eventArg) => isSortable ? this.handleHeaderClick(eventArg, col, effectiveColumns) : null}
|
|
170287
|
+
@contextmenu=${(eventArg) => isSortable ? this.openHeaderContextMenu(eventArg, col, effectiveColumns) : null}
|
|
170288
|
+
>
|
|
170289
|
+
${col.header ?? col.key}
|
|
170290
|
+
${this.renderSortIndicator(col)}
|
|
170291
|
+
</th>`;
|
|
170292
|
+
})}
|
|
170293
|
+
${this.dataActions && this.dataActions.length > 0 ? b2`<th class="actionsCol">Actions</th>` : b2``}
|
|
170294
|
+
</tr>
|
|
170295
|
+
${this.showColumnFilters ? b2`<tr class="filtersRow">
|
|
170296
|
+
${this.selectionMode !== "none" ? b2`<th style="width:42px;"></th>` : b2``}
|
|
170297
|
+
${effectiveColumns.filter((c11) => !c11.hidden).map((col) => {
|
|
170298
|
+
const key2 = String(col.key);
|
|
170299
|
+
if (col.filterable === false) return b2`<th></th>`;
|
|
170300
|
+
return b2`<th>
|
|
170301
|
+
<input type="text" placeholder="Filter..." .value=${this.columnFilters[key2] || ""}
|
|
170302
|
+
@input=${(e11) => this.setColumnFilter(key2, e11.target.value)} />
|
|
170303
|
+
</th>`;
|
|
170304
|
+
})}
|
|
170305
|
+
${this.dataActions && this.dataActions.length > 0 ? b2`<th></th>` : b2``}
|
|
170306
|
+
</tr>` : b2``}
|
|
170307
|
+
`;
|
|
170308
|
+
}
|
|
170309
|
+
get __floatingHeaderEl() {
|
|
170310
|
+
return this.shadowRoot?.querySelector(".floatingHeader") ?? null;
|
|
170311
|
+
}
|
|
170312
|
+
get __realTableEl() {
|
|
170313
|
+
return this.shadowRoot?.querySelector(".tableScroll > table") ?? null;
|
|
170314
|
+
}
|
|
170315
|
+
get __floatingTableEl() {
|
|
170316
|
+
return this.shadowRoot?.querySelector(".floatingHeader > table") ?? null;
|
|
170317
|
+
}
|
|
170318
|
+
/**
|
|
170319
|
+
* Walks up the DOM (and through shadow roots) collecting every ancestor
|
|
170320
|
+
* element whose computed `overflow-y` makes it a scroll container, plus
|
|
170321
|
+
* `window` at the end. We listen for scroll on all of them so the floating
|
|
170322
|
+
* header reacts whether the user scrolls the page or any nested container.
|
|
170323
|
+
*/
|
|
170324
|
+
__collectScrollAncestors() {
|
|
170325
|
+
const result = [];
|
|
170326
|
+
let node2 = this;
|
|
170327
|
+
const scrollish = /* @__PURE__ */ __name((v5) => v5 === "auto" || v5 === "scroll" || v5 === "overlay", "scrollish");
|
|
170328
|
+
while (node2) {
|
|
170329
|
+
if (node2 instanceof Element) {
|
|
170330
|
+
const style2 = getComputedStyle(node2);
|
|
170331
|
+
const sy = scrollish(style2.overflowY);
|
|
170332
|
+
const sx = scrollish(style2.overflowX);
|
|
170333
|
+
if (sy || sx) {
|
|
170334
|
+
result.push({ target: node2, scrollsY: sy, scrollsX: sx });
|
|
170335
|
+
}
|
|
170336
|
+
}
|
|
170337
|
+
const parent = node2.assignedSlot ? node2.assignedSlot : node2.parentNode;
|
|
170338
|
+
if (parent) {
|
|
170339
|
+
node2 = parent;
|
|
170340
|
+
} else if (node2.host) {
|
|
170341
|
+
node2 = node2.host;
|
|
170342
|
+
} else {
|
|
170343
|
+
node2 = null;
|
|
170344
|
+
}
|
|
170345
|
+
}
|
|
170346
|
+
result.push({ target: window, scrollsY: true, scrollsX: true });
|
|
170347
|
+
return result;
|
|
170348
|
+
}
|
|
170349
|
+
/**
|
|
170350
|
+
* Returns the "stick line" — the y-coordinate (in viewport space) at which
|
|
170351
|
+
* the floating header should appear. Defaults to 0 (page top), but if the
|
|
170352
|
+
* table is inside a scroll container we use that container's content-box
|
|
170353
|
+
* top so the header sits inside the container's border/padding instead of
|
|
170354
|
+
* floating over it.
|
|
170355
|
+
*/
|
|
170356
|
+
__getStickContext() {
|
|
170357
|
+
let top = 0;
|
|
170358
|
+
let left = 0;
|
|
170359
|
+
let right = window.innerWidth;
|
|
170360
|
+
for (const a5 of this.__scrollAncestors) {
|
|
170361
|
+
if (a5.target === window) continue;
|
|
170362
|
+
const el = a5.target;
|
|
170363
|
+
const r11 = el.getBoundingClientRect();
|
|
170364
|
+
const cs = getComputedStyle(el);
|
|
170365
|
+
if (a5.scrollsY) {
|
|
170366
|
+
const bt = parseFloat(cs.borderTopWidth) || 0;
|
|
170367
|
+
top = Math.max(top, r11.top + bt);
|
|
170368
|
+
}
|
|
170369
|
+
if (a5.scrollsX) {
|
|
170370
|
+
const bl = parseFloat(cs.borderLeftWidth) || 0;
|
|
170371
|
+
const br = parseFloat(cs.borderRightWidth) || 0;
|
|
170372
|
+
left = Math.max(left, r11.left + bl);
|
|
170373
|
+
right = Math.min(right, r11.right - br);
|
|
170374
|
+
}
|
|
170375
|
+
}
|
|
170376
|
+
return { top, left, right };
|
|
170377
|
+
}
|
|
170378
|
+
setupFloatingHeader() {
|
|
170379
|
+
this.teardownFloatingHeader();
|
|
170380
|
+
if (this.fixedHeight) return;
|
|
170381
|
+
const realTable = this.__realTableEl;
|
|
170382
|
+
if (!realTable) return;
|
|
170383
|
+
this.__scrollAncestors = this.__collectScrollAncestors();
|
|
170384
|
+
const tableScrollEl = this.shadowRoot?.querySelector(".tableScroll");
|
|
170385
|
+
if (tableScrollEl) {
|
|
170386
|
+
this.__scrollAncestors.unshift({ target: tableScrollEl, scrollsY: false, scrollsX: true });
|
|
170387
|
+
}
|
|
170388
|
+
this.__floatingResizeObserver = new ResizeObserver(() => {
|
|
170389
|
+
this.__syncFloatingHeader();
|
|
170390
|
+
});
|
|
170391
|
+
this.__floatingResizeObserver.observe(realTable);
|
|
170392
|
+
this.__floatingScrollHandler = () => this.__syncFloatingHeader();
|
|
170393
|
+
for (const a5 of this.__scrollAncestors) {
|
|
170394
|
+
a5.target.addEventListener("scroll", this.__floatingScrollHandler, { passive: true });
|
|
170395
|
+
}
|
|
170396
|
+
window.addEventListener("resize", this.__floatingScrollHandler, { passive: true });
|
|
170397
|
+
this.__syncFloatingHeader();
|
|
170398
|
+
}
|
|
170399
|
+
teardownFloatingHeader() {
|
|
170400
|
+
this.__floatingResizeObserver?.disconnect();
|
|
170401
|
+
this.__floatingResizeObserver = void 0;
|
|
170402
|
+
if (this.__floatingScrollHandler) {
|
|
170403
|
+
for (const a5 of this.__scrollAncestors) {
|
|
170404
|
+
a5.target.removeEventListener("scroll", this.__floatingScrollHandler);
|
|
170405
|
+
}
|
|
170406
|
+
window.removeEventListener("resize", this.__floatingScrollHandler);
|
|
170407
|
+
this.__floatingScrollHandler = void 0;
|
|
170408
|
+
}
|
|
170409
|
+
this.__scrollAncestors = [];
|
|
170410
|
+
this.__floatingActive = false;
|
|
170411
|
+
const fh = this.__floatingHeaderEl;
|
|
170412
|
+
if (fh) fh.classList.remove("active");
|
|
170413
|
+
}
|
|
170414
|
+
/**
|
|
170415
|
+
* Single function that drives both activation and geometry of the floating
|
|
170416
|
+
* header. Called on scroll, resize, table-resize, and after each render.
|
|
170417
|
+
*/
|
|
170418
|
+
__syncFloatingHeader() {
|
|
170419
|
+
const fh = this.__floatingHeaderEl;
|
|
170420
|
+
const realTable = this.__realTableEl;
|
|
170421
|
+
const floatTable = this.__floatingTableEl;
|
|
170422
|
+
if (!fh || !realTable || !floatTable) return;
|
|
170423
|
+
const tableRect = realTable.getBoundingClientRect();
|
|
170424
|
+
const stick = this.__getStickContext();
|
|
170425
|
+
floatTable.style.tableLayout = realTable.style.tableLayout || "auto";
|
|
170426
|
+
const realHeadRows = realTable.tHead?.rows;
|
|
170427
|
+
const floatHeadRows = floatTable.tHead?.rows;
|
|
170428
|
+
let headerHeight = 0;
|
|
170429
|
+
if (realHeadRows && floatHeadRows) {
|
|
170430
|
+
for (let r11 = 0; r11 < realHeadRows.length && r11 < floatHeadRows.length; r11++) {
|
|
170431
|
+
headerHeight += realHeadRows[r11].getBoundingClientRect().height;
|
|
170432
|
+
const realCells = realHeadRows[r11].cells;
|
|
170433
|
+
const floatCells = floatHeadRows[r11].cells;
|
|
170434
|
+
for (let c11 = 0; c11 < realCells.length && c11 < floatCells.length; c11++) {
|
|
170435
|
+
const w4 = realCells[c11].getBoundingClientRect().width;
|
|
170436
|
+
floatCells[c11].style.width = `${w4}px`;
|
|
170437
|
+
floatCells[c11].style.minWidth = `${w4}px`;
|
|
170438
|
+
floatCells[c11].style.maxWidth = `${w4}px`;
|
|
170439
|
+
}
|
|
170440
|
+
}
|
|
170441
|
+
}
|
|
170442
|
+
const shouldBeActive = tableRect.top < stick.top && tableRect.bottom > stick.top + Math.min(headerHeight, 1);
|
|
170443
|
+
if (shouldBeActive !== this.__floatingActive) {
|
|
170444
|
+
this.__floatingActive = shouldBeActive;
|
|
170445
|
+
fh.classList.toggle("active", shouldBeActive);
|
|
170446
|
+
}
|
|
170447
|
+
if (!shouldBeActive) return;
|
|
170448
|
+
const clipLeft = Math.max(tableRect.left, stick.left);
|
|
170449
|
+
const clipRight = Math.min(tableRect.right, stick.right);
|
|
170450
|
+
const clipWidth = Math.max(0, clipRight - clipLeft);
|
|
170451
|
+
fh.style.top = `${stick.top}px`;
|
|
170452
|
+
fh.style.left = `${clipLeft}px`;
|
|
170453
|
+
fh.style.width = `${clipWidth}px`;
|
|
170454
|
+
floatTable.style.width = `${tableRect.width}px`;
|
|
170455
|
+
floatTable.style.marginLeft = `${tableRect.left - clipLeft}px`;
|
|
170456
|
+
}
|
|
170457
|
+
async disconnectedCallback() {
|
|
170458
|
+
super.disconnectedCallback();
|
|
170459
|
+
this.teardownFloatingHeader();
|
|
170460
|
+
}
|
|
170189
170461
|
async firstUpdated() {
|
|
170190
170462
|
}
|
|
170191
170463
|
async updated(changedProperties) {
|
|
170192
170464
|
super.updated(changedProperties);
|
|
170193
170465
|
this.determineColumnWidths();
|
|
170466
|
+
if (changedProperties.has("fixedHeight") || changedProperties.has("data") || changedProperties.has("columns") || !this.__floatingScrollHandler) {
|
|
170467
|
+
if (!this.fixedHeight && this.data.length > 0) {
|
|
170468
|
+
this.setupFloatingHeader();
|
|
170469
|
+
} else {
|
|
170470
|
+
this.teardownFloatingHeader();
|
|
170471
|
+
}
|
|
170472
|
+
}
|
|
170473
|
+
if (!this.fixedHeight && this.data.length > 0) {
|
|
170474
|
+
this.__syncFloatingHeader();
|
|
170475
|
+
}
|
|
170194
170476
|
if (this.searchable) {
|
|
170195
170477
|
const existing = this.dataActions.find((actionArg) => actionArg.type?.includes("header") && actionArg.name === "Search");
|
|
170196
170478
|
if (!existing) {
|
|
@@ -170287,33 +170569,302 @@ var _DeesTable = class _DeesTable extends (_a42 = DeesElement, _heading1_dec = [
|
|
|
170287
170569
|
table2.style.tableLayout = "fixed";
|
|
170288
170570
|
}
|
|
170289
170571
|
// compute helpers moved to ./data.ts
|
|
170290
|
-
|
|
170291
|
-
|
|
170292
|
-
|
|
170293
|
-
|
|
170294
|
-
|
|
170295
|
-
|
|
170296
|
-
|
|
170297
|
-
|
|
170298
|
-
|
|
170299
|
-
|
|
170300
|
-
|
|
170301
|
-
}
|
|
170572
|
+
// ─── sort: public API ────────────────────────────────────────────────
|
|
170573
|
+
/** Returns the descriptor for `key` if the column is currently in the cascade. */
|
|
170574
|
+
getSortDescriptor(key2) {
|
|
170575
|
+
return this.sortBy.find((d6) => d6.key === key2);
|
|
170576
|
+
}
|
|
170577
|
+
/** Returns the 0-based priority of `key` in the cascade, or -1 if not present. */
|
|
170578
|
+
getSortPriority(key2) {
|
|
170579
|
+
return this.sortBy.findIndex((d6) => d6.key === key2);
|
|
170580
|
+
}
|
|
170581
|
+
/** Replaces the cascade with a single sort entry. */
|
|
170582
|
+
setSort(key2, dir) {
|
|
170583
|
+
this.sortBy = [{ key: key2, dir }];
|
|
170584
|
+
this.emitSortChange();
|
|
170585
|
+
this.requestUpdate();
|
|
170586
|
+
}
|
|
170587
|
+
/**
|
|
170588
|
+
* Inserts (or moves) `key` to a 0-based position in the cascade. If the key is
|
|
170589
|
+
* already present elsewhere, its previous entry is removed before insertion so
|
|
170590
|
+
* a column appears at most once.
|
|
170591
|
+
*/
|
|
170592
|
+
addSortAt(key2, position3, dir) {
|
|
170593
|
+
const next2 = this.sortBy.filter((d6) => d6.key !== key2);
|
|
170594
|
+
const clamped = Math.max(0, Math.min(position3, next2.length));
|
|
170595
|
+
next2.splice(clamped, 0, { key: key2, dir });
|
|
170596
|
+
this.sortBy = next2;
|
|
170597
|
+
this.emitSortChange();
|
|
170598
|
+
this.requestUpdate();
|
|
170599
|
+
}
|
|
170600
|
+
/** Appends `key` to the end of the cascade (or moves it there if already present). */
|
|
170601
|
+
appendSort(key2, dir) {
|
|
170602
|
+
const next2 = this.sortBy.filter((d6) => d6.key !== key2);
|
|
170603
|
+
next2.push({ key: key2, dir });
|
|
170604
|
+
this.sortBy = next2;
|
|
170605
|
+
this.emitSortChange();
|
|
170606
|
+
this.requestUpdate();
|
|
170607
|
+
}
|
|
170608
|
+
/** Removes `key` from the cascade. No-op if not present. */
|
|
170609
|
+
removeSort(key2) {
|
|
170610
|
+
if (!this.sortBy.some((d6) => d6.key === key2)) return;
|
|
170611
|
+
this.sortBy = this.sortBy.filter((d6) => d6.key !== key2);
|
|
170612
|
+
this.emitSortChange();
|
|
170613
|
+
this.requestUpdate();
|
|
170614
|
+
}
|
|
170615
|
+
/** Empties the cascade. */
|
|
170616
|
+
clearSorts() {
|
|
170617
|
+
if (this.sortBy.length === 0) return;
|
|
170618
|
+
this.sortBy = [];
|
|
170619
|
+
this.emitSortChange();
|
|
170620
|
+
this.requestUpdate();
|
|
170621
|
+
}
|
|
170622
|
+
emitSortChange() {
|
|
170302
170623
|
this.dispatchEvent(
|
|
170303
170624
|
new CustomEvent("sortChange", {
|
|
170304
|
-
detail: {
|
|
170625
|
+
detail: { sortBy: this.sortBy.map((d6) => ({ ...d6 })) },
|
|
170305
170626
|
bubbles: true
|
|
170306
170627
|
})
|
|
170307
170628
|
);
|
|
170308
|
-
this.requestUpdate();
|
|
170309
170629
|
}
|
|
170630
|
+
// ─── sort: header interaction handlers ───────────────────────────────
|
|
170631
|
+
/**
|
|
170632
|
+
* Plain left-click on a sortable header. Cycles `none → asc → desc → none`
|
|
170633
|
+
* collapsing the cascade to a single column. If a multi-column cascade is
|
|
170634
|
+
* active, asks the user to confirm the destructive replacement first. A
|
|
170635
|
+
* Shift+click bypasses the modal and routes through the multi-sort cycle.
|
|
170636
|
+
*/
|
|
170637
|
+
async handleHeaderClick(eventArg, col, _effectiveColumns) {
|
|
170638
|
+
if (eventArg.shiftKey) {
|
|
170639
|
+
this.handleHeaderShiftClick(col);
|
|
170640
|
+
return;
|
|
170641
|
+
}
|
|
170642
|
+
const proceed = await this.confirmReplaceCascade(col);
|
|
170643
|
+
if (!proceed) return;
|
|
170644
|
+
this.cycleSingleSort(col);
|
|
170645
|
+
}
|
|
170646
|
+
/**
|
|
170647
|
+
* Cycles a single column through `none → asc → desc → none`, collapsing the
|
|
170648
|
+
* cascade. Used by both plain click and the menu's "Sort Ascending/Descending"
|
|
170649
|
+
* shortcuts (after confirmation).
|
|
170650
|
+
*/
|
|
170651
|
+
cycleSingleSort(col) {
|
|
170652
|
+
const key2 = String(col.key);
|
|
170653
|
+
const current = this.sortBy.length === 1 && this.sortBy[0].key === key2 ? this.sortBy[0].dir : null;
|
|
170654
|
+
if (current === "asc") this.setSort(key2, "desc");
|
|
170655
|
+
else if (current === "desc") this.clearSorts();
|
|
170656
|
+
else this.setSort(key2, "asc");
|
|
170657
|
+
}
|
|
170658
|
+
/**
|
|
170659
|
+
* Shift+click cycle on a sortable header. Edits the cascade in place without
|
|
170660
|
+
* destroying other sort keys: append → flip dir → remove.
|
|
170661
|
+
*/
|
|
170662
|
+
handleHeaderShiftClick(col) {
|
|
170663
|
+
const key2 = String(col.key);
|
|
170664
|
+
const existing = this.getSortDescriptor(key2);
|
|
170665
|
+
if (!existing) {
|
|
170666
|
+
this.appendSort(key2, "asc");
|
|
170667
|
+
} else if (existing.dir === "asc") {
|
|
170668
|
+
this.sortBy = this.sortBy.map((d6) => d6.key === key2 ? { key: key2, dir: "desc" } : d6);
|
|
170669
|
+
this.emitSortChange();
|
|
170670
|
+
this.requestUpdate();
|
|
170671
|
+
} else {
|
|
170672
|
+
this.removeSort(key2);
|
|
170673
|
+
}
|
|
170674
|
+
}
|
|
170675
|
+
/**
|
|
170676
|
+
* Opens a confirmation modal when the cascade has more than one entry and the
|
|
170677
|
+
* user attempts a destructive single-sort replacement. Resolves to `true` if
|
|
170678
|
+
* the user accepts, `false` if they cancel. If the cascade has 0 or 1 entries
|
|
170679
|
+
* the modal is skipped and we resolve to `true` immediately.
|
|
170680
|
+
*/
|
|
170681
|
+
confirmReplaceCascade(targetCol) {
|
|
170682
|
+
if (this.sortBy.length <= 1) return Promise.resolve(true);
|
|
170683
|
+
return new Promise((resolve2) => {
|
|
170684
|
+
let settled = false;
|
|
170685
|
+
const settle = /* @__PURE__ */ __name((result) => {
|
|
170686
|
+
if (settled) return;
|
|
170687
|
+
settled = true;
|
|
170688
|
+
resolve2(result);
|
|
170689
|
+
}, "settle");
|
|
170690
|
+
const summary = this.sortBy.map((d6, i11) => {
|
|
170691
|
+
const c11 = this._lookupColumnByKey?.(d6.key);
|
|
170692
|
+
const label = c11?.header ?? d6.key;
|
|
170693
|
+
return b2`<li>${i11 + 1}. ${label} ${d6.dir === "asc" ? "\u25B2" : "\u25BC"}</li>`;
|
|
170694
|
+
});
|
|
170695
|
+
DeesModal.createAndShow({
|
|
170696
|
+
heading: "Replace multi-column sort?",
|
|
170697
|
+
width: "small",
|
|
170698
|
+
showCloseButton: true,
|
|
170699
|
+
content: b2`
|
|
170700
|
+
<div style="font-size:13px; line-height:1.55;">
|
|
170701
|
+
<p style="margin:0 0 8px;">
|
|
170702
|
+
You currently have a ${this.sortBy.length}-column sort active:
|
|
170703
|
+
</p>
|
|
170704
|
+
<ul style="margin:0 0 12px; padding-left:18px;">${summary}</ul>
|
|
170705
|
+
<p style="margin:0;">
|
|
170706
|
+
Continuing will discard the cascade and replace it with a single sort on
|
|
170707
|
+
<strong>${targetCol.header ?? String(targetCol.key)}</strong>.
|
|
170708
|
+
</p>
|
|
170709
|
+
</div>
|
|
170710
|
+
`,
|
|
170711
|
+
menuOptions: [
|
|
170712
|
+
{
|
|
170713
|
+
name: "Cancel",
|
|
170714
|
+
iconName: "lucide:x",
|
|
170715
|
+
action: /* @__PURE__ */ __name(async (modal) => {
|
|
170716
|
+
settle(false);
|
|
170717
|
+
await modal.destroy();
|
|
170718
|
+
return null;
|
|
170719
|
+
}, "action")
|
|
170720
|
+
},
|
|
170721
|
+
{
|
|
170722
|
+
name: "Replace",
|
|
170723
|
+
iconName: "lucide:check",
|
|
170724
|
+
action: /* @__PURE__ */ __name(async (modal) => {
|
|
170725
|
+
settle(true);
|
|
170726
|
+
await modal.destroy();
|
|
170727
|
+
return null;
|
|
170728
|
+
}, "action")
|
|
170729
|
+
}
|
|
170730
|
+
]
|
|
170731
|
+
});
|
|
170732
|
+
});
|
|
170733
|
+
}
|
|
170734
|
+
/**
|
|
170735
|
+
* Looks up a column by its string key in the currently effective column set.
|
|
170736
|
+
* Used by the modal helper to render human-friendly labels.
|
|
170737
|
+
*/
|
|
170738
|
+
_lookupColumnByKey(key2) {
|
|
170739
|
+
const usingColumns = Array.isArray(this.columns) && this.columns.length > 0;
|
|
170740
|
+
const effective = usingColumns ? computeEffectiveColumns(this.columns, this.augmentFromDisplayFunction, this.displayFunction, this.data) : computeColumnsFromDisplayFunction(this.displayFunction, this.data);
|
|
170741
|
+
return effective.find((c11) => String(c11.key) === key2);
|
|
170742
|
+
}
|
|
170743
|
+
/**
|
|
170744
|
+
* Opens the header context menu for explicit multi-sort priority control.
|
|
170745
|
+
*/
|
|
170746
|
+
openHeaderContextMenu(eventArg, col, effectiveColumns) {
|
|
170747
|
+
const items = this.buildHeaderMenuItems(col, effectiveColumns);
|
|
170748
|
+
DeesContextmenu.openContextMenuWithOptions(eventArg, items);
|
|
170749
|
+
}
|
|
170750
|
+
/**
|
|
170751
|
+
* Builds the dynamic context-menu structure for a single column header.
|
|
170752
|
+
*/
|
|
170753
|
+
buildHeaderMenuItems(col, effectiveColumns) {
|
|
170754
|
+
const key2 = String(col.key);
|
|
170755
|
+
const existing = this.getSortDescriptor(key2);
|
|
170756
|
+
const cascadeLen = this.sortBy.length;
|
|
170757
|
+
const sortableColumnCount = effectiveColumns.filter((c11) => !!c11.sortable).length;
|
|
170758
|
+
const maxSlot = Math.min(
|
|
170759
|
+
Math.max(cascadeLen + (existing ? 0 : 1), 1),
|
|
170760
|
+
Math.max(sortableColumnCount, 1)
|
|
170761
|
+
);
|
|
170762
|
+
const items = [];
|
|
170763
|
+
items.push({
|
|
170764
|
+
name: "Sort Ascending",
|
|
170765
|
+
iconName: cascadeLen === 1 && existing?.dir === "asc" ? "lucide:check" : "lucide:arrowUp",
|
|
170766
|
+
action: /* @__PURE__ */ __name(async () => {
|
|
170767
|
+
if (await this.confirmReplaceCascade(col)) this.setSort(key2, "asc");
|
|
170768
|
+
return null;
|
|
170769
|
+
}, "action")
|
|
170770
|
+
});
|
|
170771
|
+
items.push({
|
|
170772
|
+
name: "Sort Descending",
|
|
170773
|
+
iconName: cascadeLen === 1 && existing?.dir === "desc" ? "lucide:check" : "lucide:arrowDown",
|
|
170774
|
+
action: /* @__PURE__ */ __name(async () => {
|
|
170775
|
+
if (await this.confirmReplaceCascade(col)) this.setSort(key2, "desc");
|
|
170776
|
+
return null;
|
|
170777
|
+
}, "action")
|
|
170778
|
+
});
|
|
170779
|
+
items.push({ divider: true });
|
|
170780
|
+
for (let slot = 1; slot <= maxSlot; slot++) {
|
|
170781
|
+
const ordinal = ordinalLabel(slot);
|
|
170782
|
+
const isCurrentSlot = existing && this.getSortPriority(key2) === slot - 1;
|
|
170783
|
+
items.push({
|
|
170784
|
+
name: `Set as ${ordinal} sort`,
|
|
170785
|
+
iconName: isCurrentSlot ? "lucide:check" : "lucide:listOrdered",
|
|
170786
|
+
submenu: [
|
|
170787
|
+
{
|
|
170788
|
+
name: "Ascending",
|
|
170789
|
+
iconName: "lucide:arrowUp",
|
|
170790
|
+
action: /* @__PURE__ */ __name(async () => {
|
|
170791
|
+
this.addSortAt(key2, slot - 1, "asc");
|
|
170792
|
+
return null;
|
|
170793
|
+
}, "action")
|
|
170794
|
+
},
|
|
170795
|
+
{
|
|
170796
|
+
name: "Descending",
|
|
170797
|
+
iconName: "lucide:arrowDown",
|
|
170798
|
+
action: /* @__PURE__ */ __name(async () => {
|
|
170799
|
+
this.addSortAt(key2, slot - 1, "desc");
|
|
170800
|
+
return null;
|
|
170801
|
+
}, "action")
|
|
170802
|
+
}
|
|
170803
|
+
]
|
|
170804
|
+
});
|
|
170805
|
+
}
|
|
170806
|
+
items.push({ divider: true });
|
|
170807
|
+
items.push({
|
|
170808
|
+
name: "Append to sort",
|
|
170809
|
+
iconName: "lucide:plus",
|
|
170810
|
+
submenu: [
|
|
170811
|
+
{
|
|
170812
|
+
name: "Ascending",
|
|
170813
|
+
iconName: "lucide:arrowUp",
|
|
170814
|
+
action: /* @__PURE__ */ __name(async () => {
|
|
170815
|
+
this.appendSort(key2, "asc");
|
|
170816
|
+
return null;
|
|
170817
|
+
}, "action")
|
|
170818
|
+
},
|
|
170819
|
+
{
|
|
170820
|
+
name: "Descending",
|
|
170821
|
+
iconName: "lucide:arrowDown",
|
|
170822
|
+
action: /* @__PURE__ */ __name(async () => {
|
|
170823
|
+
this.appendSort(key2, "desc");
|
|
170824
|
+
return null;
|
|
170825
|
+
}, "action")
|
|
170826
|
+
}
|
|
170827
|
+
]
|
|
170828
|
+
});
|
|
170829
|
+
if (existing) {
|
|
170830
|
+
items.push({ divider: true });
|
|
170831
|
+
items.push({
|
|
170832
|
+
name: "Remove from sort",
|
|
170833
|
+
iconName: "lucide:minus",
|
|
170834
|
+
action: /* @__PURE__ */ __name(async () => {
|
|
170835
|
+
this.removeSort(key2);
|
|
170836
|
+
return null;
|
|
170837
|
+
}, "action")
|
|
170838
|
+
});
|
|
170839
|
+
}
|
|
170840
|
+
if (cascadeLen > 0) {
|
|
170841
|
+
if (!existing) items.push({ divider: true });
|
|
170842
|
+
items.push({
|
|
170843
|
+
name: "Clear all sorts",
|
|
170844
|
+
iconName: "lucide:trash",
|
|
170845
|
+
action: /* @__PURE__ */ __name(async () => {
|
|
170846
|
+
this.clearSorts();
|
|
170847
|
+
return null;
|
|
170848
|
+
}, "action")
|
|
170849
|
+
});
|
|
170850
|
+
}
|
|
170851
|
+
return items;
|
|
170852
|
+
}
|
|
170853
|
+
// ─── sort: indicator + ARIA ──────────────────────────────────────────
|
|
170310
170854
|
getAriaSort(col) {
|
|
170311
|
-
|
|
170312
|
-
|
|
170855
|
+
const primary = this.sortBy[0];
|
|
170856
|
+
if (!primary || primary.key !== String(col.key)) return "none";
|
|
170857
|
+
return primary.dir === "asc" ? "ascending" : "descending";
|
|
170313
170858
|
}
|
|
170314
170859
|
renderSortIndicator(col) {
|
|
170315
|
-
|
|
170316
|
-
|
|
170860
|
+
const idx = this.getSortPriority(String(col.key));
|
|
170861
|
+
if (idx < 0) return b2``;
|
|
170862
|
+
const desc = this.sortBy[idx];
|
|
170863
|
+
const arrow2 = desc.dir === "asc" ? "\u25B2" : "\u25BC";
|
|
170864
|
+
if (this.sortBy.length === 1) {
|
|
170865
|
+
return b2`<span class="sortArrow">${arrow2}</span>`;
|
|
170866
|
+
}
|
|
170867
|
+
return b2`<span class="sortArrow">${arrow2}</span><span class="sortBadge">${idx + 1}</span>`;
|
|
170317
170868
|
}
|
|
170318
170869
|
// filtering helpers
|
|
170319
170870
|
setFilterText(value2) {
|
|
@@ -170478,12 +171029,11 @@ _editableFields = new WeakMap();
|
|
|
170478
171029
|
_showVerticalLines = new WeakMap();
|
|
170479
171030
|
_showHorizontalLines = new WeakMap();
|
|
170480
171031
|
_showGrid = new WeakMap();
|
|
170481
|
-
|
|
170482
|
-
_sortDir = new WeakMap();
|
|
171032
|
+
_sortBy = new WeakMap();
|
|
170483
171033
|
_filterText = new WeakMap();
|
|
170484
171034
|
_columnFilters = new WeakMap();
|
|
170485
171035
|
_showColumnFilters = new WeakMap();
|
|
170486
|
-
|
|
171036
|
+
_fixedHeight = new WeakMap();
|
|
170487
171037
|
_searchMode = new WeakMap();
|
|
170488
171038
|
_selectionMode = new WeakMap();
|
|
170489
171039
|
_selectedIds = new WeakMap();
|
|
@@ -170507,12 +171057,11 @@ __decorateElement(_init39, 4, "editableFields", _editableFields_dec, _DeesTable,
|
|
|
170507
171057
|
__decorateElement(_init39, 4, "showVerticalLines", _showVerticalLines_dec, _DeesTable, _showVerticalLines);
|
|
170508
171058
|
__decorateElement(_init39, 4, "showHorizontalLines", _showHorizontalLines_dec, _DeesTable, _showHorizontalLines);
|
|
170509
171059
|
__decorateElement(_init39, 4, "showGrid", _showGrid_dec, _DeesTable, _showGrid);
|
|
170510
|
-
__decorateElement(_init39, 4, "
|
|
170511
|
-
__decorateElement(_init39, 4, "sortDir", _sortDir_dec, _DeesTable, _sortDir);
|
|
171060
|
+
__decorateElement(_init39, 4, "sortBy", _sortBy_dec, _DeesTable, _sortBy);
|
|
170512
171061
|
__decorateElement(_init39, 4, "filterText", _filterText_dec, _DeesTable, _filterText);
|
|
170513
171062
|
__decorateElement(_init39, 4, "columnFilters", _columnFilters_dec, _DeesTable, _columnFilters);
|
|
170514
171063
|
__decorateElement(_init39, 4, "showColumnFilters", _showColumnFilters_dec, _DeesTable, _showColumnFilters);
|
|
170515
|
-
__decorateElement(_init39, 4, "
|
|
171064
|
+
__decorateElement(_init39, 4, "fixedHeight", _fixedHeight_dec, _DeesTable, _fixedHeight);
|
|
170516
171065
|
__decorateElement(_init39, 4, "searchMode", _searchMode_dec, _DeesTable, _searchMode);
|
|
170517
171066
|
__decorateElement(_init39, 4, "selectionMode", _selectionMode_dec, _DeesTable, _selectionMode);
|
|
170518
171067
|
__decorateElement(_init39, 4, "selectedIds", _selectedIds_dec, _DeesTable, _selectedIds);
|