@ornery/ui-grid-vanilla 0.1.9 → 0.1.10
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/demo/index.html +3 -3
- package/demo/main.ts +1 -0
- package/dist/index.d.mts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +95 -3
- package/dist/index.mjs +95 -3
- package/package.json +2 -2
- package/src/grid-controller.ts +29 -2
- package/src/ui-grid-standalone.element.ts +91 -1
package/demo/index.html
CHANGED
|
@@ -179,7 +179,7 @@
|
|
|
179
179
|
<p>
|
|
180
180
|
Familiar <code>gridOptions</code> and <code>onRegisterApi</code>, rebuilt as a
|
|
181
181
|
framework-neutral custom element with the Rust-backed pipeline, grouping, sorting,
|
|
182
|
-
filtering, and virtualization.
|
|
182
|
+
filtering, Excel-style column resizing, and virtualization.
|
|
183
183
|
</p>
|
|
184
184
|
</div>
|
|
185
185
|
<div class="grid-demo-actions">
|
|
@@ -210,8 +210,8 @@
|
|
|
210
210
|
<div class="grid-demo-toolbar">
|
|
211
211
|
<div><strong id="visible-rows-inline">0</strong> of <span id="total-rows-value">0</span> rows</div>
|
|
212
212
|
<p>
|
|
213
|
-
<code>gridOptions</code> compatibility layer: sorting, filtering, grouping,
|
|
214
|
-
and virtualized rendering.
|
|
213
|
+
<code>gridOptions</code> compatibility layer: sorting, filtering, grouping, column resizing,
|
|
214
|
+
templating, and virtualized rendering.
|
|
215
215
|
</p>
|
|
216
216
|
</div>
|
|
217
217
|
|
package/demo/main.ts
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -41,6 +41,7 @@ declare class VanillaGridController {
|
|
|
41
41
|
private expandedTreeRows;
|
|
42
42
|
private pinnedColumns;
|
|
43
43
|
private columnOrder;
|
|
44
|
+
private columnWidthOverrides;
|
|
44
45
|
private currentPage;
|
|
45
46
|
private pageSize;
|
|
46
47
|
private editingCell;
|
|
@@ -84,6 +85,11 @@ declare class VanillaGridController {
|
|
|
84
85
|
updateEditingValue(value: string): void;
|
|
85
86
|
commitCellEdit(): void;
|
|
86
87
|
cancelCellEdit(): void;
|
|
88
|
+
canResizeColumns(): boolean;
|
|
89
|
+
setColumnWidthOverride(columnName: string, widthPx: number): void;
|
|
90
|
+
/** Returns the grid-template-columns string as if `columnName` had the given width,
|
|
91
|
+
* without triggering a full refresh. Used for smooth drag-resize DOM updates. */
|
|
92
|
+
buildTemplateColumnsWithOverride(columnName: string, widthPx: number): string;
|
|
87
93
|
isGroupingEnabled(): boolean;
|
|
88
94
|
isSortingEnabled(): boolean;
|
|
89
95
|
isFilteringEnabled(): boolean;
|
|
@@ -236,6 +242,8 @@ declare class UiGridStandaloneElement extends HTMLElement {
|
|
|
236
242
|
set enablePinning(value: boolean);
|
|
237
243
|
get enableColumnMoving(): boolean;
|
|
238
244
|
set enableColumnMoving(value: boolean);
|
|
245
|
+
get enableColumnResizing(): boolean;
|
|
246
|
+
set enableColumnResizing(value: boolean);
|
|
239
247
|
get enableCellEdit(): boolean;
|
|
240
248
|
set enableCellEdit(value: boolean);
|
|
241
249
|
get enableCellEditOnFocus(): boolean;
|
|
@@ -296,6 +304,7 @@ declare class UiGridStandaloneElement extends HTMLElement {
|
|
|
296
304
|
private render;
|
|
297
305
|
private renderHeaderCell;
|
|
298
306
|
private renderFilterCell;
|
|
307
|
+
private measureAutoColumnWidth;
|
|
299
308
|
private renderDisplayItem;
|
|
300
309
|
private renderBodyCell;
|
|
301
310
|
private renderPagination;
|
package/dist/index.d.ts
CHANGED
|
@@ -41,6 +41,7 @@ declare class VanillaGridController {
|
|
|
41
41
|
private expandedTreeRows;
|
|
42
42
|
private pinnedColumns;
|
|
43
43
|
private columnOrder;
|
|
44
|
+
private columnWidthOverrides;
|
|
44
45
|
private currentPage;
|
|
45
46
|
private pageSize;
|
|
46
47
|
private editingCell;
|
|
@@ -84,6 +85,11 @@ declare class VanillaGridController {
|
|
|
84
85
|
updateEditingValue(value: string): void;
|
|
85
86
|
commitCellEdit(): void;
|
|
86
87
|
cancelCellEdit(): void;
|
|
88
|
+
canResizeColumns(): boolean;
|
|
89
|
+
setColumnWidthOverride(columnName: string, widthPx: number): void;
|
|
90
|
+
/** Returns the grid-template-columns string as if `columnName` had the given width,
|
|
91
|
+
* without triggering a full refresh. Used for smooth drag-resize DOM updates. */
|
|
92
|
+
buildTemplateColumnsWithOverride(columnName: string, widthPx: number): string;
|
|
87
93
|
isGroupingEnabled(): boolean;
|
|
88
94
|
isSortingEnabled(): boolean;
|
|
89
95
|
isFilteringEnabled(): boolean;
|
|
@@ -236,6 +242,8 @@ declare class UiGridStandaloneElement extends HTMLElement {
|
|
|
236
242
|
set enablePinning(value: boolean);
|
|
237
243
|
get enableColumnMoving(): boolean;
|
|
238
244
|
set enableColumnMoving(value: boolean);
|
|
245
|
+
get enableColumnResizing(): boolean;
|
|
246
|
+
set enableColumnResizing(value: boolean);
|
|
239
247
|
get enableCellEdit(): boolean;
|
|
240
248
|
set enableCellEdit(value: boolean);
|
|
241
249
|
get enableCellEditOnFocus(): boolean;
|
|
@@ -296,6 +304,7 @@ declare class UiGridStandaloneElement extends HTMLElement {
|
|
|
296
304
|
private render;
|
|
297
305
|
private renderHeaderCell;
|
|
298
306
|
private renderFilterCell;
|
|
307
|
+
private measureAutoColumnWidth;
|
|
299
308
|
private renderDisplayItem;
|
|
300
309
|
private renderBodyCell;
|
|
301
310
|
private renderPagination;
|
package/dist/index.js
CHANGED
|
@@ -55,6 +55,7 @@ var VanillaGridController = class {
|
|
|
55
55
|
expandedTreeRows = {};
|
|
56
56
|
pinnedColumns = {};
|
|
57
57
|
columnOrder = [];
|
|
58
|
+
columnWidthOverrides = {};
|
|
58
59
|
currentPage = 1;
|
|
59
60
|
pageSize = 0;
|
|
60
61
|
editingCell = null;
|
|
@@ -463,6 +464,24 @@ var VanillaGridController = class {
|
|
|
463
464
|
});
|
|
464
465
|
this.refresh();
|
|
465
466
|
}
|
|
467
|
+
canResizeColumns() {
|
|
468
|
+
return this.options.enableColumnResizing !== false;
|
|
469
|
+
}
|
|
470
|
+
setColumnWidthOverride(columnName, widthPx) {
|
|
471
|
+
const nextWidth = `${Math.max(88, Math.round(widthPx))}px`;
|
|
472
|
+
this.columnWidthOverrides = { ...this.columnWidthOverrides, [columnName]: nextWidth };
|
|
473
|
+
this.refresh();
|
|
474
|
+
}
|
|
475
|
+
/** Returns the grid-template-columns string as if `columnName` had the given width,
|
|
476
|
+
* without triggering a full refresh. Used for smooth drag-resize DOM updates. */
|
|
477
|
+
buildTemplateColumnsWithOverride(columnName, widthPx) {
|
|
478
|
+
const widthStr = `${Math.max(88, Math.round(widthPx))}px`;
|
|
479
|
+
return buildGridTemplateColumns(
|
|
480
|
+
this.visibleColumns.map(
|
|
481
|
+
(c) => c.name === columnName ? { ...c, width: widthStr } : c
|
|
482
|
+
)
|
|
483
|
+
);
|
|
484
|
+
}
|
|
466
485
|
isGroupingEnabled() {
|
|
467
486
|
return (0, import_ui_grid_core.isGridGroupingEnabled)(this.options);
|
|
468
487
|
}
|
|
@@ -581,9 +600,13 @@ var VanillaGridController = class {
|
|
|
581
600
|
}
|
|
582
601
|
refresh() {
|
|
583
602
|
const orderedColumns = orderVisibleColumns(this.options.columnDefs, this.columnOrder);
|
|
603
|
+
const applyWidthOverrides = (columns) => columns.map((col) => {
|
|
604
|
+
const override = this.columnWidthOverrides[col.name];
|
|
605
|
+
return override == null ? col : { ...col, width: override };
|
|
606
|
+
});
|
|
584
607
|
const pinnedEntries = Object.entries(this.pinnedColumns);
|
|
585
608
|
if (pinnedEntries.length === 0) {
|
|
586
|
-
this.visibleColumns = orderedColumns;
|
|
609
|
+
this.visibleColumns = applyWidthOverrides(orderedColumns);
|
|
587
610
|
} else {
|
|
588
611
|
const byName = new Map(orderedColumns.map((column) => [column.name, column]));
|
|
589
612
|
const pinnedLeft = pinnedEntries.filter((entry) => entry[1] === "left").map((entry) => byName.get(entry[0])).filter((column) => column !== void 0);
|
|
@@ -591,7 +614,7 @@ var VanillaGridController = class {
|
|
|
591
614
|
const middleColumns = orderedColumns.filter(
|
|
592
615
|
(column) => this.pinnedColumns[column.name] === void 0
|
|
593
616
|
);
|
|
594
|
-
this.visibleColumns = [...pinnedLeft, ...middleColumns, ...pinnedRight];
|
|
617
|
+
this.visibleColumns = applyWidthOverrides([...pinnedLeft, ...middleColumns, ...pinnedRight]);
|
|
595
618
|
}
|
|
596
619
|
this.pipeline = import_ui_grid_core.defaultGridEngine.buildPipeline({
|
|
597
620
|
options: this.options,
|
|
@@ -915,6 +938,9 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
915
938
|
const enableColumnMoving = this.parseBooleanAttribute("enable-column-moving");
|
|
916
939
|
if (enableColumnMoving !== void 0)
|
|
917
940
|
this.attributeOptions.enableColumnMoving = enableColumnMoving;
|
|
941
|
+
const enableColumnResizing = this.parseBooleanAttribute("enable-column-resizing");
|
|
942
|
+
if (enableColumnResizing !== void 0)
|
|
943
|
+
this.attributeOptions.enableColumnResizing = enableColumnResizing;
|
|
918
944
|
const enableCellEdit = this.parseBooleanAttribute("enable-cell-edit");
|
|
919
945
|
if (enableCellEdit !== void 0) this.attributeOptions.enableCellEdit = enableCellEdit;
|
|
920
946
|
const enableCellEditOnFocus = this.parseBooleanAttribute("enable-cell-edit-on-focus");
|
|
@@ -1163,6 +1189,13 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
1163
1189
|
this.activeOptions = { ...this.activeOptions, enableColumnMoving: value };
|
|
1164
1190
|
this.ensureController(this.buildEffectiveOptions(this.activeOptions));
|
|
1165
1191
|
}
|
|
1192
|
+
get enableColumnResizing() {
|
|
1193
|
+
return this.options.enableColumnResizing ?? true;
|
|
1194
|
+
}
|
|
1195
|
+
set enableColumnResizing(value) {
|
|
1196
|
+
this.activeOptions = { ...this.activeOptions, enableColumnResizing: value };
|
|
1197
|
+
this.ensureController(this.buildEffectiveOptions(this.activeOptions));
|
|
1198
|
+
}
|
|
1166
1199
|
get enableCellEdit() {
|
|
1167
1200
|
return this.options.enableCellEdit ?? false;
|
|
1168
1201
|
}
|
|
@@ -1583,11 +1616,51 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
1583
1616
|
this.controller.setPageSize(value);
|
|
1584
1617
|
}
|
|
1585
1618
|
});
|
|
1619
|
+
root.addEventListener("mousedown", (event) => {
|
|
1620
|
+
const target = event.target;
|
|
1621
|
+
if (!target || !this.controller) return;
|
|
1622
|
+
const resizer = target.closest(".column-resizer[data-column]");
|
|
1623
|
+
if (!resizer || !this.controller.canResizeColumns()) return;
|
|
1624
|
+
const columnName = resizer.dataset["column"];
|
|
1625
|
+
if (!columnName) return;
|
|
1626
|
+
const headerCell = resizer.closest(".header-cell");
|
|
1627
|
+
if (!headerCell) return;
|
|
1628
|
+
event.preventDefault();
|
|
1629
|
+
event.stopPropagation();
|
|
1630
|
+
const startX = event.clientX;
|
|
1631
|
+
const startWidth = headerCell.getBoundingClientRect().width;
|
|
1632
|
+
let lastWidth = startWidth;
|
|
1633
|
+
const handleMove = (moveEvent) => {
|
|
1634
|
+
lastWidth = Math.max(88, startWidth + (moveEvent.clientX - startX));
|
|
1635
|
+
const newTemplate = this.controller.buildTemplateColumnsWithOverride(columnName, lastWidth);
|
|
1636
|
+
const root2 = this.shadowRoot ?? this;
|
|
1637
|
+
root2.querySelectorAll(".header-grid, .filter-grid, .body-grid").forEach((el) => {
|
|
1638
|
+
el.style.gridTemplateColumns = newTemplate;
|
|
1639
|
+
});
|
|
1640
|
+
};
|
|
1641
|
+
const handleUp = () => {
|
|
1642
|
+
window.removeEventListener("mousemove", handleMove);
|
|
1643
|
+
window.removeEventListener("mouseup", handleUp);
|
|
1644
|
+
this.controller.setColumnWidthOverride(columnName, lastWidth);
|
|
1645
|
+
};
|
|
1646
|
+
window.addEventListener("mousemove", handleMove);
|
|
1647
|
+
window.addEventListener("mouseup", handleUp);
|
|
1648
|
+
});
|
|
1586
1649
|
root.addEventListener("dblclick", (event) => {
|
|
1587
1650
|
const target = event.target;
|
|
1588
1651
|
if (!target || !this.controller) {
|
|
1589
1652
|
return;
|
|
1590
1653
|
}
|
|
1654
|
+
const resizer = target.closest(".column-resizer[data-column]");
|
|
1655
|
+
if (resizer && this.controller.canResizeColumns()) {
|
|
1656
|
+
const columnName2 = resizer.dataset["column"];
|
|
1657
|
+
if (columnName2) {
|
|
1658
|
+
event.preventDefault();
|
|
1659
|
+
event.stopPropagation();
|
|
1660
|
+
this.controller.setColumnWidthOverride(columnName2, this.measureAutoColumnWidth(columnName2));
|
|
1661
|
+
return;
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1591
1664
|
const cell = target.closest(".body-cell");
|
|
1592
1665
|
if (!cell) {
|
|
1593
1666
|
return;
|
|
@@ -1913,8 +1986,10 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
1913
1986
|
const sortIconKey = sortDirection === import_ui_grid_core2.SORT_DIRECTIONS.asc ? "sortAsc" : sortDirection === import_ui_grid_core2.SORT_DIRECTIONS.desc ? "sortDesc" : "sortNone";
|
|
1914
1987
|
const draggable = (0, import_ui_grid_core2.canGridMoveColumns)(options) ? 'draggable="true"' : "";
|
|
1915
1988
|
const pinLabel = isPinned ? this.snapshot?.labels.unpin ?? "Unpin" : this.snapshot?.labels.pinColumn ?? "Pin";
|
|
1989
|
+
const canResize = controller.canResizeColumns();
|
|
1916
1990
|
const headerValue = escapeHtml((0, import_ui_grid_core2.formatGridHeaderDisplayValue)((0, import_ui_grid_core2.buildGridHeaderContext)(column)));
|
|
1917
|
-
|
|
1991
|
+
const resizerHtml = canResize ? `<button type="button" class="column-resizer" data-action="resize" data-column="${escapeHtml(column.name)}" aria-label="Resize ${escapeHtml(headerValue)} column" title="Drag to resize, double-click to auto fit"></button>` : "";
|
|
1992
|
+
return `<div class="${classes}" data-column="${escapeHtml(column.name)}" ${draggable} style="${stickyStyle}"><span class="header-label">${headerValue}</span><span class="header-actions">${sortEnabled ? `<button type="button" class="header-action" data-action="sort" data-column="${escapeHtml(column.name)}" aria-label="${escapeHtml(sortLabel)}" ${canSort ? "" : "disabled"}>${this.renderControlIcon(sortIconKey)}<span class="sr-only">${escapeHtml(sortLabel)}</span></button>` : ""}${groupingEnabled ? `<button type="button" class="chip-action${controller.isColumnGrouped(column) ? " chip-action-active" : ""}" data-action="group" data-column="${escapeHtml(column.name)}" aria-label="${escapeHtml(groupingLabel)}" ${canGroup ? "" : "disabled"}>${this.renderControlIcon("group")}<span class="sr-only">${escapeHtml(groupingLabel)}</span></button>` : ""}${canPin ? `<div class="pin-control${this.openPinMenuColumn === column.name ? " pin-control-open" : ""}"><button type="button" class="chip-action pin-trigger${isPinned ? " chip-action-active" : ""}" data-action="pin-trigger" data-column="${escapeHtml(column.name)}" aria-label="${escapeHtml(pinLabel)}">${this.renderControlIcon("pin")}<span class="sr-only">${escapeHtml(pinLabel)}</span></button><div class="pin-menu" role="menu" aria-label="${escapeHtml(pinLabel)}"><button type="button" class="pin-menu-action" data-action="pin-left" data-column="${escapeHtml(column.name)}" aria-label="${escapeHtml(this.snapshot?.labels.pinLeft ?? "Pin left")}">${this.renderIconWithClass("control-icon", "pinLeft")}<span class="sr-only">${escapeHtml(this.snapshot?.labels.pinLeft ?? "Pin left")}</span></button><button type="button" class="pin-menu-action" data-action="pin-right" data-column="${escapeHtml(column.name)}" aria-label="${escapeHtml(this.snapshot?.labels.pinRight ?? "Pin right")}">${this.renderIconWithClass("control-icon", "pinRight")}<span class="sr-only">${escapeHtml(this.snapshot?.labels.pinRight ?? "Pin right")}</span></button></div></div>` : ""}</span>${resizerHtml}</div>`;
|
|
1918
1993
|
}
|
|
1919
1994
|
renderFilterCell(column) {
|
|
1920
1995
|
const value = this.snapshot?.activeFilters[column.name] ?? "";
|
|
@@ -1930,6 +2005,23 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
1930
2005
|
const stickyStyle = pinOffset ? `${pinOffset.side}:${pinOffset.offset};` : "";
|
|
1931
2006
|
return `<label class="${classes}" style="${stickyStyle}"><input class="ui-grid-filter-input" data-role="filter" data-column="${escapeHtml(column.name)}" placeholder="${escapeHtml(controller.filterPlaceholder(column))}" value="${escapeHtml(value)}" ${canFilter ? "" : "disabled"}></label>`;
|
|
1932
2007
|
}
|
|
2008
|
+
measureAutoColumnWidth(columnName) {
|
|
2009
|
+
const root = this.shadowRoot;
|
|
2010
|
+
if (root == null) return 176;
|
|
2011
|
+
const escaped = CSS.escape ? CSS.escape(columnName) : columnName.replace(/([\\".#:[\](){}+~> ])/g, "\\$1");
|
|
2012
|
+
const selectors = [
|
|
2013
|
+
`.header-cell[data-column="${escaped}"]`,
|
|
2014
|
+
`.filter-cell[data-column="${escaped}"]`,
|
|
2015
|
+
`.body-cell[data-column="${escaped}"] .cell-shell`
|
|
2016
|
+
];
|
|
2017
|
+
let maxWidth = 0;
|
|
2018
|
+
for (const selector of selectors) {
|
|
2019
|
+
for (const el of root.querySelectorAll(selector)) {
|
|
2020
|
+
maxWidth = Math.max(maxWidth, el.scrollWidth);
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
return maxWidth + 12;
|
|
2024
|
+
}
|
|
1933
2025
|
renderDisplayItem(item, displayIndex) {
|
|
1934
2026
|
if (!this.snapshot || !this.controller) {
|
|
1935
2027
|
return "";
|
package/dist/index.mjs
CHANGED
|
@@ -97,6 +97,7 @@ var VanillaGridController = class {
|
|
|
97
97
|
expandedTreeRows = {};
|
|
98
98
|
pinnedColumns = {};
|
|
99
99
|
columnOrder = [];
|
|
100
|
+
columnWidthOverrides = {};
|
|
100
101
|
currentPage = 1;
|
|
101
102
|
pageSize = 0;
|
|
102
103
|
editingCell = null;
|
|
@@ -505,6 +506,24 @@ var VanillaGridController = class {
|
|
|
505
506
|
});
|
|
506
507
|
this.refresh();
|
|
507
508
|
}
|
|
509
|
+
canResizeColumns() {
|
|
510
|
+
return this.options.enableColumnResizing !== false;
|
|
511
|
+
}
|
|
512
|
+
setColumnWidthOverride(columnName, widthPx) {
|
|
513
|
+
const nextWidth = `${Math.max(88, Math.round(widthPx))}px`;
|
|
514
|
+
this.columnWidthOverrides = { ...this.columnWidthOverrides, [columnName]: nextWidth };
|
|
515
|
+
this.refresh();
|
|
516
|
+
}
|
|
517
|
+
/** Returns the grid-template-columns string as if `columnName` had the given width,
|
|
518
|
+
* without triggering a full refresh. Used for smooth drag-resize DOM updates. */
|
|
519
|
+
buildTemplateColumnsWithOverride(columnName, widthPx) {
|
|
520
|
+
const widthStr = `${Math.max(88, Math.round(widthPx))}px`;
|
|
521
|
+
return buildGridTemplateColumns(
|
|
522
|
+
this.visibleColumns.map(
|
|
523
|
+
(c) => c.name === columnName ? { ...c, width: widthStr } : c
|
|
524
|
+
)
|
|
525
|
+
);
|
|
526
|
+
}
|
|
508
527
|
isGroupingEnabled() {
|
|
509
528
|
return isGridGroupingEnabled(this.options);
|
|
510
529
|
}
|
|
@@ -623,9 +642,13 @@ var VanillaGridController = class {
|
|
|
623
642
|
}
|
|
624
643
|
refresh() {
|
|
625
644
|
const orderedColumns = orderVisibleColumns(this.options.columnDefs, this.columnOrder);
|
|
645
|
+
const applyWidthOverrides = (columns) => columns.map((col) => {
|
|
646
|
+
const override = this.columnWidthOverrides[col.name];
|
|
647
|
+
return override == null ? col : { ...col, width: override };
|
|
648
|
+
});
|
|
626
649
|
const pinnedEntries = Object.entries(this.pinnedColumns);
|
|
627
650
|
if (pinnedEntries.length === 0) {
|
|
628
|
-
this.visibleColumns = orderedColumns;
|
|
651
|
+
this.visibleColumns = applyWidthOverrides(orderedColumns);
|
|
629
652
|
} else {
|
|
630
653
|
const byName = new Map(orderedColumns.map((column) => [column.name, column]));
|
|
631
654
|
const pinnedLeft = pinnedEntries.filter((entry) => entry[1] === "left").map((entry) => byName.get(entry[0])).filter((column) => column !== void 0);
|
|
@@ -633,7 +656,7 @@ var VanillaGridController = class {
|
|
|
633
656
|
const middleColumns = orderedColumns.filter(
|
|
634
657
|
(column) => this.pinnedColumns[column.name] === void 0
|
|
635
658
|
);
|
|
636
|
-
this.visibleColumns = [...pinnedLeft, ...middleColumns, ...pinnedRight];
|
|
659
|
+
this.visibleColumns = applyWidthOverrides([...pinnedLeft, ...middleColumns, ...pinnedRight]);
|
|
637
660
|
}
|
|
638
661
|
this.pipeline = defaultGridEngine.buildPipeline({
|
|
639
662
|
options: this.options,
|
|
@@ -957,6 +980,9 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
957
980
|
const enableColumnMoving = this.parseBooleanAttribute("enable-column-moving");
|
|
958
981
|
if (enableColumnMoving !== void 0)
|
|
959
982
|
this.attributeOptions.enableColumnMoving = enableColumnMoving;
|
|
983
|
+
const enableColumnResizing = this.parseBooleanAttribute("enable-column-resizing");
|
|
984
|
+
if (enableColumnResizing !== void 0)
|
|
985
|
+
this.attributeOptions.enableColumnResizing = enableColumnResizing;
|
|
960
986
|
const enableCellEdit = this.parseBooleanAttribute("enable-cell-edit");
|
|
961
987
|
if (enableCellEdit !== void 0) this.attributeOptions.enableCellEdit = enableCellEdit;
|
|
962
988
|
const enableCellEditOnFocus = this.parseBooleanAttribute("enable-cell-edit-on-focus");
|
|
@@ -1205,6 +1231,13 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
1205
1231
|
this.activeOptions = { ...this.activeOptions, enableColumnMoving: value };
|
|
1206
1232
|
this.ensureController(this.buildEffectiveOptions(this.activeOptions));
|
|
1207
1233
|
}
|
|
1234
|
+
get enableColumnResizing() {
|
|
1235
|
+
return this.options.enableColumnResizing ?? true;
|
|
1236
|
+
}
|
|
1237
|
+
set enableColumnResizing(value) {
|
|
1238
|
+
this.activeOptions = { ...this.activeOptions, enableColumnResizing: value };
|
|
1239
|
+
this.ensureController(this.buildEffectiveOptions(this.activeOptions));
|
|
1240
|
+
}
|
|
1208
1241
|
get enableCellEdit() {
|
|
1209
1242
|
return this.options.enableCellEdit ?? false;
|
|
1210
1243
|
}
|
|
@@ -1625,11 +1658,51 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
1625
1658
|
this.controller.setPageSize(value);
|
|
1626
1659
|
}
|
|
1627
1660
|
});
|
|
1661
|
+
root.addEventListener("mousedown", (event) => {
|
|
1662
|
+
const target = event.target;
|
|
1663
|
+
if (!target || !this.controller) return;
|
|
1664
|
+
const resizer = target.closest(".column-resizer[data-column]");
|
|
1665
|
+
if (!resizer || !this.controller.canResizeColumns()) return;
|
|
1666
|
+
const columnName = resizer.dataset["column"];
|
|
1667
|
+
if (!columnName) return;
|
|
1668
|
+
const headerCell = resizer.closest(".header-cell");
|
|
1669
|
+
if (!headerCell) return;
|
|
1670
|
+
event.preventDefault();
|
|
1671
|
+
event.stopPropagation();
|
|
1672
|
+
const startX = event.clientX;
|
|
1673
|
+
const startWidth = headerCell.getBoundingClientRect().width;
|
|
1674
|
+
let lastWidth = startWidth;
|
|
1675
|
+
const handleMove = (moveEvent) => {
|
|
1676
|
+
lastWidth = Math.max(88, startWidth + (moveEvent.clientX - startX));
|
|
1677
|
+
const newTemplate = this.controller.buildTemplateColumnsWithOverride(columnName, lastWidth);
|
|
1678
|
+
const root2 = this.shadowRoot ?? this;
|
|
1679
|
+
root2.querySelectorAll(".header-grid, .filter-grid, .body-grid").forEach((el) => {
|
|
1680
|
+
el.style.gridTemplateColumns = newTemplate;
|
|
1681
|
+
});
|
|
1682
|
+
};
|
|
1683
|
+
const handleUp = () => {
|
|
1684
|
+
window.removeEventListener("mousemove", handleMove);
|
|
1685
|
+
window.removeEventListener("mouseup", handleUp);
|
|
1686
|
+
this.controller.setColumnWidthOverride(columnName, lastWidth);
|
|
1687
|
+
};
|
|
1688
|
+
window.addEventListener("mousemove", handleMove);
|
|
1689
|
+
window.addEventListener("mouseup", handleUp);
|
|
1690
|
+
});
|
|
1628
1691
|
root.addEventListener("dblclick", (event) => {
|
|
1629
1692
|
const target = event.target;
|
|
1630
1693
|
if (!target || !this.controller) {
|
|
1631
1694
|
return;
|
|
1632
1695
|
}
|
|
1696
|
+
const resizer = target.closest(".column-resizer[data-column]");
|
|
1697
|
+
if (resizer && this.controller.canResizeColumns()) {
|
|
1698
|
+
const columnName2 = resizer.dataset["column"];
|
|
1699
|
+
if (columnName2) {
|
|
1700
|
+
event.preventDefault();
|
|
1701
|
+
event.stopPropagation();
|
|
1702
|
+
this.controller.setColumnWidthOverride(columnName2, this.measureAutoColumnWidth(columnName2));
|
|
1703
|
+
return;
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1633
1706
|
const cell = target.closest(".body-cell");
|
|
1634
1707
|
if (!cell) {
|
|
1635
1708
|
return;
|
|
@@ -1955,8 +2028,10 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
1955
2028
|
const sortIconKey = sortDirection === SORT_DIRECTIONS2.asc ? "sortAsc" : sortDirection === SORT_DIRECTIONS2.desc ? "sortDesc" : "sortNone";
|
|
1956
2029
|
const draggable = canGridMoveColumns2(options) ? 'draggable="true"' : "";
|
|
1957
2030
|
const pinLabel = isPinned ? this.snapshot?.labels.unpin ?? "Unpin" : this.snapshot?.labels.pinColumn ?? "Pin";
|
|
2031
|
+
const canResize = controller.canResizeColumns();
|
|
1958
2032
|
const headerValue = escapeHtml(formatGridHeaderDisplayValue(buildGridHeaderContext(column)));
|
|
1959
|
-
|
|
2033
|
+
const resizerHtml = canResize ? `<button type="button" class="column-resizer" data-action="resize" data-column="${escapeHtml(column.name)}" aria-label="Resize ${escapeHtml(headerValue)} column" title="Drag to resize, double-click to auto fit"></button>` : "";
|
|
2034
|
+
return `<div class="${classes}" data-column="${escapeHtml(column.name)}" ${draggable} style="${stickyStyle}"><span class="header-label">${headerValue}</span><span class="header-actions">${sortEnabled ? `<button type="button" class="header-action" data-action="sort" data-column="${escapeHtml(column.name)}" aria-label="${escapeHtml(sortLabel)}" ${canSort ? "" : "disabled"}>${this.renderControlIcon(sortIconKey)}<span class="sr-only">${escapeHtml(sortLabel)}</span></button>` : ""}${groupingEnabled ? `<button type="button" class="chip-action${controller.isColumnGrouped(column) ? " chip-action-active" : ""}" data-action="group" data-column="${escapeHtml(column.name)}" aria-label="${escapeHtml(groupingLabel)}" ${canGroup ? "" : "disabled"}>${this.renderControlIcon("group")}<span class="sr-only">${escapeHtml(groupingLabel)}</span></button>` : ""}${canPin ? `<div class="pin-control${this.openPinMenuColumn === column.name ? " pin-control-open" : ""}"><button type="button" class="chip-action pin-trigger${isPinned ? " chip-action-active" : ""}" data-action="pin-trigger" data-column="${escapeHtml(column.name)}" aria-label="${escapeHtml(pinLabel)}">${this.renderControlIcon("pin")}<span class="sr-only">${escapeHtml(pinLabel)}</span></button><div class="pin-menu" role="menu" aria-label="${escapeHtml(pinLabel)}"><button type="button" class="pin-menu-action" data-action="pin-left" data-column="${escapeHtml(column.name)}" aria-label="${escapeHtml(this.snapshot?.labels.pinLeft ?? "Pin left")}">${this.renderIconWithClass("control-icon", "pinLeft")}<span class="sr-only">${escapeHtml(this.snapshot?.labels.pinLeft ?? "Pin left")}</span></button><button type="button" class="pin-menu-action" data-action="pin-right" data-column="${escapeHtml(column.name)}" aria-label="${escapeHtml(this.snapshot?.labels.pinRight ?? "Pin right")}">${this.renderIconWithClass("control-icon", "pinRight")}<span class="sr-only">${escapeHtml(this.snapshot?.labels.pinRight ?? "Pin right")}</span></button></div></div>` : ""}</span>${resizerHtml}</div>`;
|
|
1960
2035
|
}
|
|
1961
2036
|
renderFilterCell(column) {
|
|
1962
2037
|
const value = this.snapshot?.activeFilters[column.name] ?? "";
|
|
@@ -1972,6 +2047,23 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
1972
2047
|
const stickyStyle = pinOffset ? `${pinOffset.side}:${pinOffset.offset};` : "";
|
|
1973
2048
|
return `<label class="${classes}" style="${stickyStyle}"><input class="ui-grid-filter-input" data-role="filter" data-column="${escapeHtml(column.name)}" placeholder="${escapeHtml(controller.filterPlaceholder(column))}" value="${escapeHtml(value)}" ${canFilter ? "" : "disabled"}></label>`;
|
|
1974
2049
|
}
|
|
2050
|
+
measureAutoColumnWidth(columnName) {
|
|
2051
|
+
const root = this.shadowRoot;
|
|
2052
|
+
if (root == null) return 176;
|
|
2053
|
+
const escaped = CSS.escape ? CSS.escape(columnName) : columnName.replace(/([\\".#:[\](){}+~> ])/g, "\\$1");
|
|
2054
|
+
const selectors = [
|
|
2055
|
+
`.header-cell[data-column="${escaped}"]`,
|
|
2056
|
+
`.filter-cell[data-column="${escaped}"]`,
|
|
2057
|
+
`.body-cell[data-column="${escaped}"] .cell-shell`
|
|
2058
|
+
];
|
|
2059
|
+
let maxWidth = 0;
|
|
2060
|
+
for (const selector of selectors) {
|
|
2061
|
+
for (const el of root.querySelectorAll(selector)) {
|
|
2062
|
+
maxWidth = Math.max(maxWidth, el.scrollWidth);
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
return maxWidth + 12;
|
|
2066
|
+
}
|
|
1975
2067
|
renderDisplayItem(item, displayIndex) {
|
|
1976
2068
|
if (!this.snapshot || !this.controller) {
|
|
1977
2069
|
return "";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ornery/ui-grid-vanilla",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "Vanilla DOM wrapper for the Rust/WASM-backed @ornery/ui-grid-core custom element",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
}
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@ornery/ui-grid-core": "0.1.
|
|
19
|
+
"@ornery/ui-grid-core": "0.1.10"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"typescript": "~5.8.0",
|
package/src/grid-controller.ts
CHANGED
|
@@ -134,6 +134,7 @@ export class VanillaGridController {
|
|
|
134
134
|
private expandedTreeRows: Record<string, boolean> = {};
|
|
135
135
|
private pinnedColumns: PinnedColumnState = {};
|
|
136
136
|
private columnOrder: string[] = [];
|
|
137
|
+
private columnWidthOverrides: Record<string, string> = {};
|
|
137
138
|
private currentPage = 1;
|
|
138
139
|
private pageSize = 0;
|
|
139
140
|
private editingCell: GridCellPosition | null = null;
|
|
@@ -590,6 +591,27 @@ export class VanillaGridController {
|
|
|
590
591
|
this.refresh();
|
|
591
592
|
}
|
|
592
593
|
|
|
594
|
+
canResizeColumns(): boolean {
|
|
595
|
+
return this.options.enableColumnResizing !== false;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
setColumnWidthOverride(columnName: string, widthPx: number): void {
|
|
599
|
+
const nextWidth = `${Math.max(88, Math.round(widthPx))}px`;
|
|
600
|
+
this.columnWidthOverrides = { ...this.columnWidthOverrides, [columnName]: nextWidth };
|
|
601
|
+
this.refresh();
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/** Returns the grid-template-columns string as if `columnName` had the given width,
|
|
605
|
+
* without triggering a full refresh. Used for smooth drag-resize DOM updates. */
|
|
606
|
+
buildTemplateColumnsWithOverride(columnName: string, widthPx: number): string {
|
|
607
|
+
const widthStr = `${Math.max(88, Math.round(widthPx))}px`;
|
|
608
|
+
return buildGridTemplateColumns(
|
|
609
|
+
this.visibleColumns.map((c) =>
|
|
610
|
+
c.name === columnName ? { ...c, width: widthStr } : c,
|
|
611
|
+
),
|
|
612
|
+
);
|
|
613
|
+
}
|
|
614
|
+
|
|
593
615
|
isGroupingEnabled(): boolean {
|
|
594
616
|
return isGridGroupingEnabled(this.options);
|
|
595
617
|
}
|
|
@@ -743,10 +765,15 @@ export class VanillaGridController {
|
|
|
743
765
|
|
|
744
766
|
private refresh(): void {
|
|
745
767
|
const orderedColumns = orderVisibleColumns(this.options.columnDefs, this.columnOrder);
|
|
768
|
+
const applyWidthOverrides = (columns: GridColumnDef[]): GridColumnDef[] =>
|
|
769
|
+
columns.map((col) => {
|
|
770
|
+
const override = this.columnWidthOverrides[col.name];
|
|
771
|
+
return override == null ? col : { ...col, width: override };
|
|
772
|
+
});
|
|
746
773
|
const pinnedEntries = Object.entries(this.pinnedColumns);
|
|
747
774
|
|
|
748
775
|
if (pinnedEntries.length === 0) {
|
|
749
|
-
this.visibleColumns = orderedColumns;
|
|
776
|
+
this.visibleColumns = applyWidthOverrides(orderedColumns);
|
|
750
777
|
} else {
|
|
751
778
|
const byName = new Map(orderedColumns.map((column) => [column.name, column]));
|
|
752
779
|
const pinnedLeft = pinnedEntries
|
|
@@ -760,7 +787,7 @@ export class VanillaGridController {
|
|
|
760
787
|
const middleColumns = orderedColumns.filter(
|
|
761
788
|
(column) => this.pinnedColumns[column.name] === undefined,
|
|
762
789
|
);
|
|
763
|
-
this.visibleColumns = [...pinnedLeft, ...middleColumns, ...pinnedRight];
|
|
790
|
+
this.visibleColumns = applyWidthOverrides([...pinnedLeft, ...middleColumns, ...pinnedRight]);
|
|
764
791
|
}
|
|
765
792
|
|
|
766
793
|
this.pipeline = defaultGridEngine.buildPipeline({
|
|
@@ -5,8 +5,11 @@ import {
|
|
|
5
5
|
canGridMoveColumns,
|
|
6
6
|
downloadGridCsvFile,
|
|
7
7
|
exportCsvRows,
|
|
8
|
+
findNextGridCell,
|
|
8
9
|
formatGridHeaderDisplayValue,
|
|
9
10
|
getCellValue,
|
|
11
|
+
isGridNavigationKey,
|
|
12
|
+
isPrintableGridKey,
|
|
10
13
|
sanitizeDownloadFilename,
|
|
11
14
|
type DisplayItem,
|
|
12
15
|
type GridColumnDef,
|
|
@@ -283,6 +286,10 @@ export class UiGridStandaloneElement extends HTMLElement {
|
|
|
283
286
|
if (enableColumnMoving !== undefined)
|
|
284
287
|
this.attributeOptions.enableColumnMoving = enableColumnMoving;
|
|
285
288
|
|
|
289
|
+
const enableColumnResizing = this.parseBooleanAttribute('enable-column-resizing');
|
|
290
|
+
if (enableColumnResizing !== undefined)
|
|
291
|
+
this.attributeOptions.enableColumnResizing = enableColumnResizing;
|
|
292
|
+
|
|
286
293
|
const enableCellEdit = this.parseBooleanAttribute('enable-cell-edit');
|
|
287
294
|
if (enableCellEdit !== undefined) this.attributeOptions.enableCellEdit = enableCellEdit;
|
|
288
295
|
|
|
@@ -580,6 +587,14 @@ export class UiGridStandaloneElement extends HTMLElement {
|
|
|
580
587
|
this.ensureController(this.buildEffectiveOptions(this.activeOptions as VanillaGridOptions));
|
|
581
588
|
}
|
|
582
589
|
|
|
590
|
+
get enableColumnResizing(): boolean {
|
|
591
|
+
return (this.options as any).enableColumnResizing ?? true;
|
|
592
|
+
}
|
|
593
|
+
set enableColumnResizing(value: boolean) {
|
|
594
|
+
this.activeOptions = { ...this.activeOptions, enableColumnResizing: value } as any;
|
|
595
|
+
this.ensureController(this.buildEffectiveOptions(this.activeOptions as VanillaGridOptions));
|
|
596
|
+
}
|
|
597
|
+
|
|
583
598
|
get enableCellEdit(): boolean {
|
|
584
599
|
return this.options.enableCellEdit ?? false;
|
|
585
600
|
}
|
|
@@ -1084,12 +1099,65 @@ export class UiGridStandaloneElement extends HTMLElement {
|
|
|
1084
1099
|
}
|
|
1085
1100
|
});
|
|
1086
1101
|
|
|
1102
|
+
root.addEventListener('mousedown', (event) => {
|
|
1103
|
+
const target = event.target as HTMLElement | null;
|
|
1104
|
+
if (!target || !this.controller) return;
|
|
1105
|
+
|
|
1106
|
+
const resizer = target.closest<HTMLElement>('.column-resizer[data-column]');
|
|
1107
|
+
if (!resizer || !this.controller.canResizeColumns()) return;
|
|
1108
|
+
|
|
1109
|
+
const columnName = resizer.dataset['column'];
|
|
1110
|
+
if (!columnName) return;
|
|
1111
|
+
|
|
1112
|
+
const headerCell = resizer.closest<HTMLElement>('.header-cell');
|
|
1113
|
+
if (!headerCell) return;
|
|
1114
|
+
|
|
1115
|
+
event.preventDefault();
|
|
1116
|
+
event.stopPropagation();
|
|
1117
|
+
|
|
1118
|
+
const startX = (event as MouseEvent).clientX;
|
|
1119
|
+
const startWidth = headerCell.getBoundingClientRect().width;
|
|
1120
|
+
let lastWidth = startWidth;
|
|
1121
|
+
|
|
1122
|
+
const handleMove = (moveEvent: MouseEvent): void => {
|
|
1123
|
+
lastWidth = Math.max(88, startWidth + (moveEvent.clientX - startX));
|
|
1124
|
+
|
|
1125
|
+
// Write directly to DOM — skip full refresh while dragging.
|
|
1126
|
+
const newTemplate = this.controller!.buildTemplateColumnsWithOverride(columnName, lastWidth);
|
|
1127
|
+
const root = this.shadowRoot ?? this;
|
|
1128
|
+
(root as ShadowRoot | HTMLElement).querySelectorAll<HTMLElement>('.header-grid, .filter-grid, .body-grid').forEach((el) => {
|
|
1129
|
+
el.style.gridTemplateColumns = newTemplate;
|
|
1130
|
+
});
|
|
1131
|
+
};
|
|
1132
|
+
|
|
1133
|
+
const handleUp = (): void => {
|
|
1134
|
+
window.removeEventListener('mousemove', handleMove);
|
|
1135
|
+
window.removeEventListener('mouseup', handleUp);
|
|
1136
|
+
// Commit final width once — triggers one full refresh.
|
|
1137
|
+
this.controller!.setColumnWidthOverride(columnName, lastWidth);
|
|
1138
|
+
};
|
|
1139
|
+
|
|
1140
|
+
window.addEventListener('mousemove', handleMove);
|
|
1141
|
+
window.addEventListener('mouseup', handleUp);
|
|
1142
|
+
});
|
|
1143
|
+
|
|
1087
1144
|
root.addEventListener('dblclick', (event) => {
|
|
1088
1145
|
const target = event.target as HTMLElement | null;
|
|
1089
1146
|
if (!target || !this.controller) {
|
|
1090
1147
|
return;
|
|
1091
1148
|
}
|
|
1092
1149
|
|
|
1150
|
+
const resizer = target.closest<HTMLElement>('.column-resizer[data-column]');
|
|
1151
|
+
if (resizer && this.controller.canResizeColumns()) {
|
|
1152
|
+
const columnName = resizer.dataset['column'];
|
|
1153
|
+
if (columnName) {
|
|
1154
|
+
event.preventDefault();
|
|
1155
|
+
event.stopPropagation();
|
|
1156
|
+
this.controller.setColumnWidthOverride(columnName, this.measureAutoColumnWidth(columnName));
|
|
1157
|
+
return;
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1093
1161
|
const cell = target.closest<HTMLElement>('.body-cell');
|
|
1094
1162
|
if (!cell) {
|
|
1095
1163
|
return;
|
|
@@ -1520,9 +1588,13 @@ export class UiGridStandaloneElement extends HTMLElement {
|
|
|
1520
1588
|
const pinLabel = isPinned
|
|
1521
1589
|
? (this.snapshot?.labels.unpin ?? 'Unpin')
|
|
1522
1590
|
: (this.snapshot?.labels.pinColumn ?? 'Pin');
|
|
1591
|
+
const canResize = controller.canResizeColumns();
|
|
1523
1592
|
const headerValue = escapeHtml(formatGridHeaderDisplayValue(buildGridHeaderContext(column)));
|
|
1593
|
+
const resizerHtml = canResize
|
|
1594
|
+
? `<button type="button" class="column-resizer" data-action="resize" data-column="${escapeHtml(column.name)}" aria-label="Resize ${escapeHtml(headerValue)} column" title="Drag to resize, double-click to auto fit"></button>`
|
|
1595
|
+
: '';
|
|
1524
1596
|
|
|
1525
|
-
return `<div class="${classes}" data-column="${escapeHtml(column.name)}" ${draggable} style="${stickyStyle}"><span class="header-label">${headerValue}</span><span class="header-actions">${sortEnabled ? `<button type="button" class="header-action" data-action="sort" data-column="${escapeHtml(column.name)}" aria-label="${escapeHtml(sortLabel)}" ${canSort ? '' : 'disabled'}>${this.renderControlIcon(sortIconKey)}<span class="sr-only">${escapeHtml(sortLabel)}</span></button>` : ''}${groupingEnabled ? `<button type="button" class="chip-action${controller.isColumnGrouped(column) ? ' chip-action-active' : ''}" data-action="group" data-column="${escapeHtml(column.name)}" aria-label="${escapeHtml(groupingLabel)}" ${canGroup ? '' : 'disabled'}>${this.renderControlIcon('group')}<span class="sr-only">${escapeHtml(groupingLabel)}</span></button>` : ''}${canPin ? `<div class="pin-control${this.openPinMenuColumn === column.name ? ' pin-control-open' : ''}"><button type="button" class="chip-action pin-trigger${isPinned ? ' chip-action-active' : ''}" data-action="pin-trigger" data-column="${escapeHtml(column.name)}" aria-label="${escapeHtml(pinLabel)}">${this.renderControlIcon('pin')}<span class="sr-only">${escapeHtml(pinLabel)}</span></button><div class="pin-menu" role="menu" aria-label="${escapeHtml(pinLabel)}"><button type="button" class="pin-menu-action" data-action="pin-left" data-column="${escapeHtml(column.name)}" aria-label="${escapeHtml(this.snapshot?.labels.pinLeft ?? 'Pin left')}">${this.renderIconWithClass('control-icon', 'pinLeft')}<span class="sr-only">${escapeHtml(this.snapshot?.labels.pinLeft ?? 'Pin left')}</span></button><button type="button" class="pin-menu-action" data-action="pin-right" data-column="${escapeHtml(column.name)}" aria-label="${escapeHtml(this.snapshot?.labels.pinRight ?? 'Pin right')}">${this.renderIconWithClass('control-icon', 'pinRight')}<span class="sr-only">${escapeHtml(this.snapshot?.labels.pinRight ?? 'Pin right')}</span></button></div></div>` : ''}</span
|
|
1597
|
+
return `<div class="${classes}" data-column="${escapeHtml(column.name)}" ${draggable} style="${stickyStyle}"><span class="header-label">${headerValue}</span><span class="header-actions">${sortEnabled ? `<button type="button" class="header-action" data-action="sort" data-column="${escapeHtml(column.name)}" aria-label="${escapeHtml(sortLabel)}" ${canSort ? '' : 'disabled'}>${this.renderControlIcon(sortIconKey)}<span class="sr-only">${escapeHtml(sortLabel)}</span></button>` : ''}${groupingEnabled ? `<button type="button" class="chip-action${controller.isColumnGrouped(column) ? ' chip-action-active' : ''}" data-action="group" data-column="${escapeHtml(column.name)}" aria-label="${escapeHtml(groupingLabel)}" ${canGroup ? '' : 'disabled'}>${this.renderControlIcon('group')}<span class="sr-only">${escapeHtml(groupingLabel)}</span></button>` : ''}${canPin ? `<div class="pin-control${this.openPinMenuColumn === column.name ? ' pin-control-open' : ''}"><button type="button" class="chip-action pin-trigger${isPinned ? ' chip-action-active' : ''}" data-action="pin-trigger" data-column="${escapeHtml(column.name)}" aria-label="${escapeHtml(pinLabel)}">${this.renderControlIcon('pin')}<span class="sr-only">${escapeHtml(pinLabel)}</span></button><div class="pin-menu" role="menu" aria-label="${escapeHtml(pinLabel)}"><button type="button" class="pin-menu-action" data-action="pin-left" data-column="${escapeHtml(column.name)}" aria-label="${escapeHtml(this.snapshot?.labels.pinLeft ?? 'Pin left')}">${this.renderIconWithClass('control-icon', 'pinLeft')}<span class="sr-only">${escapeHtml(this.snapshot?.labels.pinLeft ?? 'Pin left')}</span></button><button type="button" class="pin-menu-action" data-action="pin-right" data-column="${escapeHtml(column.name)}" aria-label="${escapeHtml(this.snapshot?.labels.pinRight ?? 'Pin right')}">${this.renderIconWithClass('control-icon', 'pinRight')}<span class="sr-only">${escapeHtml(this.snapshot?.labels.pinRight ?? 'Pin right')}</span></button></div></div>` : ''}</span>${resizerHtml}</div>`;
|
|
1526
1598
|
}
|
|
1527
1599
|
|
|
1528
1600
|
private renderFilterCell(column: GridColumnDef): string {
|
|
@@ -1542,6 +1614,24 @@ export class UiGridStandaloneElement extends HTMLElement {
|
|
|
1542
1614
|
return `<label class="${classes}" style="${stickyStyle}"><input class="ui-grid-filter-input" data-role="filter" data-column="${escapeHtml(column.name)}" placeholder="${escapeHtml(controller.filterPlaceholder(column))}" value="${escapeHtml(value)}" ${canFilter ? '' : 'disabled'}></label>`;
|
|
1543
1615
|
}
|
|
1544
1616
|
|
|
1617
|
+
private measureAutoColumnWidth(columnName: string): number {
|
|
1618
|
+
const root = this.shadowRoot;
|
|
1619
|
+
if (root == null) return 176;
|
|
1620
|
+
const escaped = CSS.escape ? CSS.escape(columnName) : columnName.replace(/([\\".#:[\](){}+~> ])/g, '\\$1');
|
|
1621
|
+
const selectors = [
|
|
1622
|
+
`.header-cell[data-column="${escaped}"]`,
|
|
1623
|
+
`.filter-cell[data-column="${escaped}"]`,
|
|
1624
|
+
`.body-cell[data-column="${escaped}"] .cell-shell`,
|
|
1625
|
+
];
|
|
1626
|
+
let maxWidth = 0;
|
|
1627
|
+
for (const selector of selectors) {
|
|
1628
|
+
for (const el of root.querySelectorAll<HTMLElement>(selector)) {
|
|
1629
|
+
maxWidth = Math.max(maxWidth, el.scrollWidth);
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
return maxWidth + 12;
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1545
1635
|
private renderDisplayItem(item: DisplayItem, displayIndex: number): string {
|
|
1546
1636
|
if (!this.snapshot || !this.controller) {
|
|
1547
1637
|
return '';
|