@alaarab/ogrid-js 2.1.13 → 2.1.14

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/esm/index.js CHANGED
@@ -1012,23 +1012,94 @@ var ROW_NUMBER_COLUMN_WIDTH = 50;
1012
1012
  var DEFAULT_MIN_COLUMN_WIDTH = 80;
1013
1013
  var CELL_PADDING = 16;
1014
1014
  var GRID_BORDER_RADIUS = 6;
1015
- var AUTOSIZE_EXTRA_PX = 28;
1015
+ var AUTOSIZE_EXTRA_PX = 16;
1016
1016
  var AUTOSIZE_MAX_PX = 520;
1017
+ function measureHeaderWidth(th) {
1018
+ const cs = getComputedStyle(th);
1019
+ const thPadding = (parseFloat(cs.paddingLeft) || 0) + (parseFloat(cs.paddingRight) || 0);
1020
+ let resizeHandleWidth = 0;
1021
+ for (let i = 0; i < th.children.length; i++) {
1022
+ const child = th.children[i];
1023
+ const cls = child.className || "";
1024
+ if (cls.includes("resizeHandle") || cls.includes("resize-handle") || cls.includes("ogrid-resize-handle")) {
1025
+ resizeHandleWidth = child.offsetWidth;
1026
+ break;
1027
+ }
1028
+ }
1029
+ const contentContainer = th.firstElementChild;
1030
+ if (!contentContainer) return th.offsetWidth;
1031
+ const modified = [];
1032
+ const expandDescendants = (parent) => {
1033
+ for (let i = 0; i < parent.children.length; i++) {
1034
+ const child = parent.children[i];
1035
+ const style = getComputedStyle(child);
1036
+ if (style.overflow === "hidden" || style.flexShrink !== "0") {
1037
+ modified.push({
1038
+ el: child,
1039
+ overflow: child.style.overflow,
1040
+ flexShrink: child.style.flexShrink,
1041
+ width: child.style.width,
1042
+ minWidth: child.style.minWidth
1043
+ });
1044
+ child.style.overflow = "visible";
1045
+ child.style.flexShrink = "0";
1046
+ child.style.width = "max-content";
1047
+ child.style.minWidth = "max-content";
1048
+ }
1049
+ expandDescendants(child);
1050
+ }
1051
+ };
1052
+ const origPos = contentContainer.style.position;
1053
+ const origWidth = contentContainer.style.width;
1054
+ contentContainer.style.position = "absolute";
1055
+ contentContainer.style.width = "max-content";
1056
+ expandDescendants(contentContainer);
1057
+ const expandedWidth = contentContainer.offsetWidth;
1058
+ contentContainer.style.position = origPos;
1059
+ contentContainer.style.width = origWidth;
1060
+ for (const m of modified) {
1061
+ m.el.style.overflow = m.overflow;
1062
+ m.el.style.flexShrink = m.flexShrink;
1063
+ m.el.style.width = m.width;
1064
+ m.el.style.minWidth = m.minWidth;
1065
+ }
1066
+ return expandedWidth + resizeHandleWidth + thPadding;
1067
+ }
1017
1068
  function measureColumnContentWidth(columnId, minWidth, container) {
1018
1069
  const minW = minWidth ?? DEFAULT_MIN_COLUMN_WIDTH;
1019
1070
  const root = container ?? document;
1020
1071
  const cells = root.querySelectorAll(`[data-column-id="${columnId}"]`);
1021
1072
  if (cells.length === 0) return minW;
1022
1073
  let maxWidth = minW;
1074
+ const contentEls = [];
1075
+ const origPositions = [];
1076
+ const origWidths = [];
1023
1077
  cells.forEach((cell) => {
1024
1078
  const el = cell;
1025
- const label = el.querySelector?.("[data-header-label]");
1026
- if (label) {
1027
- maxWidth = Math.max(maxWidth, label.scrollWidth + AUTOSIZE_EXTRA_PX);
1079
+ const isHeader = !!el.querySelector?.("[data-header-label]");
1080
+ if (isHeader) {
1081
+ maxWidth = Math.max(maxWidth, measureHeaderWidth(el));
1028
1082
  } else {
1029
- maxWidth = Math.max(maxWidth, el.scrollWidth);
1083
+ const content = el.firstElementChild ?? el;
1084
+ contentEls.push(content);
1030
1085
  }
1031
1086
  });
1087
+ if (contentEls.length > 0) {
1088
+ for (let i = 0; i < contentEls.length; i++) {
1089
+ const el = contentEls[i];
1090
+ origPositions.push(el.style.position);
1091
+ origWidths.push(el.style.width);
1092
+ el.style.position = "absolute";
1093
+ el.style.width = "max-content";
1094
+ }
1095
+ for (let i = 0; i < contentEls.length; i++) {
1096
+ maxWidth = Math.max(maxWidth, contentEls[i].offsetWidth + AUTOSIZE_EXTRA_PX);
1097
+ }
1098
+ for (let i = 0; i < contentEls.length; i++) {
1099
+ contentEls[i].style.position = origPositions[i];
1100
+ contentEls[i].style.width = origWidths[i];
1101
+ }
1102
+ }
1032
1103
  return Math.min(AUTOSIZE_MAX_PX, Math.max(minW, Math.ceil(maxWidth)));
1033
1104
  }
1034
1105
  function findCtrlArrowTarget(pos, edge, step, isEmpty) {
@@ -1907,6 +1978,7 @@ var TableRenderer = class {
1907
1978
  // Delegated event handlers bound to thead (avoids per-<th> inline listeners)
1908
1979
  this._theadClickHandler = null;
1909
1980
  this._theadMousedownHandler = null;
1981
+ this._theadDblclickHandler = null;
1910
1982
  // State tracking for incremental DOM patching
1911
1983
  this.lastActiveCell = null;
1912
1984
  this.lastSelectionRange = null;
@@ -2015,15 +2087,30 @@ var TableRenderer = class {
2015
2087
  }
2016
2088
  }
2017
2089
  };
2090
+ this._theadDblclickHandler = (e) => {
2091
+ const target = e.target;
2092
+ if (target.classList.contains("ogrid-resize-handle")) {
2093
+ e.stopPropagation();
2094
+ const th = target.closest("th[data-column-id]");
2095
+ if (!th) return;
2096
+ const columnId = th.getAttribute("data-column-id");
2097
+ if (columnId) {
2098
+ this.interactionState?.onResizeDoubleClick?.(columnId);
2099
+ }
2100
+ }
2101
+ };
2018
2102
  if (this._theadClickHandler) this.thead.addEventListener("click", this._theadClickHandler);
2019
2103
  this.thead.addEventListener("mousedown", this._theadMousedownHandler);
2104
+ this.thead.addEventListener("dblclick", this._theadDblclickHandler);
2020
2105
  }
