@canvas-components/list-table 0.3.3 → 0.3.4

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/index.cjs CHANGED
@@ -666,6 +666,40 @@ function cloneColumns(columns) {
666
666
  children: column.children ? cloneColumns(column.children) : void 0
667
667
  }));
668
668
  }
669
+ function preserveRuntimeColumnWidths(params) {
670
+ const runtimeByKey = collectColumnsByKey(params.runtimeColumns);
671
+ const initialByKey = collectColumnsByKey(params.initialColumns);
672
+ let changed = false;
673
+ const visit = (columns) => {
674
+ columns.forEach((column) => {
675
+ const key = resolveColumnKey(column);
676
+ const runtimeColumn = runtimeByKey.get(key);
677
+ const initialColumn = initialByKey.get(key);
678
+ if (runtimeColumn && initialColumn && column.width === initialColumn.width && runtimeColumn.width !== initialColumn.width) {
679
+ column.width = runtimeColumn.width;
680
+ changed = true;
681
+ }
682
+ if (column.children?.length) {
683
+ visit(column.children);
684
+ }
685
+ });
686
+ };
687
+ visit(params.nextColumns);
688
+ return changed;
689
+ }
690
+ function collectColumnsByKey(columns) {
691
+ const result = /* @__PURE__ */ new Map();
692
+ const visit = (items) => {
693
+ items.forEach((column) => {
694
+ result.set(resolveColumnKey(column), column);
695
+ if (column.children?.length) {
696
+ visit(column.children);
697
+ }
698
+ });
699
+ };
700
+ visit(columns);
701
+ return result;
702
+ }
669
703
  function applyInitialColumnVisibility(columns) {
670
704
  columns.forEach((column) => {
671
705
  if (column.hidden === void 0 && column.initialHide) {
@@ -1784,11 +1818,20 @@ function clampPageNumber(page, totalPages) {
1784
1818
  }
1785
1819
  var maximumTreeDepthCache = /* @__PURE__ */ new WeakMap();
1786
1820
  var sourceRowIndexCache = /* @__PURE__ */ new WeakMap();
1821
+ var selectedRowKeySetCache = /* @__PURE__ */ new WeakMap();
1787
1822
  var headerSelectionStateCache = /* @__PURE__ */ new WeakMap();
1788
1823
  var ROW_SELECTION_COLUMN_KEY = "__row_selection__";
1789
1824
  var ROW_SELECTOR_COLUMN_KEY = "__row_selector__";
1790
1825
  var EXPAND_COLUMN_KEY = "__row_expand__";
1791
1826
  var DEFAULT_ROW_SELECTOR_WIDTH = DEFAULT_SCROLLBAR_THICKNESS;
1827
+ function getSelectedRowKeySet(selectedRowKeys) {
1828
+ let cached = selectedRowKeySetCache.get(selectedRowKeys);
1829
+ if (!cached) {
1830
+ cached = new Set(selectedRowKeys);
1831
+ selectedRowKeySetCache.set(selectedRowKeys, cached);
1832
+ }
1833
+ return cached;
1834
+ }
1792
1835
  function getInitialSelectedRowKeys(options) {
1793
1836
  const rowSelection = options.rowSelection;
1794
1837
  if (!rowSelection) {
@@ -1851,6 +1894,7 @@ function createRowSelectionColumn(params) {
1851
1894
  const { options, selectedRowKeys } = params;
1852
1895
  const rowSelection = options.rowSelection;
1853
1896
  const type = rowSelection?.type === "radio" ? "radio" : "checkbox";
1897
+ const selectedRowKeySet = getSelectedRowKeySet(selectedRowKeys);
1854
1898
  const selectionColumn = {
1855
1899
  key: ROW_SELECTION_COLUMN_KEY,
1856
1900
  dataIndex: ROW_SELECTION_COLUMN_KEY,
@@ -1867,7 +1911,7 @@ function createRowSelectionColumn(params) {
1867
1911
  const rowKey = getRowKey(options, record, rowIndex);
1868
1912
  return {
1869
1913
  type,
1870
- checked: selectedRowKeys.includes(rowKey),
1914
+ checked: selectedRowKeySet.has(rowKey),
1871
1915
  disabled: isRowSelectionDisabled(rowSelection, record)
1872
1916
  };
1873
1917
  },
@@ -1986,40 +2030,39 @@ function getResolvedColumns(options, selectedRowKeys) {
1986
2030
  return rowSelectorColumn ? [rowSelectorColumn, ...resolvedColumns] : resolvedColumns;
1987
2031
  }
1988
2032
  function getSelectedRows(options, selectedRowKeys) {
2033
+ const selectedRowKeySet = getSelectedRowKeySet(selectedRowKeys);
1989
2034
  return options.dataSource.filter(
1990
- (record, index) => selectedRowKeys.includes(getRowKey(options, record, index))
2035
+ (record, index) => selectedRowKeySet.has(getRowKey(options, record, index))
1991
2036
  );
1992
2037
  }
1993
- function getVisibleSelectableRows(params) {
1994
- const { rowSelection, displayData } = params;
1995
- return displayData.filter((record) => !isRowSelectionDisabled(rowSelection, record));
1996
- }
1997
2038
  function getHeaderSelectionState(params) {
1998
- const { options, selectedRowKeys, displayData } = params;
1999
- const cached = headerSelectionStateCache.get(displayData);
2039
+ const { options, selectedRowKeys } = params;
2040
+ const selectableData = options.dataSource;
2041
+ const cached = headerSelectionStateCache.get(selectableData);
2000
2042
  if (cached && cached.options === options && cached.selectedRowKeys === selectedRowKeys) {
2001
2043
  return cached.state;
2002
2044
  }
2003
2045
  const rowSelection = options.rowSelection;
2004
- const visibleRows = getVisibleSelectableRows({
2005
- rowSelection,
2006
- displayData
2007
- });
2008
- const selectedKeySet = new Set(selectedRowKeys);
2009
- let selectedVisibleCount = 0;
2010
- visibleRows.forEach((record, index) => {
2046
+ const selectedKeySet = getSelectedRowKeySet(selectedRowKeys);
2047
+ let selectableCount = 0;
2048
+ let selectedCount = 0;
2049
+ selectableData.forEach((record, index) => {
2050
+ if (isRowSelectionDisabled(rowSelection, record)) {
2051
+ return;
2052
+ }
2053
+ selectableCount += 1;
2011
2054
  if (selectedKeySet.has(getRowKey(options, record, index))) {
2012
- selectedVisibleCount += 1;
2055
+ selectedCount += 1;
2013
2056
  }
2014
2057
  });
2015
2058
  const type = rowSelection?.type === "radio" ? "radio" : "checkbox";
2016
2059
  const state = {
2017
2060
  type,
2018
- checked: visibleRows.length > 0 && selectedVisibleCount === visibleRows.length,
2019
- indeterminate: selectedVisibleCount > 0 && selectedVisibleCount < visibleRows.length,
2020
- disabled: visibleRows.length === 0
2061
+ checked: selectableCount > 0 && selectedCount === selectableCount,
2062
+ indeterminate: selectedCount > 0 && selectedCount < selectableCount,
2063
+ disabled: selectableCount === 0
2021
2064
  };
2022
- headerSelectionStateCache.set(displayData, {
2065
+ headerSelectionStateCache.set(selectableData, {
2023
2066
  options,
2024
2067
  selectedRowKeys,
2025
2068
  state
@@ -2042,24 +2085,31 @@ function resolveToggledRowSelectionKeys(params) {
2042
2085
  };
2043
2086
  }
2044
2087
  function resolveToggleAllVisibleRowKeys(params) {
2045
- const { options, selectedRowKeys, displayData } = params;
2088
+ const { options, selectedRowKeys } = params;
2046
2089
  const rowSelection = options.rowSelection;
2047
2090
  if (!rowSelection || rowSelection.type === "radio") {
2048
2091
  return null;
2049
2092
  }
2050
- const visibleRows = getVisibleSelectableRows({
2051
- rowSelection,
2052
- displayData
2053
- });
2054
- const visibleKeys = visibleRows.map(
2055
- (record, index) => getRowKey(options, record, index)
2056
- );
2057
- const headerState = getHeaderSelectionState({
2058
- options,
2059
- selectedRowKeys,
2060
- displayData
2093
+ const selectedKeySet = getSelectedRowKeySet(selectedRowKeys);
2094
+ const selectableKeys = [];
2095
+ let allSelected = true;
2096
+ options.dataSource.forEach((record, index) => {
2097
+ if (isRowSelectionDisabled(rowSelection, record)) {
2098
+ return;
2099
+ }
2100
+ const key = getRowKey(options, record, index);
2101
+ selectableKeys.push(key);
2102
+ if (!selectedKeySet.has(key)) {
2103
+ allSelected = false;
2104
+ }
2061
2105
  });
2062
- return headerState.checked ? selectedRowKeys.filter((key) => !visibleKeys.includes(key)) : Array.from(/* @__PURE__ */ new Set([...selectedRowKeys, ...visibleKeys]));
2106
+ if (allSelected && selectableKeys.length > 0) {
2107
+ const selectableKeySet = new Set(selectableKeys);
2108
+ return selectedRowKeys.filter((key) => !selectableKeySet.has(key));
2109
+ }
2110
+ const nextKeySet = new Set(selectedRowKeys);
2111
+ selectableKeys.forEach((key) => nextKeySet.add(key));
2112
+ return Array.from(nextKeySet);
2063
2113
  }
2064
2114
 
2065
2115
  // src/engine/store/state.ts
@@ -13592,7 +13642,7 @@ async function getBaseDisplayRowsAsync(params) {
13592
13642
  }
13593
13643
  function getDisplayRows(params) {
13594
13644
  const rows = getBaseDisplayRows(params);
13595
- if (!params.options.pagination || params.options.query?.mode === "remote") {
13645
+ if (!params.options.pagination || isRemotePaginationResult(params.options)) {
13596
13646
  return rows;
13597
13647
  }
13598
13648
  return sliceDisplayRowsByPagination({
@@ -13602,7 +13652,7 @@ function getDisplayRows(params) {
13602
13652
  });
13603
13653
  }
13604
13654
  function sliceDisplayRowsFromBaseRows(params) {
13605
- if (!params.options.pagination || params.options.query?.mode === "remote") {
13655
+ if (!params.options.pagination || isRemotePaginationResult(params.options)) {
13606
13656
  return params.rows;
13607
13657
  }
13608
13658
  return sliceDisplayRowsByPagination({
@@ -13611,6 +13661,13 @@ function sliceDisplayRowsFromBaseRows(params) {
13611
13661
  state: params.query.pagination
13612
13662
  });
13613
13663
  }
13664
+ function isRemotePaginationResult(options) {
13665
+ if (options.query?.mode === "remote") {
13666
+ return true;
13667
+ }
13668
+ const total = options.pagination && options.pagination.total;
13669
+ return typeof total === "number" && Number.isFinite(total) && total > options.dataSource.length;
13670
+ }
13614
13671
  function emitListTableQueryChange(params) {
13615
13672
  const {
13616
13673
  options,
@@ -15138,6 +15195,7 @@ var TEXT_SELECTION_DRAG_THRESHOLD = 5;
15138
15195
  var TEXT_SELECTION_AUTO_SCROLL_EDGE_SIZE = 36;
15139
15196
  var TEXT_SELECTION_AUTO_SCROLL_MAX_VERTICAL_SPEED = 1200;
15140
15197
  var TEXT_SELECTION_AUTO_SCROLL_MAX_HORIZONTAL_SPEED = 900;
15198
+ var EDITABLE_CELL_ROW_SELECTION_DELAY = 300;
15141
15199
  var ListTableEventController = class {
15142
15200
  constructor(host) {
15143
15201
  __publicField(this, "searchKeyword", "");
@@ -15159,6 +15217,7 @@ var ListTableEventController = class {
15159
15217
  __publicField(this, "cellSelectionAutoScrollVelocity", { x: 0, y: 0 });
15160
15218
  __publicField(this, "cellSelectionAutoScrollTargetVelocity", { x: 0, y: 0 });
15161
15219
  __publicField(this, "continuousScrollTimer", null);
15220
+ __publicField(this, "pendingEditableCellRowSelectionTimer", null);
15162
15221
  __publicField(this, "outsideClickDocument", null);
15163
15222
  __publicField(this, "outsideClickStarted", null);
15164
15223
  __publicField(this, "host");
@@ -15560,6 +15619,7 @@ var ListTableEventController = class {
15560
15619
  );
15561
15620
  });
15562
15621
  __publicField(this, "handleDoubleClick", (event) => {
15622
+ this.cancelPendingEditableCellRowSelection();
15563
15623
  if (!this.host.canvasElement) {
15564
15624
  return;
15565
15625
  }
@@ -16089,7 +16149,24 @@ var ListTableEventController = class {
16089
16149
  if ((result.area === "body" || result.area === "body-content") && typeof result.rowIndex === "number" && this.host.options.rowSelection?.selectRowByClick && result.columnKey && !isSystemColumnKey(result.columnKey)) {
16090
16150
  const record = this.host.getDisplayData()[result.rowIndex];
16091
16151
  if (record !== void 0) {
16092
- this.host.toggleRowSelection(record, result.rowIndex);
16152
+ const column = this.host.leafColumns.find(
16153
+ (item) => item.key === result.columnKey
16154
+ );
16155
+ const value = column?.dataIndex != null ? utils.getValueByDataIndex(record, column.dataIndex) : void 0;
16156
+ const canOpenEditorByDoubleClick = shouldOpenCellEditorOnClick(
16157
+ column,
16158
+ 2,
16159
+ {
16160
+ value,
16161
+ record,
16162
+ rowIndex: result.rowIndex
16163
+ }
16164
+ );
16165
+ if (canOpenEditorByDoubleClick && event.detail === 1) {
16166
+ this.scheduleEditableCellRowSelection(record, result.rowIndex);
16167
+ } else if (!canOpenEditorByDoubleClick || event.detail !== 2) {
16168
+ this.host.toggleRowSelection(record, result.rowIndex);
16169
+ }
16093
16170
  }
16094
16171
  }
16095
16172
  if (result.area === "body" && typeof result.rowIndex === "number" && this.host.options.expandable?.expandRowByClick && result.columnKey && !isSystemColumnKey(result.columnKey) && this.host.toggleRowExpand(result.rowIndex)) {
@@ -16563,6 +16640,7 @@ var ListTableEventController = class {
16563
16640
  this.host.render();
16564
16641
  }
16565
16642
  destroy() {
16643
+ this.cancelPendingEditableCellRowSelection();
16566
16644
  this.stopContinuousScroll();
16567
16645
  this.stopTextSelectionAutoScroll();
16568
16646
  this.stopCellSelectionAutoScroll();
@@ -16627,6 +16705,20 @@ var ListTableEventController = class {
16627
16705
  event.preventDefault();
16628
16706
  this.host.editingController.open(rowIndex, columnKey, event.key);
16629
16707
  }
16708
+ scheduleEditableCellRowSelection(record, rowIndex) {
16709
+ this.cancelPendingEditableCellRowSelection();
16710
+ this.pendingEditableCellRowSelectionTimer = globalThis.setTimeout(() => {
16711
+ this.pendingEditableCellRowSelectionTimer = null;
16712
+ this.host.toggleRowSelection(record, rowIndex);
16713
+ }, EDITABLE_CELL_ROW_SELECTION_DELAY);
16714
+ }
16715
+ cancelPendingEditableCellRowSelection() {
16716
+ if (this.pendingEditableCellRowSelectionTimer == null) {
16717
+ return;
16718
+ }
16719
+ globalThis.clearTimeout(this.pendingEditableCellRowSelectionTimer);
16720
+ this.pendingEditableCellRowSelectionTimer = null;
16721
+ }
16630
16722
  async autoFitColumnWidths(columnKey) {
16631
16723
  const ctx = this.host.canvasElement?.getContext("2d");
16632
16724
  if (!ctx) {
@@ -18365,6 +18457,47 @@ function persistListTableColumnConfig(params) {
18365
18457
  )
18366
18458
  );
18367
18459
  }
18460
+ async function resetListTableStoredColumnConfig(params) {
18461
+ const { storageKey, columns } = params;
18462
+ if (!storageKey) {
18463
+ return;
18464
+ }
18465
+ const initialColumnTree = columns.map(cloneColumnTree);
18466
+ ensureColumnKeysInPlace(initialColumnTree);
18467
+ const stored = await getColumnConfig(storageKey);
18468
+ if (!stored) {
18469
+ return;
18470
+ }
18471
+ const initialColumns = buildStoredColumnConfig(
18472
+ initialColumnTree,
18473
+ { key: null, order: null },
18474
+ {}
18475
+ ).columns;
18476
+ const nextColumns = {};
18477
+ Object.entries(initialColumns).forEach(([key, initial]) => {
18478
+ const next = {
18479
+ ...stored.columns[key] ?? initial,
18480
+ width: initial.width,
18481
+ hidden: initial.hidden
18482
+ };
18483
+ if (initial.fixed) {
18484
+ next.fixed = initial.fixed;
18485
+ } else {
18486
+ delete next.fixed;
18487
+ }
18488
+ nextColumns[key] = next;
18489
+ });
18490
+ await saveColumnConfig(storageKey, {
18491
+ ...stored,
18492
+ columns: nextColumns
18493
+ });
18494
+ }
18495
+ function cloneColumnTree(column) {
18496
+ return {
18497
+ ...column,
18498
+ children: column.children?.map(cloneColumnTree)
18499
+ };
18500
+ }
18368
18501
  async function loadListTableStoredConfig(params) {
18369
18502
  const { storageKey, columns } = params;
18370
18503
  if (!storageKey) {
@@ -23963,9 +24096,7 @@ function drawListTableHeader(params) {
23963
24096
  columnKey: ROW_SELECTION_COLUMN_KEY,
23964
24097
  ...getHeaderSelectionState({
23965
24098
  options,
23966
- selectedRowKeys,
23967
- displayData
23968
- })
24099
+ selectedRowKeys})
23969
24100
  } : null,
23970
24101
  inlineContentInset,
23971
24102
  collapsedColumnMarkers,
@@ -27025,6 +27156,19 @@ var ListTableCore = class {
27025
27156
  */
27026
27157
  updateOptions(options) {
27027
27158
  this.animationController.stopCarouselScroll();
27159
+ const host = this.asAssemblyHost();
27160
+ const incomingColumnsAreRuntimeColumns = options.columns === this.options.columns;
27161
+ const nextInitialColumns = incomingColumnsAreRuntimeColumns ? cloneColumns(host.initialColumns) : cloneColumns(options.columns);
27162
+ const nextInitialStretchColumns = incomingColumnsAreRuntimeColumns ? host.initialStretchColumns : options.stretchColumns;
27163
+ const shouldPreserveRuntimeWidths = this.options.stretchColumns === false && options.stretchColumns === host.initialStretchColumns;
27164
+ if (shouldPreserveRuntimeWidths) {
27165
+ preserveRuntimeColumnWidths({
27166
+ nextColumns: options.columns,
27167
+ runtimeColumns: this.options.columns,
27168
+ initialColumns: host.initialColumns
27169
+ });
27170
+ options.stretchColumns = false;
27171
+ }
27028
27172
  applyInitialColumnVisibility(options.columns);
27029
27173
  ensureColumnKeysInPlace(options.columns);
27030
27174
  if (options.expandable?.expandedRowKeys !== void 0 && !areSameRowKeySet(
@@ -27040,10 +27184,9 @@ var ListTableCore = class {
27040
27184
  this.queryController.reset();
27041
27185
  this.summaryController.reset();
27042
27186
  this.options = options;
27043
- const host = this.asAssemblyHost();
27044
27187
  host.syncGroupingFromOptions();
27045
- host.initialColumns = cloneColumns(options.columns);
27046
- host.initialStretchColumns = options.stretchColumns;
27188
+ host.initialColumns = nextInitialColumns;
27189
+ host.initialStretchColumns = nextInitialStretchColumns;
27047
27190
  this.store.dispatch(
27048
27191
  replaceStateAction(
27049
27192
  resolveListTableStateOnOptionsUpdate(options, this.store.getSnapshot())
@@ -27247,5 +27390,6 @@ var ListTable = class {
27247
27390
  };
27248
27391
 
27249
27392
  exports.ListTable = ListTable;
27393
+ exports.resetListTableStoredColumnConfig = resetListTableStoredColumnConfig;
27250
27394
  //# sourceMappingURL=index.cjs.map
27251
27395
  //# sourceMappingURL=index.cjs.map