@design.estate/dees-catalog 3.61.1 → 3.62.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.
@@ -108515,6 +108515,7 @@ var init_dees_icon = __esm({
108515
108515
  justify-content: center;
108516
108516
  line-height: 1;
108517
108517
  vertical-align: middle;
108518
+ pointer-events: none;
108518
108519
  }
108519
108520
 
108520
108521
  /* Improve rendering performance */
@@ -156698,12 +156699,14 @@ var _DeesInputList = class _DeesInputList extends (_a36 = DeesInputBase, _value_
156698
156699
  this.currentCandidateIndex = -1;
156699
156700
  this.matchingCandidates = [];
156700
156701
  this.validationText = "";
156701
- const input = this.shadowRoot?.querySelector(".add-input");
156702
- if (input) {
156703
- input.value = "";
156704
- input.focus();
156705
- }
156706
156702
  this.emitChange();
156703
+ this.updateComplete.then(() => {
156704
+ const input = this.shadowRoot?.querySelector(".add-input");
156705
+ if (input) {
156706
+ input.value = "";
156707
+ input.focus();
156708
+ }
156709
+ });
156707
156710
  }
156708
156711
  /**
156709
156712
  * Get the full candidate object for an item by its viewKey.
@@ -156734,12 +156737,14 @@ var _DeesInputList = class _DeesInputList extends (_a36 = DeesInputBase, _value_
156734
156737
  this.value = [...this.value, trimmedValue];
156735
156738
  this.inputValue = "";
156736
156739
  this.validationText = "";
156737
- const input = this.shadowRoot?.querySelector(".add-input");
156738
- if (input) {
156739
- input.value = "";
156740
- input.focus();
156741
- }
156742
156740
  this.emitChange();
156741
+ this.updateComplete.then(() => {
156742
+ const input = this.shadowRoot?.querySelector(".add-input");
156743
+ if (input) {
156744
+ input.value = "";
156745
+ input.focus();
156746
+ }
156747
+ });
156743
156748
  }
156744
156749
  startEdit(index3) {
156745
156750
  this.editingIndex = index3;
@@ -168986,6 +168991,44 @@ var demoFunc29 = /* @__PURE__ */ __name(() => b2`
168986
168991
  ></dees-table>
168987
168992
  </div>
168988
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
+
168989
169032
  <div class="demo-section">
168990
169033
  <h2 class="demo-title">Wide Properties + Many Actions</h2>
168991
169034
  <p class="demo-description">A table with many columns and rich actions to stress test layout and sticky Actions.</p>
@@ -169379,6 +169422,32 @@ var tableStyles = [
169379
169422
  color: ${cssManager.bdTheme("hsl(215.4 16.3% 46.9%)", "hsl(215 20.2% 65.1%)")};
169380
169423
  letter-spacing: -0.01em;
169381
169424
  }
169425
+
169426
+ th[role='columnheader']:hover {
169427
+ color: var(--dees-color-text-primary);
169428
+ }
169429
+
169430
+ th .sortArrow {
169431
+ display: inline-block;
169432
+ margin-left: 6px;
169433
+ font-size: 10px;
169434
+ line-height: 1;
169435
+ opacity: 0.7;
169436
+ vertical-align: middle;
169437
+ }
169438
+
169439
+ th .sortBadge {
169440
+ display: inline-block;
169441
+ margin-left: 3px;
169442
+ padding: 1px 5px;
169443
+ font-size: 10px;
169444
+ font-weight: 600;
169445
+ line-height: 1;
169446
+ color: ${cssManager.bdTheme("hsl(222.2 47.4% 30%)", "hsl(217.2 91.2% 75%)")};
169447
+ background: ${cssManager.bdTheme("hsl(222.2 47.4% 51.2% / 0.12)", "hsl(217.2 91.2% 59.8% / 0.18)")};
169448
+ border-radius: 999px;
169449
+ vertical-align: middle;
169450
+ }
169382
169451
 
169383
169452
  :host([show-vertical-lines]) th {
169384
169453
  border-right: 1px solid var(--dees-color-border-default);
@@ -169570,7 +169639,23 @@ function getCellValue(row, col, displayFunction) {
169570
169639
  return col.value ? col.value(row) : row[col.key];
169571
169640
  }
169572
169641
  __name(getCellValue, "getCellValue");
169573
- function getViewData(data, effectiveColumns, sortKey, sortDir, filterText, columnFilters, filterMode = "table", lucenePredicate) {
169642
+ function compareCellValues(va, vb) {
169643
+ if (va == null && vb == null) return 0;
169644
+ if (va == null) return -1;
169645
+ if (vb == null) return 1;
169646
+ if (typeof va === "number" && typeof vb === "number") {
169647
+ if (va < vb) return -1;
169648
+ if (va > vb) return 1;
169649
+ return 0;
169650
+ }
169651
+ const sa = String(va).toLowerCase();
169652
+ const sb = String(vb).toLowerCase();
169653
+ if (sa < sb) return -1;
169654
+ if (sa > sb) return 1;
169655
+ return 0;
169656
+ }
169657
+ __name(compareCellValues, "compareCellValues");
169658
+ function getViewData(data, effectiveColumns, sortBy, filterText, columnFilters, filterMode = "table", lucenePredicate) {
169574
169659
  let arr = data.slice();
169575
169660
  const ft = (filterText || "").trim().toLowerCase();
169576
169661
  const cf = columnFilters || {};
@@ -169584,9 +169669,9 @@ function getViewData(data, effectiveColumns, sortKey, sortDir, filterText, colum
169584
169669
  const needle = String(cf[k4]).toLowerCase();
169585
169670
  if (!s10.includes(needle)) return false;
169586
169671
  } else {
169587
- const col2 = effectiveColumns.find((c11) => String(c11.key) === k4);
169588
- if (!col2 || col2.hidden || col2.filterable === false) continue;
169589
- const val = getCellValue(row, col2);
169672
+ const col = effectiveColumns.find((c11) => String(c11.key) === k4);
169673
+ if (!col || col.hidden || col.filterable === false) continue;
169674
+ const val = getCellValue(row, col);
169590
169675
  const s10 = String(val ?? "").toLowerCase();
169591
169676
  const needle = String(cf[k4]).toLowerCase();
169592
169677
  if (!s10.includes(needle)) return false;
@@ -169607,9 +169692,9 @@ function getViewData(data, effectiveColumns, sortKey, sortDir, filterText, colum
169607
169692
  }
169608
169693
  }
169609
169694
  } else {
169610
- for (const col2 of effectiveColumns) {
169611
- if (col2.hidden) continue;
169612
- const val = getCellValue(row, col2);
169695
+ for (const col of effectiveColumns) {
169696
+ if (col.hidden) continue;
169697
+ const val = getCellValue(row, col);
169613
169698
  const s10 = String(val ?? "").toLowerCase();
169614
169699
  if (s10.includes(ft)) {
169615
169700
  any = true;
@@ -169622,21 +169707,14 @@ function getViewData(data, effectiveColumns, sortKey, sortDir, filterText, colum
169622
169707
  return true;
169623
169708
  });
169624
169709
  }
169625
- if (!sortKey || !sortDir) return arr;
169626
- const col = effectiveColumns.find((c11) => String(c11.key) === sortKey);
169627
- if (!col) return arr;
169628
- const dir = sortDir === "asc" ? 1 : -1;
169710
+ if (!sortBy || sortBy.length === 0) return arr;
169711
+ const resolved2 = sortBy.map((desc) => ({ desc, col: effectiveColumns.find((c11) => String(c11.key) === desc.key) })).filter((entry) => !!entry.col);
169712
+ if (resolved2.length === 0) return arr;
169629
169713
  arr.sort((a5, b5) => {
169630
- const va = getCellValue(a5, col);
169631
- const vb = getCellValue(b5, col);
169632
- if (va == null && vb == null) return 0;
169633
- if (va == null) return -1 * dir;
169634
- if (vb == null) return 1 * dir;
169635
- if (typeof va === "number" && typeof vb === "number") return (va - vb) * dir;
169636
- const sa = String(va).toLowerCase();
169637
- const sb = String(vb).toLowerCase();
169638
- if (sa < sb) return -1 * dir;
169639
- if (sa > sb) return 1 * dir;
169714
+ for (const { desc, col } of resolved2) {
169715
+ const cmp2 = compareCellValues(getCellValue(a5, col), getCellValue(b5, col));
169716
+ if (cmp2 !== 0) return desc.dir === "asc" ? cmp2 : -cmp2;
169717
+ }
169640
169718
  return 0;
169641
169719
  });
169642
169720
  return arr;
@@ -169789,7 +169867,13 @@ __name(compileLucenePredicate, "compileLucenePredicate");
169789
169867
  init_dist_ts30();
169790
169868
  init_dist_ts29();
169791
169869
  init_theme();
169792
- var _selectedIds_dec, _selectionMode_dec, _searchMode_dec, _stickyHeader_dec, _showColumnFilters_dec, _columnFilters_dec, _filterText_dec, _sortDir_dec, _sortKey_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, _sortKey, _sortDir, _filterText, _columnFilters, _showColumnFilters, _stickyHeader, _searchMode, _selectionMode, _selectedIds;
169870
+ var _selectedIds_dec, _selectionMode_dec, _searchMode_dec, _stickyHeader_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, _stickyHeader, _searchMode, _selectionMode, _selectedIds;
169871
+ function ordinalLabel(n12) {
169872
+ const s10 = ["th", "st", "nd", "rd"];
169873
+ const v5 = n12 % 100;
169874
+ return n12 + (s10[(v5 - 20) % 10] || s10[v5] || s10[0]);
169875
+ }
169876
+ __name(ordinalLabel, "ordinalLabel");
169793
169877
  _DeesTable_decorators = [customElement("dees-table")];
169794
169878
  var _DeesTable = class _DeesTable extends (_a42 = DeesElement, _heading1_dec = [n5({
169795
169879
  type: String
@@ -169832,7 +169916,7 @@ var _DeesTable = class _DeesTable extends (_a42 = DeesElement, _heading1_dec = [
169832
169916
  type: Boolean,
169833
169917
  reflect: true,
169834
169918
  attribute: "show-grid"
169835
- })], _sortKey_dec = [n5({ attribute: false })], _sortDir_dec = [n5({ attribute: false })], _filterText_dec = [n5({ type: String })], _columnFilters_dec = [n5({ attribute: false })], _showColumnFilters_dec = [n5({ type: Boolean, attribute: "show-column-filters" })], _stickyHeader_dec = [n5({ type: Boolean, reflect: true, attribute: "sticky-header" })], _searchMode_dec = [n5({ type: String })], _selectionMode_dec = [n5({ type: String })], _selectedIds_dec = [n5({ attribute: false })], _a42) {
169919
+ })], _sortBy_dec = [n5({ attribute: false })], _filterText_dec = [n5({ type: String })], _columnFilters_dec = [n5({ attribute: false })], _showColumnFilters_dec = [n5({ type: Boolean, attribute: "show-column-filters" })], _stickyHeader_dec = [n5({ type: Boolean, reflect: true, attribute: "sticky-header" })], _searchMode_dec = [n5({ type: String })], _selectionMode_dec = [n5({ type: String })], _selectedIds_dec = [n5({ attribute: false })], _a42) {
169836
169920
  constructor() {
169837
169921
  super();
169838
169922
  __privateAdd(this, _heading1, __runInitializers(_init39, 8, this, "heading 1")), __runInitializers(_init39, 11, this);
@@ -169859,17 +169943,16 @@ var _DeesTable = class _DeesTable extends (_a42 = DeesElement, _heading1_dec = [
169859
169943
  __publicField(this, "files", []);
169860
169944
  __publicField(this, "fileWeakMap", /* @__PURE__ */ new WeakMap());
169861
169945
  __publicField(this, "dataChangeSubject", new domtools_pluginexports_exports.smartrx.rxjs.Subject());
169862
- __privateAdd(this, _sortKey, __runInitializers(_init39, 88, this)), __runInitializers(_init39, 91, this);
169863
- __privateAdd(this, _sortDir, __runInitializers(_init39, 92, this, null)), __runInitializers(_init39, 95, this);
169864
- __privateAdd(this, _filterText, __runInitializers(_init39, 96, this, "")), __runInitializers(_init39, 99, this);
169865
- __privateAdd(this, _columnFilters, __runInitializers(_init39, 100, this, {})), __runInitializers(_init39, 103, this);
169866
- __privateAdd(this, _showColumnFilters, __runInitializers(_init39, 104, this, false)), __runInitializers(_init39, 107, this);
169867
- __privateAdd(this, _stickyHeader, __runInitializers(_init39, 108, this, false)), __runInitializers(_init39, 111, this);
169868
- __privateAdd(this, _searchMode, __runInitializers(_init39, 112, this, "table")), __runInitializers(_init39, 115, this);
169946
+ __privateAdd(this, _sortBy, __runInitializers(_init39, 88, this, [])), __runInitializers(_init39, 91, this);
169947
+ __privateAdd(this, _filterText, __runInitializers(_init39, 92, this, "")), __runInitializers(_init39, 95, this);
169948
+ __privateAdd(this, _columnFilters, __runInitializers(_init39, 96, this, {})), __runInitializers(_init39, 99, this);
169949
+ __privateAdd(this, _showColumnFilters, __runInitializers(_init39, 100, this, false)), __runInitializers(_init39, 103, this);
169950
+ __privateAdd(this, _stickyHeader, __runInitializers(_init39, 104, this, false)), __runInitializers(_init39, 107, this);
169951
+ __privateAdd(this, _searchMode, __runInitializers(_init39, 108, this, "table")), __runInitializers(_init39, 111, this);
169869
169952
  __publicField(this, "__searchTextSub");
169870
169953
  __publicField(this, "__searchModeSub");
169871
- __privateAdd(this, _selectionMode, __runInitializers(_init39, 116, this, "none")), __runInitializers(_init39, 119, this);
169872
- __privateAdd(this, _selectedIds, __runInitializers(_init39, 120, this, /* @__PURE__ */ new Set())), __runInitializers(_init39, 123, this);
169954
+ __privateAdd(this, _selectionMode, __runInitializers(_init39, 112, this, "none")), __runInitializers(_init39, 115, this);
169955
+ __privateAdd(this, _selectedIds, __runInitializers(_init39, 116, this, /* @__PURE__ */ new Set())), __runInitializers(_init39, 119, this);
169873
169956
  __publicField(this, "_rowIdMap", /* @__PURE__ */ new WeakMap());
169874
169957
  __publicField(this, "_rowIdCounter", 0);
169875
169958
  __publicField(this, "__debounceTimer");
@@ -169890,8 +169973,7 @@ var _DeesTable = class _DeesTable extends (_a42 = DeesElement, _heading1_dec = [
169890
169973
  const viewData = getViewData(
169891
169974
  this.data,
169892
169975
  effectiveColumns,
169893
- this.sortKey,
169894
- this.sortDir,
169976
+ this.sortBy,
169895
169977
  this.filterText,
169896
169978
  this.columnFilters,
169897
169979
  this.searchMode === "data" ? "data" : "table",
@@ -169986,7 +170068,8 @@ var _DeesTable = class _DeesTable extends (_a42 = DeesElement, _heading1_dec = [
169986
170068
  role="columnheader"
169987
170069
  aria-sort=${ariaSort}
169988
170070
  style="${isSortable ? "cursor: pointer;" : ""}"
169989
- @click=${() => isSortable ? this.toggleSort(col) : null}
170071
+ @click=${(eventArg) => isSortable ? this.handleHeaderClick(eventArg, col, effectiveColumns) : null}
170072
+ @contextmenu=${(eventArg) => isSortable ? this.openHeaderContextMenu(eventArg, col, effectiveColumns) : null}
169990
170073
  >
169991
170074
  ${col.header ?? col.key}
169992
170075
  ${this.renderSortIndicator(col)}
@@ -170282,33 +170365,302 @@ var _DeesTable = class _DeesTable extends (_a42 = DeesElement, _heading1_dec = [
170282
170365
  table2.style.tableLayout = "fixed";
170283
170366
  }
170284
170367
  // compute helpers moved to ./data.ts
170285
- toggleSort(col) {
170286
- const key2 = String(col.key);
170287
- if (this.sortKey !== key2) {
170288
- this.sortKey = key2;
170289
- this.sortDir = "asc";
170290
- } else {
170291
- if (this.sortDir === "asc") this.sortDir = "desc";
170292
- else if (this.sortDir === "desc") {
170293
- this.sortDir = null;
170294
- this.sortKey = void 0;
170295
- } else this.sortDir = "asc";
170296
- }
170368
+ // ─── sort: public API ────────────────────────────────────────────────
170369
+ /** Returns the descriptor for `key` if the column is currently in the cascade. */
170370
+ getSortDescriptor(key2) {
170371
+ return this.sortBy.find((d6) => d6.key === key2);
170372
+ }
170373
+ /** Returns the 0-based priority of `key` in the cascade, or -1 if not present. */
170374
+ getSortPriority(key2) {
170375
+ return this.sortBy.findIndex((d6) => d6.key === key2);
170376
+ }
170377
+ /** Replaces the cascade with a single sort entry. */
170378
+ setSort(key2, dir) {
170379
+ this.sortBy = [{ key: key2, dir }];
170380
+ this.emitSortChange();
170381
+ this.requestUpdate();
170382
+ }
170383
+ /**
170384
+ * Inserts (or moves) `key` to a 0-based position in the cascade. If the key is
170385
+ * already present elsewhere, its previous entry is removed before insertion so
170386
+ * a column appears at most once.
170387
+ */
170388
+ addSortAt(key2, position3, dir) {
170389
+ const next2 = this.sortBy.filter((d6) => d6.key !== key2);
170390
+ const clamped = Math.max(0, Math.min(position3, next2.length));
170391
+ next2.splice(clamped, 0, { key: key2, dir });
170392
+ this.sortBy = next2;
170393
+ this.emitSortChange();
170394
+ this.requestUpdate();
170395
+ }
170396
+ /** Appends `key` to the end of the cascade (or moves it there if already present). */
170397
+ appendSort(key2, dir) {
170398
+ const next2 = this.sortBy.filter((d6) => d6.key !== key2);
170399
+ next2.push({ key: key2, dir });
170400
+ this.sortBy = next2;
170401
+ this.emitSortChange();
170402
+ this.requestUpdate();
170403
+ }
170404
+ /** Removes `key` from the cascade. No-op if not present. */
170405
+ removeSort(key2) {
170406
+ if (!this.sortBy.some((d6) => d6.key === key2)) return;
170407
+ this.sortBy = this.sortBy.filter((d6) => d6.key !== key2);
170408
+ this.emitSortChange();
170409
+ this.requestUpdate();
170410
+ }
170411
+ /** Empties the cascade. */
170412
+ clearSorts() {
170413
+ if (this.sortBy.length === 0) return;
170414
+ this.sortBy = [];
170415
+ this.emitSortChange();
170416
+ this.requestUpdate();
170417
+ }
170418
+ emitSortChange() {
170297
170419
  this.dispatchEvent(
170298
170420
  new CustomEvent("sortChange", {
170299
- detail: { key: this.sortKey, dir: this.sortDir },
170421
+ detail: { sortBy: this.sortBy.map((d6) => ({ ...d6 })) },
170300
170422
  bubbles: true
170301
170423
  })
170302
170424
  );
170303
- this.requestUpdate();
170304
170425
  }
170426
+ // ─── sort: header interaction handlers ───────────────────────────────
170427
+ /**
170428
+ * Plain left-click on a sortable header. Cycles `none → asc → desc → none`
170429
+ * collapsing the cascade to a single column. If a multi-column cascade is
170430
+ * active, asks the user to confirm the destructive replacement first. A
170431
+ * Shift+click bypasses the modal and routes through the multi-sort cycle.
170432
+ */
170433
+ async handleHeaderClick(eventArg, col, _effectiveColumns) {
170434
+ if (eventArg.shiftKey) {
170435
+ this.handleHeaderShiftClick(col);
170436
+ return;
170437
+ }
170438
+ const proceed = await this.confirmReplaceCascade(col);
170439
+ if (!proceed) return;
170440
+ this.cycleSingleSort(col);
170441
+ }
170442
+ /**
170443
+ * Cycles a single column through `none → asc → desc → none`, collapsing the
170444
+ * cascade. Used by both plain click and the menu's "Sort Ascending/Descending"
170445
+ * shortcuts (after confirmation).
170446
+ */
170447
+ cycleSingleSort(col) {
170448
+ const key2 = String(col.key);
170449
+ const current = this.sortBy.length === 1 && this.sortBy[0].key === key2 ? this.sortBy[0].dir : null;
170450
+ if (current === "asc") this.setSort(key2, "desc");
170451
+ else if (current === "desc") this.clearSorts();
170452
+ else this.setSort(key2, "asc");
170453
+ }
170454
+ /**
170455
+ * Shift+click cycle on a sortable header. Edits the cascade in place without
170456
+ * destroying other sort keys: append → flip dir → remove.
170457
+ */
170458
+ handleHeaderShiftClick(col) {
170459
+ const key2 = String(col.key);
170460
+ const existing = this.getSortDescriptor(key2);
170461
+ if (!existing) {
170462
+ this.appendSort(key2, "asc");
170463
+ } else if (existing.dir === "asc") {
170464
+ this.sortBy = this.sortBy.map((d6) => d6.key === key2 ? { key: key2, dir: "desc" } : d6);
170465
+ this.emitSortChange();
170466
+ this.requestUpdate();
170467
+ } else {
170468
+ this.removeSort(key2);
170469
+ }
170470
+ }
170471
+ /**
170472
+ * Opens a confirmation modal when the cascade has more than one entry and the
170473
+ * user attempts a destructive single-sort replacement. Resolves to `true` if
170474
+ * the user accepts, `false` if they cancel. If the cascade has 0 or 1 entries
170475
+ * the modal is skipped and we resolve to `true` immediately.
170476
+ */
170477
+ confirmReplaceCascade(targetCol) {
170478
+ if (this.sortBy.length <= 1) return Promise.resolve(true);
170479
+ return new Promise((resolve2) => {
170480
+ let settled = false;
170481
+ const settle = /* @__PURE__ */ __name((result) => {
170482
+ if (settled) return;
170483
+ settled = true;
170484
+ resolve2(result);
170485
+ }, "settle");
170486
+ const summary = this.sortBy.map((d6, i11) => {
170487
+ const c11 = this._lookupColumnByKey?.(d6.key);
170488
+ const label = c11?.header ?? d6.key;
170489
+ return b2`<li>${i11 + 1}. ${label} ${d6.dir === "asc" ? "\u25B2" : "\u25BC"}</li>`;
170490
+ });
170491
+ DeesModal.createAndShow({
170492
+ heading: "Replace multi-column sort?",
170493
+ width: "small",
170494
+ showCloseButton: true,
170495
+ content: b2`
170496
+ <div style="font-size:13px; line-height:1.55;">
170497
+ <p style="margin:0 0 8px;">
170498
+ You currently have a ${this.sortBy.length}-column sort active:
170499
+ </p>
170500
+ <ul style="margin:0 0 12px; padding-left:18px;">${summary}</ul>
170501
+ <p style="margin:0;">
170502
+ Continuing will discard the cascade and replace it with a single sort on
170503
+ <strong>${targetCol.header ?? String(targetCol.key)}</strong>.
170504
+ </p>
170505
+ </div>
170506
+ `,
170507
+ menuOptions: [
170508
+ {
170509
+ name: "Cancel",
170510
+ iconName: "lucide:x",
170511
+ action: /* @__PURE__ */ __name(async (modal) => {
170512
+ settle(false);
170513
+ await modal.destroy();
170514
+ return null;
170515
+ }, "action")
170516
+ },
170517
+ {
170518
+ name: "Replace",
170519
+ iconName: "lucide:check",
170520
+ action: /* @__PURE__ */ __name(async (modal) => {
170521
+ settle(true);
170522
+ await modal.destroy();
170523
+ return null;
170524
+ }, "action")
170525
+ }
170526
+ ]
170527
+ });
170528
+ });
170529
+ }
170530
+ /**
170531
+ * Looks up a column by its string key in the currently effective column set.
170532
+ * Used by the modal helper to render human-friendly labels.
170533
+ */
170534
+ _lookupColumnByKey(key2) {
170535
+ const usingColumns = Array.isArray(this.columns) && this.columns.length > 0;
170536
+ const effective = usingColumns ? computeEffectiveColumns(this.columns, this.augmentFromDisplayFunction, this.displayFunction, this.data) : computeColumnsFromDisplayFunction(this.displayFunction, this.data);
170537
+ return effective.find((c11) => String(c11.key) === key2);
170538
+ }
170539
+ /**
170540
+ * Opens the header context menu for explicit multi-sort priority control.
170541
+ */
170542
+ openHeaderContextMenu(eventArg, col, effectiveColumns) {
170543
+ const items = this.buildHeaderMenuItems(col, effectiveColumns);
170544
+ DeesContextmenu.openContextMenuWithOptions(eventArg, items);
170545
+ }
170546
+ /**
170547
+ * Builds the dynamic context-menu structure for a single column header.
170548
+ */
170549
+ buildHeaderMenuItems(col, effectiveColumns) {
170550
+ const key2 = String(col.key);
170551
+ const existing = this.getSortDescriptor(key2);
170552
+ const cascadeLen = this.sortBy.length;
170553
+ const sortableColumnCount = effectiveColumns.filter((c11) => !!c11.sortable).length;
170554
+ const maxSlot = Math.min(
170555
+ Math.max(cascadeLen + (existing ? 0 : 1), 1),
170556
+ Math.max(sortableColumnCount, 1)
170557
+ );
170558
+ const items = [];
170559
+ items.push({
170560
+ name: "Sort Ascending",
170561
+ iconName: cascadeLen === 1 && existing?.dir === "asc" ? "lucide:check" : "lucide:arrowUp",
170562
+ action: /* @__PURE__ */ __name(async () => {
170563
+ if (await this.confirmReplaceCascade(col)) this.setSort(key2, "asc");
170564
+ return null;
170565
+ }, "action")
170566
+ });
170567
+ items.push({
170568
+ name: "Sort Descending",
170569
+ iconName: cascadeLen === 1 && existing?.dir === "desc" ? "lucide:check" : "lucide:arrowDown",
170570
+ action: /* @__PURE__ */ __name(async () => {
170571
+ if (await this.confirmReplaceCascade(col)) this.setSort(key2, "desc");
170572
+ return null;
170573
+ }, "action")
170574
+ });
170575
+ items.push({ divider: true });
170576
+ for (let slot = 1; slot <= maxSlot; slot++) {
170577
+ const ordinal = ordinalLabel(slot);
170578
+ const isCurrentSlot = existing && this.getSortPriority(key2) === slot - 1;
170579
+ items.push({
170580
+ name: `Set as ${ordinal} sort`,
170581
+ iconName: isCurrentSlot ? "lucide:check" : "lucide:listOrdered",
170582
+ submenu: [
170583
+ {
170584
+ name: "Ascending",
170585
+ iconName: "lucide:arrowUp",
170586
+ action: /* @__PURE__ */ __name(async () => {
170587
+ this.addSortAt(key2, slot - 1, "asc");
170588
+ return null;
170589
+ }, "action")
170590
+ },
170591
+ {
170592
+ name: "Descending",
170593
+ iconName: "lucide:arrowDown",
170594
+ action: /* @__PURE__ */ __name(async () => {
170595
+ this.addSortAt(key2, slot - 1, "desc");
170596
+ return null;
170597
+ }, "action")
170598
+ }
170599
+ ]
170600
+ });
170601
+ }
170602
+ items.push({ divider: true });
170603
+ items.push({
170604
+ name: "Append to sort",
170605
+ iconName: "lucide:plus",
170606
+ submenu: [
170607
+ {
170608
+ name: "Ascending",
170609
+ iconName: "lucide:arrowUp",
170610
+ action: /* @__PURE__ */ __name(async () => {
170611
+ this.appendSort(key2, "asc");
170612
+ return null;
170613
+ }, "action")
170614
+ },
170615
+ {
170616
+ name: "Descending",
170617
+ iconName: "lucide:arrowDown",
170618
+ action: /* @__PURE__ */ __name(async () => {
170619
+ this.appendSort(key2, "desc");
170620
+ return null;
170621
+ }, "action")
170622
+ }
170623
+ ]
170624
+ });
170625
+ if (existing) {
170626
+ items.push({ divider: true });
170627
+ items.push({
170628
+ name: "Remove from sort",
170629
+ iconName: "lucide:minus",
170630
+ action: /* @__PURE__ */ __name(async () => {
170631
+ this.removeSort(key2);
170632
+ return null;
170633
+ }, "action")
170634
+ });
170635
+ }
170636
+ if (cascadeLen > 0) {
170637
+ if (!existing) items.push({ divider: true });
170638
+ items.push({
170639
+ name: "Clear all sorts",
170640
+ iconName: "lucide:trash",
170641
+ action: /* @__PURE__ */ __name(async () => {
170642
+ this.clearSorts();
170643
+ return null;
170644
+ }, "action")
170645
+ });
170646
+ }
170647
+ return items;
170648
+ }
170649
+ // ─── sort: indicator + ARIA ──────────────────────────────────────────
170305
170650
  getAriaSort(col) {
170306
- if (String(col.key) !== this.sortKey || !this.sortDir) return "none";
170307
- return this.sortDir === "asc" ? "ascending" : "descending";
170651
+ const primary = this.sortBy[0];
170652
+ if (!primary || primary.key !== String(col.key)) return "none";
170653
+ return primary.dir === "asc" ? "ascending" : "descending";
170308
170654
  }
170309
170655
  renderSortIndicator(col) {
170310
- if (String(col.key) !== this.sortKey || !this.sortDir) return b2``;
170311
- return b2`<span style="margin-left:6px; opacity:0.7;">${this.sortDir === "asc" ? "\u25B2" : "\u25BC"}</span>`;
170656
+ const idx = this.getSortPriority(String(col.key));
170657
+ if (idx < 0) return b2``;
170658
+ const desc = this.sortBy[idx];
170659
+ const arrow2 = desc.dir === "asc" ? "\u25B2" : "\u25BC";
170660
+ if (this.sortBy.length === 1) {
170661
+ return b2`<span class="sortArrow">${arrow2}</span>`;
170662
+ }
170663
+ return b2`<span class="sortArrow">${arrow2}</span><span class="sortBadge">${idx + 1}</span>`;
170312
170664
  }
170313
170665
  // filtering helpers
170314
170666
  setFilterText(value2) {
@@ -170473,8 +170825,7 @@ _editableFields = new WeakMap();
170473
170825
  _showVerticalLines = new WeakMap();
170474
170826
  _showHorizontalLines = new WeakMap();
170475
170827
  _showGrid = new WeakMap();
170476
- _sortKey = new WeakMap();
170477
- _sortDir = new WeakMap();
170828
+ _sortBy = new WeakMap();
170478
170829
  _filterText = new WeakMap();
170479
170830
  _columnFilters = new WeakMap();
170480
170831
  _showColumnFilters = new WeakMap();
@@ -170502,8 +170853,7 @@ __decorateElement(_init39, 4, "editableFields", _editableFields_dec, _DeesTable,
170502
170853
  __decorateElement(_init39, 4, "showVerticalLines", _showVerticalLines_dec, _DeesTable, _showVerticalLines);
170503
170854
  __decorateElement(_init39, 4, "showHorizontalLines", _showHorizontalLines_dec, _DeesTable, _showHorizontalLines);
170504
170855
  __decorateElement(_init39, 4, "showGrid", _showGrid_dec, _DeesTable, _showGrid);
170505
- __decorateElement(_init39, 4, "sortKey", _sortKey_dec, _DeesTable, _sortKey);
170506
- __decorateElement(_init39, 4, "sortDir", _sortDir_dec, _DeesTable, _sortDir);
170856
+ __decorateElement(_init39, 4, "sortBy", _sortBy_dec, _DeesTable, _sortBy);
170507
170857
  __decorateElement(_init39, 4, "filterText", _filterText_dec, _DeesTable, _filterText);
170508
170858
  __decorateElement(_init39, 4, "columnFilters", _columnFilters_dec, _DeesTable, _columnFilters);
170509
170859
  __decorateElement(_init39, 4, "showColumnFilters", _showColumnFilters_dec, _DeesTable, _showColumnFilters);