2021
2106
  detachHeaderDelegation() {
2022
2107
  if (!this.thead) return;
2023
2108
  if (this._theadClickHandler) this.thead.removeEventListener("click", this._theadClickHandler);
2024
2109
  if (this._theadMousedownHandler) this.thead.removeEventListener("mousedown", this._theadMousedownHandler);
2110
+ if (this._theadDblclickHandler) this.thead.removeEventListener("dblclick", this._theadDblclickHandler);
2025
2111
  this._theadClickHandler = null;
2026
2112
  this._theadMousedownHandler = null;
2113
+ this._theadDblclickHandler = null;
2027
2114
  }
2028
2115
  getWrapperElement() {
2029
2116
  return this.wrapperEl;
@@ -4547,6 +4634,11 @@ var ColumnResizeState = class {
4547
4634
  this.isResizing = false;
4548
4635
  this.resizeColumnId = null;
4549
4636
  }
4637
+ /** Set a column width directly (used by double-click auto-fit). */
4638
+ setColumnWidth(columnId, widthPx) {
4639
+ this.columnWidths.set(columnId, widthPx);
4640
+ this.emitter.emit("columnWidthChange", { columnId, widthPx });
4641
+ }
4550
4642
  onColumnWidthChange(handler) {
4551
4643
  this.emitter.on("columnWidthChange", handler);
4552
4644
  return () => this.emitter.off("columnWidthChange", handler);
@@ -5766,6 +5858,13 @@ var OGridRendering = class {
5766
5858
  if (ce.event) this.ctx.handleCellContextMenu(ce.rowIndex, ce.colIndex, ce.event);
5767
5859
  },
5768
5860
  onResizeStart: renderer.getOnResizeStart(),
5861
+ onResizeDoubleClick: (columnId) => {
5862
+ const col = visibleCols.find((c) => c.columnId === columnId);
5863
+ const minW = col?.minWidth ?? DEFAULT_MIN_COLUMN_WIDTH;
5864
+ const container = renderer.getTableElement()?.parentElement ?? void 0;
5865
+ const idealWidth = measureColumnContentWidth(columnId, minW, container);
5866
+ resizeState.setColumnWidth(columnId, idealWidth);
5867
+ },
5769
5868
  // Fill handle
5770
5869
  onFillHandleMouseDown: options.editable !== false ? (e) => fillHandleState?.startFillDrag(e) : void 0,
5771
5870
  // Row selection
@@ -199,6 +199,7 @@
199
199
  position: relative;
200
200
  min-width: fit-content;
201
201
  background: var(--ogrid-bg, #fff);
202
+ overflow-x: clip;
202
203
  }
203
204
 
204
205
  .ogrid-table {
@@ -18,6 +18,7 @@ export interface TableRendererInteractionState {
18
18
  onCellDoubleClick?: (cellEvent: CellEvent) => void;
19
19
  onCellContextMenu?: (cellEvent: CellEvent) => void;
20
20
  onResizeStart?: (columnId: string, clientX: number, currentWidth: number) => void;
21
+ onResizeDoubleClick?: (columnId: string) => void;
21
22
  onFillHandleMouseDown?: (e: MouseEvent) => void;
22
23
  rowSelectionMode?: 'single' | 'multiple' | 'none';
23
24
  selectedRowIds?: Set<RowId>;
@@ -50,6 +51,7 @@ export declare class TableRenderer<T> {
50
51
  private _tbodyContextmenuHandler;
51
52
  private _theadClickHandler;
52
53
  private _theadMousedownHandler;
54
+ private _theadDblclickHandler;
53
55
  private lastActiveCell;
54
56
  private lastSelectionRange;
55
57
  private lastCopyRange;
@@ -17,6 +17,8 @@ export declare class ColumnResizeState {
17
17
  startResize(columnId: string, clientX: number, currentWidth: number): void;
18
18
  updateResize(clientX: number): number | null;
19
19
  endResize(clientX: number): void;
20
+ /** Set a column width directly (used by double-click auto-fit). */
21
+ setColumnWidth(columnId: string, widthPx: number): void;
20
22
  onColumnWidthChange(handler: (data: ColumnResizeStateEvents['columnWidthChange']) => void): () => void;
21
23
  destroy(): void;
22
24
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alaarab/ogrid-js",
3
- "version": "2.1.13",
3
+ "version": "2.1.14",
4
4
  "description": "OGrid vanilla JS – framework-free data grid with sorting, filtering, pagination, and spreadsheet-style editing.",
5
5
  "main": "dist/esm/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -36,7 +36,7 @@
36
36
  "node": ">=18"
37
37
  },
38
38
  "dependencies": {
39
- "@alaarab/ogrid-core": "2.1.13"
39
+ "@alaarab/ogrid-core": "2.1.14"
40
40
  },
41
41
  "sideEffects": [
42
42
  "**/*.css"