@toolbox-web/grid 0.4.1 → 0.4.2

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.
Files changed (157) hide show
  1. package/README.md +10 -13
  2. package/all.js +1101 -1048
  3. package/all.js.map +1 -1
  4. package/index.js +245 -137
  5. package/index.js.map +1 -1
  6. package/lib/core/grid.d.ts +10 -0
  7. package/lib/core/grid.d.ts.map +1 -1
  8. package/lib/core/internal/config-manager.d.ts +1 -0
  9. package/lib/core/internal/config-manager.d.ts.map +1 -1
  10. package/lib/core/internal/keyboard.d.ts.map +1 -1
  11. package/lib/core/internal/utils.d.ts +1 -0
  12. package/lib/core/internal/utils.d.ts.map +1 -1
  13. package/lib/core/plugin/base-plugin.d.ts +57 -1
  14. package/lib/core/plugin/base-plugin.d.ts.map +1 -1
  15. package/lib/core/plugin/expander-column.d.ts +51 -0
  16. package/lib/core/plugin/expander-column.d.ts.map +1 -0
  17. package/lib/core/plugin/types.d.ts +117 -1
  18. package/lib/core/plugin/types.d.ts.map +1 -1
  19. package/lib/core/types.d.ts +4 -2
  20. package/lib/core/types.d.ts.map +1 -1
  21. package/lib/plugins/clipboard/ClipboardPlugin.d.ts +5 -4
  22. package/lib/plugins/clipboard/ClipboardPlugin.d.ts.map +1 -1
  23. package/lib/plugins/clipboard/index.d.ts +1 -1
  24. package/lib/plugins/clipboard/index.d.ts.map +1 -1
  25. package/lib/plugins/clipboard/index.js +282 -188
  26. package/lib/plugins/clipboard/index.js.map +1 -1
  27. package/lib/plugins/clipboard/types.d.ts +72 -2
  28. package/lib/plugins/clipboard/types.d.ts.map +1 -1
  29. package/lib/plugins/column-virtualization/ColumnVirtualizationPlugin.d.ts +0 -1
  30. package/lib/plugins/column-virtualization/ColumnVirtualizationPlugin.d.ts.map +1 -1
  31. package/lib/plugins/column-virtualization/index.js +102 -26
  32. package/lib/plugins/column-virtualization/index.js.map +1 -1
  33. package/lib/plugins/context-menu/ContextMenuPlugin.d.ts +0 -1
  34. package/lib/plugins/context-menu/ContextMenuPlugin.d.ts.map +1 -1
  35. package/lib/plugins/context-menu/index.js +154 -78
  36. package/lib/plugins/context-menu/index.js.map +1 -1
  37. package/lib/plugins/editing/EditingPlugin.d.ts +1 -7
  38. package/lib/plugins/editing/EditingPlugin.d.ts.map +1 -1
  39. package/lib/plugins/editing/index.js +200 -136
  40. package/lib/plugins/editing/index.js.map +1 -1
  41. package/lib/plugins/export/ExportPlugin.d.ts +0 -1
  42. package/lib/plugins/export/ExportPlugin.d.ts.map +1 -1
  43. package/lib/plugins/export/index.js +175 -99
  44. package/lib/plugins/export/index.js.map +1 -1
  45. package/lib/plugins/filtering/FilteringPlugin.d.ts +5 -2
  46. package/lib/plugins/filtering/FilteringPlugin.d.ts.map +1 -1
  47. package/lib/plugins/filtering/index.js +129 -43
  48. package/lib/plugins/filtering/index.js.map +1 -1
  49. package/lib/plugins/grouping-columns/GroupingColumnsPlugin.d.ts +1 -2
  50. package/lib/plugins/grouping-columns/GroupingColumnsPlugin.d.ts.map +1 -1
  51. package/lib/plugins/grouping-columns/grouping-columns.d.ts +1 -1
  52. package/lib/plugins/grouping-columns/grouping-columns.d.ts.map +1 -1
  53. package/lib/plugins/grouping-columns/index.js +144 -66
  54. package/lib/plugins/grouping-columns/index.js.map +1 -1
  55. package/lib/plugins/grouping-rows/GroupingRowsPlugin.d.ts +14 -2
  56. package/lib/plugins/grouping-rows/GroupingRowsPlugin.d.ts.map +1 -1
  57. package/lib/plugins/grouping-rows/index.js +230 -138
  58. package/lib/plugins/grouping-rows/index.js.map +1 -1
  59. package/lib/plugins/master-detail/MasterDetailPlugin.d.ts +13 -11
  60. package/lib/plugins/master-detail/MasterDetailPlugin.d.ts.map +1 -1
  61. package/lib/plugins/master-detail/index.js +265 -196
  62. package/lib/plugins/master-detail/index.js.map +1 -1
  63. package/lib/plugins/master-detail/types.d.ts +0 -10
  64. package/lib/plugins/master-detail/types.d.ts.map +1 -1
  65. package/lib/plugins/multi-sort/MultiSortPlugin.d.ts +1 -2
  66. package/lib/plugins/multi-sort/MultiSortPlugin.d.ts.map +1 -1
  67. package/lib/plugins/multi-sort/index.js +105 -31
  68. package/lib/plugins/multi-sort/index.js.map +1 -1
  69. package/lib/plugins/pinned-columns/PinnedColumnsPlugin.d.ts +0 -1
  70. package/lib/plugins/pinned-columns/PinnedColumnsPlugin.d.ts.map +1 -1
  71. package/lib/plugins/pinned-columns/index.js +128 -52
  72. package/lib/plugins/pinned-columns/index.js.map +1 -1
  73. package/lib/plugins/pinned-rows/PinnedRowsPlugin.d.ts +1 -2
  74. package/lib/plugins/pinned-rows/PinnedRowsPlugin.d.ts.map +1 -1
  75. package/lib/plugins/pinned-rows/index.js +162 -88
  76. package/lib/plugins/pinned-rows/index.js.map +1 -1
  77. package/lib/plugins/pivot/PivotPlugin.d.ts +26 -4
  78. package/lib/plugins/pivot/PivotPlugin.d.ts.map +1 -1
  79. package/lib/plugins/pivot/index.js +398 -310
  80. package/lib/plugins/pivot/index.js.map +1 -1
  81. package/lib/plugins/pivot/pivot-rows.d.ts +2 -1
  82. package/lib/plugins/pivot/pivot-rows.d.ts.map +1 -1
  83. package/lib/plugins/reorder/ReorderPlugin.d.ts +13 -10
  84. package/lib/plugins/reorder/ReorderPlugin.d.ts.map +1 -1
  85. package/lib/plugins/reorder/index.js +288 -226
  86. package/lib/plugins/reorder/index.js.map +1 -1
  87. package/lib/plugins/selection/SelectionPlugin.d.ts +21 -3
  88. package/lib/plugins/selection/SelectionPlugin.d.ts.map +1 -1
  89. package/lib/plugins/selection/index.d.ts +2 -2
  90. package/lib/plugins/selection/index.d.ts.map +1 -1
  91. package/lib/plugins/selection/index.js +276 -145
  92. package/lib/plugins/selection/index.js.map +1 -1
  93. package/lib/plugins/selection/types.d.ts +24 -0
  94. package/lib/plugins/selection/types.d.ts.map +1 -1
  95. package/lib/plugins/server-side/ServerSidePlugin.d.ts +0 -1
  96. package/lib/plugins/server-side/ServerSidePlugin.d.ts.map +1 -1
  97. package/lib/plugins/server-side/index.js +83 -7
  98. package/lib/plugins/server-side/index.js.map +1 -1
  99. package/lib/plugins/tree/TreePlugin.d.ts +5 -1
  100. package/lib/plugins/tree/TreePlugin.d.ts.map +1 -1
  101. package/lib/plugins/tree/index.js +197 -112
  102. package/lib/plugins/tree/index.js.map +1 -1
  103. package/lib/plugins/tree/types.d.ts +0 -10
  104. package/lib/plugins/tree/types.d.ts.map +1 -1
  105. package/lib/plugins/undo-redo/UndoRedoPlugin.d.ts +0 -1
  106. package/lib/plugins/undo-redo/UndoRedoPlugin.d.ts.map +1 -1
  107. package/lib/plugins/undo-redo/index.js +93 -17
  108. package/lib/plugins/undo-redo/index.js.map +1 -1
  109. package/lib/plugins/visibility/VisibilityPlugin.d.ts +7 -4
  110. package/lib/plugins/visibility/VisibilityPlugin.d.ts.map +1 -1
  111. package/lib/plugins/visibility/index.js +144 -65
  112. package/lib/plugins/visibility/index.js.map +1 -1
  113. package/package.json +1 -1
  114. package/umd/grid.all.umd.js +17 -19
  115. package/umd/grid.all.umd.js.map +1 -1
  116. package/umd/grid.umd.js +7 -7
  117. package/umd/grid.umd.js.map +1 -1
  118. package/umd/plugins/clipboard.umd.js +5 -7
  119. package/umd/plugins/clipboard.umd.js.map +1 -1
  120. package/umd/plugins/column-virtualization.umd.js +1 -1
  121. package/umd/plugins/column-virtualization.umd.js.map +1 -1
  122. package/umd/plugins/context-menu.umd.js +1 -1
  123. package/umd/plugins/context-menu.umd.js.map +1 -1
  124. package/umd/plugins/editing.umd.js +1 -1
  125. package/umd/plugins/editing.umd.js.map +1 -1
  126. package/umd/plugins/export.umd.js +1 -1
  127. package/umd/plugins/export.umd.js.map +1 -1
  128. package/umd/plugins/filtering.umd.js +1 -1
  129. package/umd/plugins/filtering.umd.js.map +1 -1
  130. package/umd/plugins/grouping-columns.umd.js +1 -1
  131. package/umd/plugins/grouping-columns.umd.js.map +1 -1
  132. package/umd/plugins/grouping-rows.umd.js +1 -1
  133. package/umd/plugins/grouping-rows.umd.js.map +1 -1
  134. package/umd/plugins/master-detail.umd.js +1 -1
  135. package/umd/plugins/master-detail.umd.js.map +1 -1
  136. package/umd/plugins/multi-sort.umd.js +1 -1
  137. package/umd/plugins/multi-sort.umd.js.map +1 -1
  138. package/umd/plugins/pinned-columns.umd.js +1 -1
  139. package/umd/plugins/pinned-columns.umd.js.map +1 -1
  140. package/umd/plugins/pinned-rows.umd.js +1 -1
  141. package/umd/plugins/pinned-rows.umd.js.map +1 -1
  142. package/umd/plugins/pivot.umd.js +1 -1
  143. package/umd/plugins/pivot.umd.js.map +1 -1
  144. package/umd/plugins/reorder.umd.js +1 -1
  145. package/umd/plugins/reorder.umd.js.map +1 -1
  146. package/umd/plugins/selection.umd.js +1 -1
  147. package/umd/plugins/selection.umd.js.map +1 -1
  148. package/umd/plugins/server-side.umd.js +1 -1
  149. package/umd/plugins/server-side.umd.js.map +1 -1
  150. package/umd/plugins/tree.umd.js +1 -1
  151. package/umd/plugins/tree.umd.js.map +1 -1
  152. package/umd/plugins/undo-redo.umd.js +1 -1
  153. package/umd/plugins/undo-redo.umd.js.map +1 -1
  154. package/umd/plugins/visibility.umd.js +1 -1
  155. package/umd/plugins/visibility.umd.js.map +1 -1
  156. package/lib/core/internal/editing.d.ts +0 -76
  157. package/lib/core/internal/editing.d.ts.map +0 -1
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
- const te = ':root{color-scheme:light dark}:host{--tbw-color-bg: transparent;--tbw-color-panel-bg: light-dark(#eeeeee, #222222);--tbw-color-fg: light-dark(#222222, #eeeeee);--tbw-color-fg-muted: light-dark(#555555, #aaaaaa);--tbw-color-accent: light-dark(#3b82f6, #3b82f6);--tbw-color-accent-fg: light-dark(#ffffff, #000000);--tbw-color-success: light-dark(hsl(122, 39%, 40%), hsl(122, 39%, 49%));--tbw-color-selection: light-dark(#fff7d6, #333333);--tbw-color-row-alt: var(--tbw-color-bg);--tbw-color-row-hover: light-dark(#f0f6ff, #1c1c1c);--tbw-color-header-bg: color-mix(in hsl, var(--tbw-color-panel-bg) 85%, var(--tbw-color-fg));--tbw-color-header-fg: color-mix(in hsl, var(--tbw-color-fg) 75%, var(--tbw-color-panel-bg));--tbw-color-border: light-dark(#d0d0d4, #454545);--tbw-color-border-strong: light-dark(#777777, #adacac);--tbw-color-border-cell: var(--tbw-color-border);--tbw-color-border-header: var(--tbw-color-border);--tbw-color-shadow: light-dark(rgba(0, 0, 0, .1), rgba(0, 0, 0, .3));--tbw-font-family: inherit;--tbw-font-size: inherit;--tbw-font-size-header: var(--tbw-font-size);--tbw-font-weight-header: bold;--tbw-cell-padding-header: 2px 8px;--tbw-cell-padding: 2px 8px;--tbw-cell-padding-input: 2px 6px;--tbw-row-height: 28px;--tbw-header-height: 30px;--tbw-cell-white-space: nowrap;--tbw-border-radius: 4px;--tbw-border-input: 1px solid var(--tbw-color-border-strong);--tbw-border-header: 1px solid var(--tbw-color-border-header);--tbw-row-divider: 1px solid var(--tbw-color-border-cell);--tbw-row-hover-outline: 0;--tbw-color-active-row-bg: var(--tbw-color-selection);--tbw-active-row-outline: 0;--tbw-focus-outline: 2px solid var(--tbw-color-accent);--tbw-focus-outline-offset: -2px;--tbw-focus-background: rgba(from var(--tbw-color-accent) r g b / 12%);--tbw-range-border-color: var(--tbw-color-accent);--tbw-range-selection-bg: rgba(from var(--tbw-range-border-color) r g b / 12%);--tbw-resize-handle-width: 6px;--tbw-resize-handle-color: transparent;--tbw-resize-handle-color-hover: var(--tbw-color-accent);--tbw-resize-handle-border-radius: 0;--tbw-scrollbar-thumb: var(--tbw-color-border-strong);--tbw-scrollbar-track: var(--tbw-color-bg);--tbw-transition-duration: .12s;--tbw-transition-ease: ease;--tbw-animation-duration: .2s;--tbw-animation-easing: ease-out;--tbw-animation-enabled: 1;--tbw-editing-bg: var(--tbw-color-selection);--tbw-editing-border: var(--tbw-border-input, 1px solid var(--tbw-color-border-strong));--tbw-padding-editing-input: var(--tbw-cell-padding-input, 2px 6px);--tbw-font-size-editor: inherit;--tbw-editing-row-bg: var(--tbw-editing-bg);--tbw-editing-row-outline-color: var(--tbw-color-accent);--tbw-editing-row-outline-width: 1px;--tbw-sort-indicator-color: var(--tbw-color-fg-muted);--tbw-sort-indicator-active-color: var(--tbw-color-accent);--tbw-header-text-transform: none;--tbw-header-letter-spacing: normal;--tbw-color-header-separator: var(--tbw-color-border-cell);--tbw-checkbox-size: 16px;--tbw-density-scale: 1}:host{position:relative;display:block;width:100%;height:100%;min-height:0;contain:content;font-family:var(--tbw-font-family);font-size:var(--tbw-font-size);background:var(--tbw-color-bg);color:var(--tbw-color-fg);border:1px solid var(--tbw-color-border);border-radius:var(--tbw-border-radius);overflow:clip;outline:none}:host,:host *{box-sizing:border-box}:host .header{display:block;flex-shrink:0;z-index:var(--tbw-z-layer-header, 30);background:var(--tbw-color-header-bg);overflow:visible}:host .header-group-row{display:grid;grid-template-columns:var(--tbw-column-template);background:var(--tbw-color-header-bg);z-index:var(--tbw-z-layer-header, 30)}:host .header-group-cell{display:flex;align-items:center;justify-content:flex-start;padding:var(--tbw-cell-padding-header, 2px 8px);color:var(--tbw-color-header-group-fg, var(--tbw-color-header-fg));font-weight:var(--tbw-font-weight-header-group, var(--tbw-font-weight-header));justify-content:var(--tbw-align-header-group, var(--tbw-align-header, flex-start))}:host .header-row{display:grid;grid-template-columns:var(--tbw-column-template);color:var(--tbw-color-header-fg);font-size:var(--tbw-font-size-header);min-height:var(--tbw-header-height);border-bottom:var(--tbw-border-header);z-index:var(--tbw-z-layer-header, 30)}:host .header-row>.cell{display:flex;align-items:center;gap:4px;padding:var(--tbw-cell-padding-header, 2px 8px);background-color:var(--tbw-color-header-bg);font-weight:var(--tbw-font-weight-header);border-right:1px solid var(--tbw-color-border-cell);overflow:hidden;min-width:0}:host .header-row>.cell>span:first-child{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host .header-row>.cell>span[part~=sort-indicator]{flex-shrink:0;opacity:.6}:host .header-row>.cell:last-child{border-right:0}:host .header-group-cell:not(:last-child),:host .header-row>.cell.grouped.group-end:not(:last-child){border-right:2px solid var(--tbw-color-border)}:host .tbw-grid-root{display:flex;flex-direction:column;height:100%}:host .rows-body-wrapper{flex:1;min-height:0;display:flex;flex-direction:row;width:100%;min-width:fit-content}:host .rows-body{flex:1;min-width:0;min-height:0;display:flex;flex-direction:column;overflow:visible}:host .rows-container{display:flex;flex-direction:row;flex:1;min-height:0;overflow:visible}:host .rows-viewport{flex:1;min-width:0;position:relative;display:block;overflow:clip}:host .faux-vscroll{position:sticky;inset-inline-end:0;flex-shrink:0;width:auto;overflow-y:auto;overflow-x:hidden;z-index:var(--tbw-z-layer-header, 30)}:host .faux-vscroll-spacer{width:1px}:host .rows-viewport .rows{position:absolute;top:0;left:0;min-width:100%;will-change:transform;z-index:var(--tbw-z-layer-rows, 1)}:host .data-grid-row{display:grid;grid-template-columns:var(--tbw-column-template);contain:layout style;content-visibility:auto;contain-intrinsic-size:auto var(--tbw-row-height)}:host .data-grid-row:has(.editing){background:var(--tbw-editing-row-bg);outline:var(--tbw-editing-row-outline-width) solid var(--tbw-editing-row-outline-color);outline-offset:calc(-1 * var(--tbw-editing-row-outline-width))}:host .selecting .data-grid-row>.cell{user-select:none}:host .data-grid-row>.cell.selected:focus-visible,:host .data-grid-row>.cell:focus-visible:not(.cell-focus){outline:none}:host .data-grid-row>.cell{display:block;padding:var(--tbw-cell-padding, 2px 8px);border-bottom:var(--tbw-row-divider);min-height:var(--tbw-row-height);line-height:calc(var(--tbw-row-height) - 5px);border-right:1px solid var(--tbw-color-border-cell);overflow:hidden;min-width:0;white-space:var(--tbw-cell-white-space, nowrap);text-overflow:ellipsis}:host .data-grid-row>.cell>*{overflow:hidden;text-overflow:ellipsis;white-space:inherit;min-width:0}:host .data-grid-row>.cell:last-child{border-right:0}:host .data-grid-row>.cell[data-type=boolean]{text-align:center}:host .data-grid-row>.cell[data-type=boolean] input[type=checkbox]{margin:0;width:var(--tbw-checkbox-size);height:var(--tbw-checkbox-size);vertical-align:middle}:host .data-grid-row>.cell.editing{overflow:hidden;padding:0;display:flex;min-height:calc(var(--tbw-row-height) + 2px)}:host .data-grid-row>.cell.editing input:not([type=checkbox]),:host .data-grid-row>.cell.editing select,:host .data-grid-row>.cell.editing textarea{width:100%;height:100%;flex:1 1 auto;min-width:0;border:var(--tbw-editing-border);padding:var(--tbw-padding-editing-input);font-size:var(--tbw-font-size-editor)}:host .data-grid-row:nth-child(2n){background:var(--tbw-color-row-alt)}:host .data-grid-row:hover{background:var(--tbw-color-row-hover)}:host .sortable{cursor:pointer;user-select:none}:host .header-row>.cell.resizable{position:relative}:host .tbw-editor-host{display:contents}:host .resize-handle{position:absolute;top:0;right:calc(var(--tbw-resize-handle-width) / -2);width:var(--tbw-resize-handle-width);height:100%;cursor:e-resize;user-select:none;touch-action:none;z-index:20;background:var(--tbw-resize-handle-color);transition:background .12s ease;border-radius:var(--tbw-resize-handle-border-radius)}:host .resize-handle:hover{background:var(--tbw-resize-handle-color-hover)}:host .cell-focus,:host .row-focus{outline:var(--tbw-focus-outline);outline-offset:var(--tbw-focus-outline-offset)}:host .sticky-left,:host .sticky-right{position:sticky;z-index:25}:host .header-row>.cell.sticky-left,:host .header-row>.cell.sticky-right{background:var(--tbw-color-header-bg);z-index:35}:host .data-grid-row>.cell.sticky-left,:host .data-grid-row>.cell.sticky-right{background:var(--tbw-color-panel-bg)}:host .sticky-left{box-shadow:1px 0 0 var(--tbw-color-border)}:host .sticky-right{box-shadow:-1px 0 0 var(--tbw-color-border)}:host{--tbw-shell-header-height: 44px;--tbw-shell-header-bg: var(--tbw-color-panel-bg);--tbw-shell-header-border: var(--tbw-color-border);--tbw-shell-title-font-size: 14px;--tbw-shell-title-font-weight: 600;--tbw-tool-panel-width: 280px;--tbw-tool-panel-bg: var(--tbw-color-panel-bg);--tbw-tool-panel-border: var(--tbw-color-border);--tbw-tool-panel-header-height: 40px;--tbw-tool-panel-transition: var(--tbw-animation-duration) var(--tbw-animation-easing);--tbw-toolbar-button-size: 32px;--tbw-toolbar-button-gap: 4px}:host .tbw-grid-root.has-shell{display:flex;flex-direction:column;height:100%}:host .tbw-shell-header{display:flex;align-items:center;gap:8px;min-height:var(--tbw-shell-header-height);padding:0 8px;background:var(--tbw-shell-header-bg);border-bottom:1px solid var(--tbw-shell-header-border);flex-shrink:0}:host .tbw-shell-title{font-size:var(--tbw-shell-title-font-size);font-weight:var(--tbw-shell-title-font-weight);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}:host .tbw-shell-content{flex:1;display:flex;align-items:center;gap:12px;min-width:0;overflow:hidden}:host .tbw-shell-toolbar{display:flex;align-items:center;gap:var(--tbw-toolbar-button-gap);flex-shrink:0}:host .tbw-toolbar-btn{display:inline-flex;align-items:center;justify-content:center;width:var(--tbw-toolbar-button-size);height:var(--tbw-toolbar-button-size);padding:0;border:1px solid transparent;border-radius:var(--tbw-border-radius);background:transparent;color:var(--tbw-color-fg);cursor:pointer;font-size:16px;transition:background var(--tbw-transition-duration) var(--tbw-transition-ease),border-color var(--tbw-transition-duration) var(--tbw-transition-ease)}:host .tbw-toolbar-btn:hover{background:var(--tbw-color-row-hover)}:host .tbw-toolbar-btn:focus-visible{outline:var(--tbw-focus-outline);outline-offset:var(--tbw-focus-outline-offset)}:host .tbw-toolbar-btn.active{background:var(--tbw-focus-background);border-color:var(--tbw-color-accent)}:host .tbw-toolbar-btn:disabled{opacity:.5;cursor:not-allowed}:host .tbw-toolbar-separator{width:1px;height:20px;background:var(--tbw-color-border);margin:0 4px}:host .tbw-shell-body{position:relative;display:flex;flex:1;min-height:0;overflow:visible}:host .tbw-grid-content{flex:1;min-width:0;min-height:0;display:flex;flex-direction:row;overflow:hidden}:host .tbw-scroll-area{flex:1;min-width:0;min-height:0;display:flex;flex-direction:column;overflow-x:auto;overflow-y:hidden;overflow-anchor:none}:host .tbw-tool-panel{position:absolute;top:0;bottom:0;right:0;width:0;overflow:hidden;background:var(--tbw-tool-panel-bg);border-left:1px solid var(--tbw-tool-panel-border);transition:width var(--tbw-tool-panel-transition);display:flex;flex-direction:column;z-index:30;box-shadow:-2px 0 8px var(--tbw-color-shadow)}:host .tbw-tool-panel[data-position=left]{right:auto;left:0;border-left:none;border-right:1px solid var(--tbw-tool-panel-border);box-shadow:2px 0 8px var(--tbw-color-shadow)}:host .tbw-tool-panel.open{width:var(--tbw-tool-panel-width)}:host .tbw-tool-panel-resize{position:absolute;top:0;bottom:0;width:6px;cursor:col-resize;background:transparent;z-index:10;transition:background var(--tbw-transition-duration) var(--tbw-transition-ease)}:host .tbw-tool-panel-resize[data-handle-position=left]{left:0}:host .tbw-tool-panel-resize[data-handle-position=right]{right:0}:host .tbw-tool-panel-resize:hover,:host .tbw-tool-panel-resize.resizing{background:var(--tbw-color-accent)}:host .tbw-tool-panel-header{display:flex;align-items:center;justify-content:space-between;min-height:var(--tbw-tool-panel-header-height);padding:0 12px;border-bottom:1px solid var(--tbw-tool-panel-border);flex-shrink:0}:host .tbw-tool-panel-title{font-weight:600;font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}:host .tbw-tool-panel-close{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:none;border-radius:var(--tbw-border-radius);background:transparent;color:var(--tbw-color-fg-muted);cursor:pointer;font-size:14px}:host .tbw-tool-panel-close:hover{background:var(--tbw-color-row-hover);color:var(--tbw-color-fg)}:host .tbw-tool-panel-content{flex:1;overflow:auto}:host .tbw-accordion{display:flex;flex-direction:column;gap:0}:host .tbw-accordion-section{border-bottom:1px solid var(--tbw-tool-panel-border)}:host .tbw-accordion-section:last-child{border-bottom:none}:host .tbw-accordion-header{display:flex;align-items:center;gap:8px;width:100%;padding:10px 12px;border:none;background:transparent;color:var(--tbw-color-fg);font-size:13px;font-weight:600;text-align:left;cursor:pointer;user-select:none}:host .tbw-accordion-header:hover{background:var(--tbw-color-row-hover)}:host .tbw-accordion-section.single .tbw-accordion-header{cursor:default}:host .tbw-accordion-section.single .tbw-accordion-header:hover{background:transparent}:host .tbw-accordion-chevron{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;font-size:10px;color:var(--tbw-color-fg-muted);transition:transform .15s ease;flex-shrink:0}:host .tbw-accordion-section.expanded .tbw-accordion-chevron{transform:rotate(90deg)}:host .tbw-accordion-icon{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;font-size:14px;flex-shrink:0}:host .tbw-accordion-title{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host .tbw-accordion-content{display:none}:host .tbw-accordion-section.expanded .tbw-accordion-content{display:block}@media(forced-colors:active){:host{--tbw-color-border: CanvasText;--tbw-color-border-strong: CanvasText;--tbw-color-border-cell: CanvasText;--tbw-color-border-header: CanvasText;--tbw-color-fg: CanvasText;--tbw-color-bg: Canvas;--tbw-color-panel-bg: Canvas;--tbw-color-header-bg: Canvas;--tbw-color-header-fg: CanvasText;--tbw-color-accent: Highlight;--tbw-color-accent-fg: HighlightText;--tbw-color-selection: Highlight;--tbw-color-row-hover: Highlight;--tbw-focus-outline: 2px solid Highlight;--tbw-range-border-color: Highlight}:host .cell:focus,:host .cell.active-cell{outline:2px solid Highlight!important;outline-offset:-2px}:host .data-grid-row[aria-selected=true]{background:Highlight!important;color:HighlightText!important}}@media(prefers-reduced-motion:reduce){:host([data-animation-mode="reduced-motion"]){--tbw-animation-enabled: 0;--tbw-animation-duration: 0ms}}:host([data-animation-mode="off"]){--tbw-animation-enabled: 0;--tbw-animation-duration: 0ms}:host .tbw-expanding{animation:tbw-expand var(--tbw-animation-duration) var(--tbw-animation-easing) forwards;overflow:hidden}:host .tbw-collapsing{animation:tbw-collapse var(--tbw-animation-duration) var(--tbw-animation-easing) forwards;overflow:hidden}@keyframes tbw-expand{0%{opacity:0;max-height:0;transform:translateY(-8px)}to{opacity:1;max-height:500px;transform:translateY(0)}}@keyframes tbw-collapse{0%{opacity:1;max-height:500px;transform:translateY(0)}to{opacity:0;max-height:0;transform:translateY(-8px)}}', W = {
1
+ const te = ':root{color-scheme:light dark}:host{--tbw-color-bg: transparent;--tbw-color-panel-bg: light-dark(#eeeeee, #222222);--tbw-color-fg: light-dark(#222222, #eeeeee);--tbw-color-fg-muted: light-dark(#555555, #aaaaaa);--tbw-color-accent: light-dark(#3b82f6, #3b82f6);--tbw-color-accent-fg: light-dark(#ffffff, #000000);--tbw-color-success: light-dark(hsl(122, 39%, 40%), hsl(122, 39%, 49%));--tbw-color-selection: light-dark(#fff7d6, #333333);--tbw-color-row-alt: var(--tbw-color-bg);--tbw-color-row-hover: light-dark(#f0f6ff, #1c1c1c);--tbw-color-header-bg: color-mix(in hsl, var(--tbw-color-panel-bg) 85%, var(--tbw-color-fg));--tbw-color-header-fg: color-mix(in hsl, var(--tbw-color-fg) 75%, var(--tbw-color-panel-bg));--tbw-color-border: light-dark(#d0d0d4, #454545);--tbw-color-border-strong: light-dark(#777777, #adacac);--tbw-color-border-cell: var(--tbw-color-border);--tbw-color-border-header: var(--tbw-color-border);--tbw-color-shadow: light-dark(rgba(0, 0, 0, .1), rgba(0, 0, 0, .3));--tbw-font-family: inherit;--tbw-font-size: inherit;--tbw-font-size-header: var(--tbw-font-size);--tbw-font-weight-header: bold;--tbw-cell-padding-header: 2px 8px;--tbw-cell-padding: 2px 8px;--tbw-cell-padding-input: 2px 6px;--tbw-row-height: 28px;--tbw-header-height: 30px;--tbw-cell-white-space: nowrap;--tbw-border-radius: 4px;--tbw-border-input: 1px solid var(--tbw-color-border-strong);--tbw-border-header: 1px solid var(--tbw-color-border-header);--tbw-row-divider: 1px solid var(--tbw-color-border-cell);--tbw-row-hover-outline: 0;--tbw-color-active-row-bg: var(--tbw-color-selection);--tbw-active-row-outline: 0;--tbw-focus-outline: 2px solid var(--tbw-color-accent);--tbw-focus-outline-offset: -2px;--tbw-focus-background: rgba(from var(--tbw-color-accent) r g b / 12%);--tbw-range-border-color: var(--tbw-color-accent);--tbw-range-selection-bg: rgba(from var(--tbw-range-border-color) r g b / 12%);--tbw-resize-handle-width: 6px;--tbw-resize-handle-color: transparent;--tbw-resize-handle-color-hover: var(--tbw-color-accent);--tbw-resize-handle-border-radius: 0;--tbw-scrollbar-thumb: var(--tbw-color-border-strong);--tbw-scrollbar-track: var(--tbw-color-bg);--tbw-transition-duration: .12s;--tbw-transition-ease: ease;--tbw-animation-duration: .2s;--tbw-animation-easing: ease-out;--tbw-animation-enabled: 1;--tbw-editing-bg: var(--tbw-color-selection);--tbw-editing-border: var(--tbw-border-input, 1px solid var(--tbw-color-border-strong));--tbw-padding-editing-input: var(--tbw-cell-padding-input, 2px 6px);--tbw-font-size-editor: inherit;--tbw-editing-row-bg: var(--tbw-editing-bg);--tbw-editing-row-outline-color: var(--tbw-color-accent);--tbw-editing-row-outline-width: 1px;--tbw-sort-indicator-color: var(--tbw-color-fg-muted);--tbw-sort-indicator-active-color: var(--tbw-color-accent);--tbw-header-text-transform: none;--tbw-header-letter-spacing: normal;--tbw-color-header-separator: var(--tbw-color-border-cell);--tbw-checkbox-size: 16px;--tbw-density-scale: 1}:host{position:relative;display:block;width:100%;height:100%;min-height:0;contain:content;font-family:var(--tbw-font-family);font-size:var(--tbw-font-size);background:var(--tbw-color-bg);color:var(--tbw-color-fg);border:1px solid var(--tbw-color-border);border-radius:var(--tbw-border-radius);overflow:clip;outline:none}:host,:host *{box-sizing:border-box}:host .header{display:block;flex-shrink:0;z-index:var(--tbw-z-layer-header, 30);background:var(--tbw-color-header-bg);overflow:visible}:host .header-group-row{display:grid;grid-template-columns:var(--tbw-column-template);background:var(--tbw-color-header-bg);z-index:var(--tbw-z-layer-header, 30)}:host .header-group-cell{display:flex;align-items:center;justify-content:flex-start;padding:var(--tbw-cell-padding-header, 2px 8px);color:var(--tbw-color-header-group-fg, var(--tbw-color-header-fg));font-weight:var(--tbw-font-weight-header-group, var(--tbw-font-weight-header));justify-content:var(--tbw-align-header-group, var(--tbw-align-header, flex-start))}:host .header-row{display:grid;grid-template-columns:var(--tbw-column-template);color:var(--tbw-color-header-fg);font-size:var(--tbw-font-size-header);min-height:var(--tbw-header-height);border-bottom:var(--tbw-border-header);z-index:var(--tbw-z-layer-header, 30)}:host .header-row>.cell{display:flex;align-items:center;gap:4px;padding:var(--tbw-cell-padding-header, 2px 8px);background-color:var(--tbw-color-header-bg);font-weight:var(--tbw-font-weight-header);border-right:1px solid var(--tbw-color-border-cell);overflow:hidden;min-width:0}:host .header-row>.cell>span:first-child{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host .header-row>.cell>span[part~=sort-indicator]{flex-shrink:0;opacity:.6}:host .header-row>.cell:last-child{border-right:0}:host .header-group-cell:not(:last-child),:host .header-row>.cell.grouped.group-end:not(:last-child){border-right:2px solid var(--tbw-color-border)}:host .tbw-grid-root{display:flex;flex-direction:column;height:100%}:host .rows-body-wrapper{flex:1;min-height:0;display:flex;flex-direction:row;width:100%;min-width:fit-content}:host .rows-body{flex:1;min-width:0;min-height:0;display:flex;flex-direction:column;overflow:visible}:host .rows-container{display:flex;flex-direction:row;flex:1;min-height:0;overflow:visible}:host .rows-viewport{flex:1;min-width:0;position:relative;display:block;overflow:clip}:host .faux-vscroll{position:sticky;inset-inline-end:0;flex-shrink:0;width:auto;overflow-y:auto;overflow-x:hidden;z-index:var(--tbw-z-layer-header, 30)}:host .faux-vscroll-spacer{width:1px}:host .rows-viewport .rows{position:absolute;top:0;left:0;min-width:100%;will-change:transform;z-index:var(--tbw-z-layer-rows, 1)}:host .data-grid-row{display:grid;grid-template-columns:var(--tbw-column-template);contain:layout style;content-visibility:auto;contain-intrinsic-size:auto var(--tbw-row-height)}:host .data-grid-row:has(.editing){background:var(--tbw-editing-row-bg);outline:var(--tbw-editing-row-outline-width) solid var(--tbw-editing-row-outline-color);outline-offset:calc(-1 * var(--tbw-editing-row-outline-width))}:host .selecting .data-grid-row>.cell{user-select:none}:host .data-grid-row>.cell.selected:focus-visible,:host .data-grid-row>.cell:focus-visible:not(.cell-focus){outline:none}:host .data-grid-row>.cell{display:block;padding:var(--tbw-cell-padding, 2px 8px);border-bottom:var(--tbw-row-divider);min-height:var(--tbw-row-height);line-height:calc(var(--tbw-row-height) - 5px);border-right:1px solid var(--tbw-color-border-cell);overflow:hidden;min-width:0;white-space:var(--tbw-cell-white-space, nowrap);text-overflow:ellipsis}:host .data-grid-row>.cell>*{overflow:hidden;text-overflow:ellipsis;white-space:inherit;min-width:0}:host .data-grid-row>.cell:last-child{border-right:0}:host .data-grid-row>.cell[data-type=boolean]{text-align:center}:host .data-grid-row>.cell[data-type=boolean] input[type=checkbox]{margin:0;width:var(--tbw-checkbox-size);height:var(--tbw-checkbox-size);vertical-align:middle}:host .data-grid-row>.cell.editing{overflow:hidden;padding:0;display:flex;min-height:calc(var(--tbw-row-height) + 2px)}:host .data-grid-row>.cell.editing input:not([type=checkbox]),:host .data-grid-row>.cell.editing select,:host .data-grid-row>.cell.editing textarea{width:100%;height:100%;flex:1 1 auto;min-width:0;border:var(--tbw-editing-border);padding:var(--tbw-padding-editing-input);font-size:var(--tbw-font-size-editor)}:host .data-grid-row:nth-child(2n){background:var(--tbw-color-row-alt)}:host .data-grid-row:hover{background:var(--tbw-color-row-hover)}:host .sortable{cursor:pointer;user-select:none}:host .header-row>.cell.resizable{position:relative}:host .tbw-editor-host{display:contents}:host .resize-handle{position:absolute;top:0;right:calc(var(--tbw-resize-handle-width) / -2);width:var(--tbw-resize-handle-width);height:100%;cursor:e-resize;user-select:none;touch-action:none;z-index:20;background:var(--tbw-resize-handle-color);transition:background .12s ease;border-radius:var(--tbw-resize-handle-border-radius)}:host .resize-handle:hover{background:var(--tbw-resize-handle-color-hover)}:host([data-has-focus]) .cell-focus,:host([data-has-focus]) .row-focus{outline:var(--tbw-focus-outline);outline-offset:var(--tbw-focus-outline-offset)}:host .sticky-left,:host .sticky-right{position:sticky;z-index:25}:host .header-row>.cell.sticky-left,:host .header-row>.cell.sticky-right{background:var(--tbw-color-header-bg);z-index:35}:host .data-grid-row>.cell.sticky-left,:host .data-grid-row>.cell.sticky-right{background:var(--tbw-color-panel-bg)}:host .sticky-left{box-shadow:1px 0 0 var(--tbw-color-border)}:host .sticky-right{box-shadow:-1px 0 0 var(--tbw-color-border)}:host{--tbw-shell-header-height: 44px;--tbw-shell-header-bg: var(--tbw-color-panel-bg);--tbw-shell-header-border: var(--tbw-color-border);--tbw-shell-title-font-size: 14px;--tbw-shell-title-font-weight: 600;--tbw-tool-panel-width: 280px;--tbw-tool-panel-bg: var(--tbw-color-panel-bg);--tbw-tool-panel-border: var(--tbw-color-border);--tbw-tool-panel-header-height: 40px;--tbw-tool-panel-transition: var(--tbw-animation-duration) var(--tbw-animation-easing);--tbw-toolbar-button-size: 32px;--tbw-toolbar-button-gap: 4px}:host .tbw-grid-root.has-shell{display:flex;flex-direction:column;height:100%}:host .tbw-shell-header{display:flex;align-items:center;gap:8px;min-height:var(--tbw-shell-header-height);padding:0 8px;background:var(--tbw-shell-header-bg);border-bottom:1px solid var(--tbw-shell-header-border);flex-shrink:0}:host .tbw-shell-title{font-size:var(--tbw-shell-title-font-size);font-weight:var(--tbw-shell-title-font-weight);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}:host .tbw-shell-content{flex:1;display:flex;align-items:center;gap:12px;min-width:0;overflow:hidden}:host .tbw-shell-toolbar{display:flex;align-items:center;gap:var(--tbw-toolbar-button-gap);flex-shrink:0}:host .tbw-toolbar-btn{display:inline-flex;align-items:center;justify-content:center;width:var(--tbw-toolbar-button-size);height:var(--tbw-toolbar-button-size);padding:0;border:1px solid transparent;border-radius:var(--tbw-border-radius);background:transparent;color:var(--tbw-color-fg);cursor:pointer;font-size:16px;transition:background var(--tbw-transition-duration) var(--tbw-transition-ease),border-color var(--tbw-transition-duration) var(--tbw-transition-ease)}:host .tbw-toolbar-btn:hover{background:var(--tbw-color-row-hover)}:host .tbw-toolbar-btn:focus-visible{outline:var(--tbw-focus-outline);outline-offset:var(--tbw-focus-outline-offset)}:host .tbw-toolbar-btn.active{background:var(--tbw-focus-background);border-color:var(--tbw-color-accent)}:host .tbw-toolbar-btn:disabled{opacity:.5;cursor:not-allowed}:host .tbw-toolbar-separator{width:1px;height:20px;background:var(--tbw-color-border);margin:0 4px}:host .tbw-shell-body{position:relative;display:flex;flex:1;min-height:0;overflow:visible}:host .tbw-grid-content{flex:1;min-width:0;min-height:0;display:flex;flex-direction:row;overflow:hidden}:host .tbw-scroll-area{flex:1;min-width:0;min-height:0;display:flex;flex-direction:column;overflow-x:auto;overflow-y:hidden;overflow-anchor:none}:host .tbw-tool-panel{position:absolute;top:0;bottom:0;right:0;width:0;overflow:hidden;background:var(--tbw-tool-panel-bg);border-left:1px solid var(--tbw-tool-panel-border);transition:width var(--tbw-tool-panel-transition);display:flex;flex-direction:column;z-index:30;box-shadow:-2px 0 8px var(--tbw-color-shadow)}:host .tbw-tool-panel[data-position=left]{right:auto;left:0;border-left:none;border-right:1px solid var(--tbw-tool-panel-border);box-shadow:2px 0 8px var(--tbw-color-shadow)}:host .tbw-tool-panel.open{width:var(--tbw-tool-panel-width)}:host .tbw-tool-panel-resize{position:absolute;top:0;bottom:0;width:6px;cursor:col-resize;background:transparent;z-index:10;transition:background var(--tbw-transition-duration) var(--tbw-transition-ease)}:host .tbw-tool-panel-resize[data-handle-position=left]{left:0}:host .tbw-tool-panel-resize[data-handle-position=right]{right:0}:host .tbw-tool-panel-resize:hover,:host .tbw-tool-panel-resize.resizing{background:var(--tbw-color-accent)}:host .tbw-tool-panel-header{display:flex;align-items:center;justify-content:space-between;min-height:var(--tbw-tool-panel-header-height);padding:0 12px;border-bottom:1px solid var(--tbw-tool-panel-border);flex-shrink:0}:host .tbw-tool-panel-title{font-weight:600;font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}:host .tbw-tool-panel-close{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:none;border-radius:var(--tbw-border-radius);background:transparent;color:var(--tbw-color-fg-muted);cursor:pointer;font-size:14px}:host .tbw-tool-panel-close:hover{background:var(--tbw-color-row-hover);color:var(--tbw-color-fg)}:host .tbw-tool-panel-content{flex:1;overflow:auto}:host .tbw-accordion{display:flex;flex-direction:column;gap:0}:host .tbw-accordion-section{border-bottom:1px solid var(--tbw-tool-panel-border)}:host .tbw-accordion-section:last-child{border-bottom:none}:host .tbw-accordion-header{display:flex;align-items:center;gap:8px;width:100%;padding:10px 12px;border:none;background:transparent;color:var(--tbw-color-fg);font-size:13px;font-weight:600;text-align:left;cursor:pointer;user-select:none}:host .tbw-accordion-header:hover{background:var(--tbw-color-row-hover)}:host .tbw-accordion-section.single .tbw-accordion-header{cursor:default}:host .tbw-accordion-section.single .tbw-accordion-header:hover{background:transparent}:host .tbw-accordion-chevron{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;font-size:10px;color:var(--tbw-color-fg-muted);transition:transform .15s ease;flex-shrink:0}:host .tbw-accordion-section.expanded .tbw-accordion-chevron{transform:rotate(90deg)}:host .tbw-accordion-icon{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;font-size:14px;flex-shrink:0}:host .tbw-accordion-title{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host .tbw-accordion-content{display:none}:host .tbw-accordion-section.expanded .tbw-accordion-content{display:block}@media(forced-colors:active){:host{--tbw-color-border: CanvasText;--tbw-color-border-strong: CanvasText;--tbw-color-border-cell: CanvasText;--tbw-color-border-header: CanvasText;--tbw-color-fg: CanvasText;--tbw-color-bg: Canvas;--tbw-color-panel-bg: Canvas;--tbw-color-header-bg: Canvas;--tbw-color-header-fg: CanvasText;--tbw-color-accent: Highlight;--tbw-color-accent-fg: HighlightText;--tbw-color-selection: Highlight;--tbw-color-row-hover: Highlight;--tbw-focus-outline: 2px solid Highlight;--tbw-range-border-color: Highlight}:host .cell:focus,:host .cell.active-cell{outline:2px solid Highlight!important;outline-offset:-2px}:host .data-grid-row[aria-selected=true]{background:Highlight!important;color:HighlightText!important}}@media(prefers-reduced-motion:reduce){:host([data-animation-mode="reduced-motion"]){--tbw-animation-enabled: 0;--tbw-animation-duration: 0ms}}:host([data-animation-mode="off"]){--tbw-animation-enabled: 0;--tbw-animation-duration: 0ms}:host .tbw-expanding{animation:tbw-expand var(--tbw-animation-duration) var(--tbw-animation-easing) forwards;overflow:hidden}:host .tbw-collapsing{animation:tbw-collapse var(--tbw-animation-duration) var(--tbw-animation-easing) forwards;overflow:hidden}@keyframes tbw-expand{0%{opacity:0;max-height:0;transform:translateY(-8px)}to{opacity:1;max-height:500px;transform:translateY(0)}}@keyframes tbw-collapse{0%{opacity:1;max-height:500px;transform:translateY(0)}to{opacity:0;max-height:0;transform:translateY(-8px)}}', W = {
2
2
  STRETCH: "stretch",
3
3
  FIXED: "fixed"
4
4
  }, Me = {
@@ -39,9 +39,9 @@ function ze(t) {
39
39
  }));
40
40
  const m = o.querySelector("tbw-grid-column-view"), b = o.querySelector("tbw-grid-column-editor"), _ = o.querySelector("tbw-grid-column-header");
41
41
  m && (h.__viewTemplate = m), b && (h.__editorTemplate = b), _ && (h.__headerTemplate = _);
42
- const C = globalThis.DataGridElement?.getAdapters?.() ?? [], y = m ?? o, S = C.find((v) => v.canHandle(y));
43
- if (S) {
44
- const v = S.createRenderer(y);
42
+ const C = globalThis.DataGridElement?.getAdapters?.() ?? [], y = m ?? o, R = C.find((v) => v.canHandle(y));
43
+ if (R) {
44
+ const v = R.createRenderer(y);
45
45
  v && (h.viewRenderer = v);
46
46
  }
47
47
  const U = b ?? o, x = C.find((v) => v.canHandle(U));
@@ -102,9 +102,9 @@ function ne(t) {
102
102
  }
103
103
  }
104
104
  l > 0 && (n.width = l + 2, n.__autoSized = !0, i = !0);
105
- }), i && I(t), t.__didInitialAutoSize = !0;
105
+ }), i && q(t), t.__didInitialAutoSize = !0;
106
106
  }
107
- function I(t) {
107
+ function q(t) {
108
108
  (t.effectiveConfig?.fitMode || t.fitMode || W.STRETCH) === W.STRETCH ? t._gridTemplate = t._visibleColumns.map((o) => {
109
109
  if (o.width) return `${o.width}px`;
110
110
  const i = o.minWidth;
@@ -123,7 +123,7 @@ function ke(t, e) {
123
123
  n[r.field] = r.type || "string";
124
124
  }), { columns: i, typeMap: n };
125
125
  }
126
- const Ie = /{{\s*([^}]+)\s*}}/g, A = "__DG_EMPTY__", Be = /^[\w$. '?+\-*/%:()!<>=,&|]+$/, qe = /__(proto|defineGetter|defineSetter)|constructor|window|globalThis|global|process|Function|import|eval|Reflect|Proxy|Error|arguments|document|location|cookie|localStorage|sessionStorage|indexedDB|fetch|XMLHttpRequest|WebSocket|Worker|SharedWorker|ServiceWorker|opener|parent|top|frames|self|this\b/;
126
+ const Ie = /{{\s*([^}]+)\s*}}/g, A = "__DG_EMPTY__", qe = /^[\w$. '?+\-*/%:()!<>=,&|]+$/, Be = /__(proto|defineGetter|defineSetter)|constructor|window|globalThis|global|process|Function|import|eval|Reflect|Proxy|Error|arguments|document|location|cookie|localStorage|sessionStorage|indexedDB|fetch|XMLHttpRequest|WebSocket|Worker|SharedWorker|ServiceWorker|opener|parent|top|frames|self|this\b/;
127
127
  function We(t) {
128
128
  return !t || typeof t != "string" ? "" : t.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
129
129
  }
@@ -152,8 +152,8 @@ const Ue = /* @__PURE__ */ new Set([
152
152
  "plaintext",
153
153
  "xmp",
154
154
  "listing"
155
- ]), re = /^on\w+$/i, $e = /* @__PURE__ */ new Set(["href", "src", "action", "formaction", "data", "srcdoc", "xlink:href", "poster", "srcset"]), Ge = /^\s*(javascript|vbscript|data|blob):/i;
156
- function F(t) {
155
+ ]), re = /^on\w+$/i, $e = /* @__PURE__ */ new Set(["href", "src", "action", "formaction", "data", "srcdoc", "xlink:href", "poster", "srcset"]), Fe = /^\s*(javascript|vbscript|data|blob):/i;
156
+ function G(t) {
157
157
  if (!t || typeof t != "string") return "";
158
158
  if (t.indexOf("<") === -1) return t;
159
159
  const e = document.createElement("template");
@@ -180,7 +180,7 @@ function Ve(t) {
180
180
  r.push(s.name);
181
181
  continue;
182
182
  }
183
- if ($e.has(l) && Ge.test(s.value)) {
183
+ if ($e.has(l) && Fe.test(s.value)) {
184
184
  r.push(s.name);
185
185
  continue;
186
186
  }
@@ -196,19 +196,19 @@ function Ve(t) {
196
196
  function ve(t, e) {
197
197
  if (!t || t.indexOf("{{") === -1) return t;
198
198
  const o = [], i = t.replace(Ie, (l, a) => {
199
- const c = Fe(a, e);
199
+ const c = Ge(a, e);
200
200
  return o.push({ expr: a.trim(), result: c }), c;
201
201
  }), n = Xe(i), r = o.length && o.every((l) => l.result === "" || l.result === A);
202
202
  return /Reflect\.|\bProxy\b|ownKeys\(/.test(t) || r ? "" : n;
203
203
  }
204
- function Fe(t, e) {
204
+ function Ge(t, e) {
205
205
  if (t = (t || "").trim(), !t || /\b(Reflect|Proxy|ownKeys)\b/.test(t)) return A;
206
206
  if (t === "value") return e.value == null ? A : String(e.value);
207
207
  if (t.startsWith("row.") && !/[()?]/.test(t) && !t.includes(":")) {
208
208
  const i = t.slice(4), n = e.row ? e.row[i] : void 0;
209
209
  return n == null ? A : String(n);
210
210
  }
211
- if (t.length > 80 || !Be.test(t) || qe.test(t)) return A;
211
+ if (t.length > 80 || !qe.test(t) || Be.test(t)) return A;
212
212
  const o = t.match(/\./g);
213
213
  if (o && o.length > 1) return A;
214
214
  try {
@@ -634,7 +634,8 @@ class Ke {
634
634
  field: e.field,
635
635
  header: e.header || e.field,
636
636
  visible: !e.hidden,
637
- lockVisible: e.lockVisible
637
+ lockVisible: e.lockVisible,
638
+ utility: e.meta?.utility === !0
638
639
  }));
639
640
  }
640
641
  /**
@@ -783,7 +784,15 @@ function _e(t) {
783
784
  function ye(t) {
784
785
  if (!t) return -1;
785
786
  const e = t.getAttribute("data-row");
786
- return e ? parseInt(e, 10) : -1;
787
+ if (e) return parseInt(e, 10);
788
+ const o = t.closest(".data-grid-row");
789
+ if (!o) return -1;
790
+ const i = o.parentElement;
791
+ if (!i) return -1;
792
+ const n = i.querySelectorAll(":scope > .data-grid-row");
793
+ for (let r = 0; r < n.length; r++)
794
+ if (n[r] === o) return r;
795
+ return -1;
787
796
  }
788
797
  function Ze(t) {
789
798
  if (!t) return -1;
@@ -949,8 +958,8 @@ function st(t, e, o, i, n) {
949
958
  const x = j(u), v = t._activeEditRows === f;
950
959
  x && !v ? (K(u), B(t, u, p, f), u.__epoch = i, u.__rowDataRef = p) : Z(t, u, p, f);
951
960
  }
952
- const S = t._changedRowIndices?.has(f) ?? !1, U = u.classList.contains("changed");
953
- S !== U && u.classList.toggle("changed", S), u.parentNode !== s && s.appendChild(u);
961
+ const R = t._changedRowIndices?.has(f) ?? !1, U = u.classList.contains("changed");
962
+ R !== U && u.classList.toggle("changed", R), u.parentNode !== s && s.appendChild(u);
954
963
  }
955
964
  }
956
965
  function Z(t, e, o, i) {
@@ -989,8 +998,8 @@ function Z(t, e, o, i) {
989
998
  if (m !== b && (g.classList.toggle("cell-focus", m), g.setAttribute("aria-selected", String(m))), g.classList.contains("editing")) continue;
990
999
  const _ = u.renderer || u.viewRenderer;
991
1000
  if (_) {
992
- const y = o[u.field], S = _({ row: o, value: y, field: u.field, column: u, cellEl: g });
993
- typeof S == "string" ? g.innerHTML = F(S) : S instanceof Node ? S.parentElement !== g && (g.innerHTML = "", g.appendChild(S)) : S == null && (g.textContent = y == null ? "" : String(y));
1001
+ const y = o[u.field], R = _({ row: o, value: y, field: u.field, column: u, cellEl: g });
1002
+ typeof R == "string" ? g.innerHTML = G(R) : R instanceof Node ? R.parentElement !== g && (g.innerHTML = "", g.appendChild(R)) : R == null && (g.textContent = y == null ? "" : String(y));
994
1003
  continue;
995
1004
  }
996
1005
  if (u.__viewTemplate || u.__compiledView || u.externalView)
@@ -1024,7 +1033,7 @@ function B(t, e, o, i) {
1024
1033
  let _ = !1;
1025
1034
  if (m) {
1026
1035
  const w = m({ row: o, value: p, field: d.field, column: d, cellEl: f });
1027
- typeof w == "string" ? (f.innerHTML = F(w), _ = !0) : w instanceof Node ? w.parentElement !== f && (f.textContent = "", f.appendChild(w)) : w == null && (f.textContent = p == null ? "" : String(p));
1036
+ typeof w == "string" ? (f.innerHTML = G(w), _ = !0) : w instanceof Node ? w.parentElement !== f && (f.textContent = "", f.appendChild(w)) : w == null && (f.textContent = p == null ? "" : String(p));
1028
1037
  } else if (b) {
1029
1038
  const w = b, C = document.createElement("div");
1030
1039
  C.setAttribute("data-external-view", ""), C.setAttribute("data-field", d.field), f.appendChild(C);
@@ -1032,8 +1041,8 @@ function B(t, e, o, i) {
1032
1041
  if (w.mount)
1033
1042
  try {
1034
1043
  w.mount({ placeholder: C, context: y, spec: w });
1035
- } catch (S) {
1036
- console.warn(`[tbw-grid] External view mount error for column '${d.field}':`, S);
1044
+ } catch (R) {
1045
+ console.warn(`[tbw-grid] External view mount error for column '${d.field}':`, R);
1037
1046
  }
1038
1047
  else
1039
1048
  queueMicrotask(() => {
@@ -1045,17 +1054,17 @@ function B(t, e, o, i) {
1045
1054
  detail: { placeholder: C, spec: w, context: y }
1046
1055
  })
1047
1056
  );
1048
- } catch (S) {
1049
- console.warn(`[tbw-grid] External view event dispatch error for column '${d.field}':`, S);
1057
+ } catch (R) {
1058
+ console.warn(`[tbw-grid] External view event dispatch error for column '${d.field}':`, R);
1050
1059
  }
1051
1060
  });
1052
1061
  C.setAttribute("data-mounted", "");
1053
1062
  } else if (u) {
1054
1063
  const w = u({ row: o, value: p, field: d.field, column: d }), C = u.__blocked;
1055
- f.innerHTML = C ? "" : F(w), _ = !0, C && (f.textContent = "", f.setAttribute("data-blocked-template", ""));
1064
+ f.innerHTML = C ? "" : G(w), _ = !0, C && (f.textContent = "", f.setAttribute("data-blocked-template", ""));
1056
1065
  } else if (g) {
1057
1066
  const w = g.innerHTML;
1058
- /Reflect\.|\bProxy\b|ownKeys\(/.test(w) ? (f.textContent = "", f.setAttribute("data-blocked-template", "")) : (f.innerHTML = F(ve(w, { row: o, value: p })), _ = !0);
1067
+ /Reflect\.|\bProxy\b|ownKeys\(/.test(w) ? (f.textContent = "", f.setAttribute("data-blocked-template", "")) : (f.innerHTML = G(ve(w, { row: o, value: p })), _ = !0);
1059
1068
  } else
1060
1069
  d.type === "date" ? f.textContent = _e(p) : d.type === "boolean" ? f.innerHTML = Ce(!!p) : f.textContent = p == null ? "" : String(p);
1061
1070
  if (_) {
@@ -1090,7 +1099,7 @@ function he(t, e, o, i) {
1090
1099
  }
1091
1100
  return;
1092
1101
  }
1093
- q(t);
1102
+ k(t);
1094
1103
  }
1095
1104
  }
1096
1105
  }
@@ -1105,7 +1114,7 @@ function lt(t, e) {
1105
1114
  if (!(c(a) && (e.key === "Home" || e.key === "End")) && !(c(a) && (e.key === "ArrowUp" || e.key === "ArrowDown") && a.tagName === "INPUT" && a.type === "number") && !(c(a) && (e.key === "ArrowLeft" || e.key === "ArrowRight")) && !(c(a) && (e.key === "Enter" || e.key === "Escape")) && !(n && (s === "select" || s === "typeahead") && (e.key === "ArrowDown" || e.key === "ArrowUp"))) {
1106
1115
  switch (e.key) {
1107
1116
  case "Tab": {
1108
- e.preventDefault(), !e.shiftKey ? t._focusCol < i ? t._focusCol += 1 : (typeof t.commitActiveRowEdit == "function" && t.commitActiveRowEdit(), t._focusRow < o && (t._focusRow += 1, t._focusCol = 0)) : t._focusCol > 0 ? t._focusCol -= 1 : t._focusRow > 0 && (typeof t.commitActiveRowEdit == "function" && t._activeEditRows === t._focusRow && t.commitActiveRowEdit(), t._focusRow -= 1, t._focusCol = i), q(t);
1117
+ e.preventDefault(), !e.shiftKey ? t._focusCol < i ? t._focusCol += 1 : (typeof t.commitActiveRowEdit == "function" && t.commitActiveRowEdit(), t._focusRow < o && (t._focusRow += 1, t._focusCol = 0)) : t._focusCol > 0 ? t._focusCol -= 1 : t._focusRow > 0 && (typeof t.commitActiveRowEdit == "function" && t._activeEditRows === t._focusRow && t.commitActiveRowEdit(), t._focusRow -= 1, t._focusCol = i), k(t);
1109
1118
  return;
1110
1119
  }
1111
1120
  case "ArrowDown":
@@ -1121,10 +1130,10 @@ function lt(t, e) {
1121
1130
  t._focusCol = Math.max(0, t._focusCol - 1), e.preventDefault();
1122
1131
  break;
1123
1132
  case "Home":
1124
- (e.ctrlKey || e.metaKey) && (n && typeof t.commitActiveRowEdit == "function" && t.commitActiveRowEdit(), t._focusRow = 0), t._focusCol = 0, e.preventDefault(), q(t, { forceScrollLeft: !0 });
1133
+ (e.ctrlKey || e.metaKey) && (n && typeof t.commitActiveRowEdit == "function" && t.commitActiveRowEdit(), t._focusRow = 0), t._focusCol = 0, e.preventDefault(), k(t, { forceScrollLeft: !0 });
1125
1134
  return;
1126
1135
  case "End":
1127
- (e.ctrlKey || e.metaKey) && (n && typeof t.commitActiveRowEdit == "function" && t.commitActiveRowEdit(), t._focusRow = o), t._focusCol = i, e.preventDefault(), q(t, { forceScrollRight: !0 });
1136
+ (e.ctrlKey || e.metaKey) && (n && typeof t.commitActiveRowEdit == "function" && t.commitActiveRowEdit(), t._focusRow = o), t._focusCol = i, e.preventDefault(), k(t, { forceScrollRight: !0 });
1128
1137
  return;
1129
1138
  case "PageDown":
1130
1139
  t._focusRow = Math.min(o, t._focusRow + 20), e.preventDefault();
@@ -1133,19 +1142,25 @@ function lt(t, e) {
1133
1142
  t._focusRow = Math.max(0, t._focusRow - 20), e.preventDefault();
1134
1143
  break;
1135
1144
  // NOTE: Enter key is handled by EditingPlugin. If no plugin handles it,
1136
- // we dispatch an activate-cell event for custom handling but don't block navigation.
1137
- case "Enter":
1138
- t.dispatchEvent(
1139
- new CustomEvent("activate-cell", { detail: { row: t._focusRow, col: t._focusCol } })
1140
- );
1145
+ // we dispatch a cancelable activate-cell event for custom handling.
1146
+ case "Enter": {
1147
+ const h = new CustomEvent("activate-cell", {
1148
+ cancelable: !0,
1149
+ detail: { row: t._focusRow, col: t._focusCol }
1150
+ });
1151
+ if (t.dispatchEvent(h), h.defaultPrevented) {
1152
+ e.preventDefault();
1153
+ return;
1154
+ }
1141
1155
  break;
1156
+ }
1142
1157
  default:
1143
1158
  return;
1144
1159
  }
1145
- q(t);
1160
+ k(t);
1146
1161
  }
1147
1162
  }
1148
- function q(t, e) {
1163
+ function k(t, e) {
1149
1164
  if (t._virtualization?.enabled) {
1150
1165
  const { rowHeight: s, container: l, viewportEl: a } = t._virtualization, c = l, h = a?.clientHeight ?? c?.clientHeight ?? 0;
1151
1166
  if (c && h > 0) {
@@ -1159,8 +1174,9 @@ function q(t, e) {
1159
1174
  });
1160
1175
  const i = t._focusRow, n = t._virtualization.start ?? 0, r = t._virtualization.end ?? t._rows.length;
1161
1176
  if (i >= n && i < r) {
1162
- const s = t._bodyEl.querySelectorAll(".data-grid-row")[i - n], l = s?.children[t._focusCol];
1163
- if (l) {
1177
+ const s = t._bodyEl.querySelectorAll(".data-grid-row")[i - n];
1178
+ let l = s?.children[t._focusCol];
1179
+ if ((!l || !l.classList?.contains("cell")) && (l = s?.querySelector(`.cell[data-col="${t._focusCol}"]`) ?? s?.querySelector(".cell[data-col]")), l) {
1164
1180
  l.classList.add("cell-focus"), l.setAttribute("aria-selected", "true");
1165
1181
  const a = t.shadowRoot?.querySelector(".tbw-scroll-area");
1166
1182
  if (a && l && !o)
@@ -1192,7 +1208,7 @@ function q(t, e) {
1192
1208
  }
1193
1209
  }
1194
1210
  }
1195
- var R = /* @__PURE__ */ ((t) => (t[t.STYLE = 1] = "STYLE", t[t.VIRTUALIZATION = 2] = "VIRTUALIZATION", t[t.HEADER = 3] = "HEADER", t[t.ROWS = 4] = "ROWS", t[t.COLUMNS = 5] = "COLUMNS", t[t.FULL = 6] = "FULL", t))(R || {});
1211
+ var S = /* @__PURE__ */ ((t) => (t[t.STYLE = 1] = "STYLE", t[t.VIRTUALIZATION = 2] = "VIRTUALIZATION", t[t.HEADER = 3] = "HEADER", t[t.ROWS = 4] = "ROWS", t[t.COLUMNS = 5] = "COLUMNS", t[t.FULL = 6] = "FULL", t))(S || {});
1196
1212
  class at {
1197
1213
  #o;
1198
1214
  /** Current pending phase (0 = none pending) */
@@ -1310,7 +1326,7 @@ function ct(t) {
1310
1326
  }
1311
1327
  };
1312
1328
  }
1313
- function G(t, e, o) {
1329
+ function F(t, e, o) {
1314
1330
  const i = document.createElement(t);
1315
1331
  if (e)
1316
1332
  for (const n in e) {
@@ -1404,7 +1420,7 @@ function ht(t) {
1404
1420
  n.appendChild(Pe());
1405
1421
  let r = null;
1406
1422
  if (o) {
1407
- r = G("aside", {
1423
+ r = F("aside", {
1408
1424
  class: t.isPanelOpen ? "tbw-tool-panel open" : "tbw-tool-panel",
1409
1425
  part: "tool-panel",
1410
1426
  "data-position": t.position,
@@ -1426,12 +1442,12 @@ function ht(t) {
1426
1442
  "aria-controls": `tbw-section-${c.id}`
1427
1443
  });
1428
1444
  if (i && f.setAttribute("aria-disabled", "true"), c.icon) {
1429
- const u = G("span", { class: "tbw-accordion-icon" });
1445
+ const u = F("span", { class: "tbw-accordion-icon" });
1430
1446
  u.innerHTML = c.icon, f.appendChild(u);
1431
1447
  }
1432
- const p = G("span", { class: "tbw-accordion-title" });
1448
+ const p = F("span", { class: "tbw-accordion-title" });
1433
1449
  if (p.textContent = c.title, f.appendChild(p), !i) {
1434
- const u = G("span", { class: "tbw-accordion-chevron" });
1450
+ const u = F("span", { class: "tbw-accordion-chevron" });
1435
1451
  u.innerHTML = c.isExpanded ? t.collapseIcon : t.expandIcon, f.appendChild(u);
1436
1452
  }
1437
1453
  d.appendChild(f), d.appendChild(
@@ -2410,7 +2426,7 @@ class zt {
2410
2426
  class D extends HTMLElement {
2411
2427
  // TODO: Rename to 'data-grid' when migration is complete
2412
2428
  static tagName = "tbw-grid";
2413
- static version = "0.4.1";
2429
+ static version = "0.4.2";
2414
2430
  // ---------------- Framework Adapters ----------------
2415
2431
  /**
2416
2432
  * Registry of framework adapters that handle converting light DOM elements
@@ -2527,7 +2543,7 @@ class D extends HTMLElement {
2527
2543
  _rows = [];
2528
2544
  // _baseColumns: columns before plugin transformation (analogous to #rows for row processing)
2529
2545
  // This is the source of truth for processColumns - plugins transform these
2530
- #z = [];
2546
+ #N = [];
2531
2547
  // _columns is a getter/setter that operates on effectiveConfig.columns
2532
2548
  // This ensures effectiveConfig.columns is the single source of truth for columns
2533
2549
  // _columns always contains ALL columns (including hidden)
@@ -2563,6 +2579,8 @@ class D extends HTMLElement {
2563
2579
  // Focus & navigation
2564
2580
  _focusRow = 0;
2565
2581
  _focusCol = 0;
2582
+ /** Flag to restore focus styling after next render. @internal */
2583
+ _restoreFocusAfterRender = !1;
2566
2584
  // Sort state
2567
2585
  _sortState = null;
2568
2586
  // Layout
@@ -2665,15 +2683,15 @@ class D extends HTMLElement {
2665
2683
  constructor() {
2666
2684
  super(), this.#o = this.attachShadow({ mode: "open" }), this.#J(), this.#f = new Promise((e) => this.#d = e), this.#l = new at({
2667
2685
  mergeConfig: () => {
2668
- this.#t.parseLightDomColumns(this), this.#t.merge(), this.#V(), Ht(this.#n, this.#i?.getPlugins() ?? []), this.#z = [...this._columns];
2686
+ this.#t.parseLightDomColumns(this), this.#t.merge(), this.#G(), Ht(this.#n, this.#i?.getPlugins() ?? []), this.#N = [...this._columns];
2669
2687
  },
2670
2688
  processColumns: () => this.#de(),
2671
2689
  processRows: () => this.#he(),
2672
2690
  renderHeader: () => X(this),
2673
- updateTemplate: () => I(this),
2691
+ updateTemplate: () => q(this),
2674
2692
  renderVirtualWindow: () => this.refreshVirtualWindow(!0),
2675
2693
  afterRender: () => {
2676
- this.#i?.afterRender(), this.#n.fitMode === "fixed" && !this.__didInitialAutoSize && (this.__didInitialAutoSize = !0, ne(this));
2694
+ this.#i?.afterRender(), this.#n.fitMode === "fixed" && !this.__didInitialAutoSize && (this.__didInitialAutoSize = !0, ne(this)), this._restoreFocusAfterRender && (this._restoreFocusAfterRender = !1, k(this)), this._virtualization.enabled && !this.#z && this.#te();
2677
2695
  },
2678
2696
  isConnected: () => this.isConnected && this.#h
2679
2697
  }), this.#l.setInitialReadyResolver(() => this.#d?.()), this.#a = vt(this.#e, {
@@ -2692,7 +2710,7 @@ class D extends HTMLElement {
2692
2710
  this._sortState = e;
2693
2711
  },
2694
2712
  onConfigChange: () => {
2695
- this.#l.requestPhase(R.FULL, "configChange");
2713
+ this.#l.requestPhase(S.FULL, "configChange");
2696
2714
  },
2697
2715
  emit: (e, o) => this.#Y(e, o),
2698
2716
  clearRowPool: () => {
@@ -2700,8 +2718,8 @@ class D extends HTMLElement {
2700
2718
  },
2701
2719
  setup: () => this.#T(),
2702
2720
  renderHeader: () => X(this),
2703
- updateTemplate: () => I(this),
2704
- refreshVirtualWindow: () => this.#l.requestPhase(R.VIRTUALIZATION, "configManager"),
2721
+ updateTemplate: () => q(this),
2722
+ refreshVirtualWindow: () => this.#l.requestPhase(S.VIRTUALIZATION, "configManager"),
2705
2723
  getVirtualization: () => this._virtualization,
2706
2724
  setRowHeight: (e) => {
2707
2725
  this._virtualization.rowHeight = e;
@@ -2768,7 +2786,16 @@ class D extends HTMLElement {
2768
2786
  * @internal Plugin API
2769
2787
  */
2770
2788
  requestRender() {
2771
- this.#l.requestPhase(R.ROWS, "plugin:requestRender");
2789
+ this.#l.requestPhase(S.ROWS, "plugin:requestRender");
2790
+ }
2791
+ /**
2792
+ * Request a full re-render and restore focus styling afterward.
2793
+ * Use this when a plugin action (like expand/collapse) triggers a render
2794
+ * but needs to maintain keyboard navigation focus.
2795
+ * @internal Plugin API
2796
+ */
2797
+ requestRenderWithFocus() {
2798
+ this._restoreFocusAfterRender = !0, this.#l.requestPhase(S.ROWS, "plugin:requestRenderWithFocus");
2772
2799
  }
2773
2800
  /**
2774
2801
  * Update the grid's column template CSS.
@@ -2776,7 +2803,7 @@ class D extends HTMLElement {
2776
2803
  * @internal
2777
2804
  */
2778
2805
  updateTemplate() {
2779
- I(this);
2806
+ q(this);
2780
2807
  }
2781
2808
  /**
2782
2809
  * Request a lightweight style update without rebuilding DOM.
@@ -2785,13 +2812,13 @@ class D extends HTMLElement {
2785
2812
  * @internal Plugin API
2786
2813
  */
2787
2814
  requestAfterRender() {
2788
- this.#l.requestPhase(R.STYLE, "plugin:requestAfterRender");
2815
+ this.#l.requestPhase(S.STYLE, "plugin:requestAfterRender");
2789
2816
  }
2790
2817
  /**
2791
2818
  * Initialize plugin system with instances from config.
2792
2819
  * Plugins are class instances passed in gridConfig.plugins[].
2793
2820
  */
2794
- #G() {
2821
+ #V() {
2795
2822
  this.#i = new zt(this);
2796
2823
  const e = this.#n?.plugins, o = Array.isArray(e) ? e : [];
2797
2824
  this.#i.attachAll(o);
@@ -2812,7 +2839,7 @@ class D extends HTMLElement {
2812
2839
  * With class-based plugins, we need to detach old and attach new.
2813
2840
  * Skips re-initialization if the plugins array hasn't changed.
2814
2841
  */
2815
- #V() {
2842
+ #G() {
2816
2843
  const e = this.#n?.plugins, o = Array.isArray(e) ? e : [];
2817
2844
  if (this.#E !== o) {
2818
2845
  if (this.#E && this.#E.length === o.length && this.#E.every((i, n) => i === o[n])) {
@@ -2831,7 +2858,7 @@ class D extends HTMLElement {
2831
2858
  const n = this.#e.headerContentCleanups.get(i);
2832
2859
  n && (n(), this.#e.headerContentCleanups.delete(i)), this.#e.headerContents.delete(i);
2833
2860
  }
2834
- this.#G(), this.#M(), this.#E = o, this.#F(), this.#b = this.#i?.getAll().some((i) => i.onScroll) ?? !1;
2861
+ this.#V(), this.#M(), this.#E = o, this.#X(), this.#b = this.#i?.getAll().some((i) => i.onScroll) ?? !1;
2835
2862
  }
2836
2863
  }
2837
2864
  /**
@@ -2844,7 +2871,7 @@ class D extends HTMLElement {
2844
2871
  * Collect tool panels and header content from all plugins.
2845
2872
  * Called after plugins are attached but before render.
2846
2873
  */
2847
- #F() {
2874
+ #X() {
2848
2875
  if (!this.#i) return;
2849
2876
  const e = this.#i.getToolPanels();
2850
2877
  for (const { panel: i } of e)
@@ -2875,9 +2902,9 @@ class D extends HTMLElement {
2875
2902
  }
2876
2903
  // ---------------- Lifecycle ----------------
2877
2904
  connectedCallback() {
2878
- this.hasAttribute("tabindex") || (this.tabIndex = 0), this.hasAttribute("version") || this.setAttribute("version", D.version), this._rows = Array.isArray(this.#r) ? [...this.#r] : [], this.#g && (this.#g.abort(), this.#O = !1), this.#g = new AbortController(), this.#C && (de(this.#C), this.#C = void 0), M(this, this.#e), z(this, this.#e), N(this, this.#e, this.#R()), this.#t.parseLightDomColumns(this), this.#t.merge(), this.#G();
2905
+ this.hasAttribute("tabindex") || (this.tabIndex = 0), this.hasAttribute("version") || this.setAttribute("version", D.version), this._rows = Array.isArray(this.#r) ? [...this.#r] : [], this.#g && (this.#g.abort(), this.#O = !1), this.#g = new AbortController(), this.#C && (de(this.#C), this.#C = void 0), M(this, this.#e), z(this, this.#e), N(this, this.#e, this.#R()), this.#t.parseLightDomColumns(this), this.#t.merge(), this.#V();
2879
2906
  const e = this.#n?.plugins;
2880
- this.#E = Array.isArray(e) ? e : [], this.#F(), this.#c || (this.#U(), this.#M(), this.#c = !0), this.#N(), this.#C = it(
2907
+ this.#E = Array.isArray(e) ? e : [], this.#X(), this.#c || (this.#$(), this.#M(), this.#c = !0), this.#k(), this.#C = it(
2881
2908
  () => {
2882
2909
  this.#me();
2883
2910
  },
@@ -2885,7 +2912,7 @@ class D extends HTMLElement {
2885
2912
  );
2886
2913
  }
2887
2914
  disconnectedCallback() {
2888
- this.#C && (de(this.#C), this.#C = void 0), this.#Q(), mt(this.#e), this.#a.setInitialized(!1), this.#D?.(), this.#D = void 0, Oe(this.#A), this.#g && (this.#g.abort(), this.#g = void 0), this.#P?.abort(), this.#P = void 0, this.#O = !1, this._resizeController && this._resizeController.dispose(), this.#_ && (this.#_.disconnect(), this.#_ = void 0), this.#y && (this.#y.disconnect(), this.#y = void 0, this.#k = !1), $(this), this.#x.clear(), this.#E = void 0;
2915
+ this.#C && (de(this.#C), this.#C = void 0), this.#Q(), mt(this.#e), this.#a.setInitialized(!1), this.#D?.(), this.#D = void 0, Oe(this.#A), this.#g && (this.#g.abort(), this.#g = void 0), this.#P?.abort(), this.#P = void 0, this.#O = !1, this._resizeController && this._resizeController.dispose(), this.#_ && (this.#_.disconnect(), this.#_ = void 0), this.#y && (this.#y.disconnect(), this.#y = void 0, this.#z = !1), $(this), this.#x.clear(), this.#E = void 0;
2889
2916
  for (const e of this._rowPool)
2890
2917
  e.remove();
2891
2918
  this._rowPool.length = 0, this.__rowsBodyEl = null, this.#h = !1;
@@ -2906,7 +2933,7 @@ class D extends HTMLElement {
2906
2933
  }
2907
2934
  else e === "fit-mode" ? this.fitMode = i : e === "edit-on" && (this.editOn = i);
2908
2935
  }
2909
- #N() {
2936
+ #k() {
2910
2937
  const o = this.#o.querySelector(".tbw-grid-content") ?? this.#o.querySelector(".tbw-grid-root");
2911
2938
  if (this._headerRowEl = o?.querySelector(".header-row"), this._virtualization.totalHeightEl = o?.querySelector(".faux-vscroll-spacer"), this._virtualization.viewportEl = o?.querySelector(".rows-viewport"), this._bodyEl = o?.querySelector(".rows"), this.__rowsBodyEl = o?.querySelector(".rows-body"), this.#a.isInitialized) {
2912
2939
  He(this.#o, this.#e), gt(this.#o, this.#n?.shell, this.#e);
@@ -2919,13 +2946,13 @@ class D extends HTMLElement {
2919
2946
  const i = this.disconnectSignal;
2920
2947
  this.addEventListener("keydown", (r) => lt(this, r), { signal: i }), this.#o.addEventListener("mousedown", (r) => this.#pe(r), { signal: i }), document.addEventListener("mousemove", (r) => this.#ge(r), { signal: i }), document.addEventListener("mouseup", (r) => this.#we(r), { signal: i });
2921
2948
  const n = this.#n.rowHeight;
2922
- n && n > 0 ? this._virtualization.rowHeight = n : requestAnimationFrame(() => this.#X()), queueMicrotask(() => this.#oe()), this.#l.requestPhase(R.FULL, "afterConnect");
2949
+ n && n > 0 ? this._virtualization.rowHeight = n : requestAnimationFrame(() => this.#I()), queueMicrotask(() => this.#oe()), this.#l.requestPhase(S.FULL, "afterConnect");
2923
2950
  }
2924
2951
  /**
2925
2952
  * Measure actual row height from DOM.
2926
2953
  * Finds the tallest cell to account for custom renderers that may push height.
2927
2954
  */
2928
- #X() {
2955
+ #I() {
2929
2956
  const e = this._bodyEl?.querySelector(".data-grid-row");
2930
2957
  if (!e) return;
2931
2958
  const o = e.querySelectorAll(".cell");
@@ -2935,7 +2962,7 @@ class D extends HTMLElement {
2935
2962
  l > i && (i = l);
2936
2963
  });
2937
2964
  const n = e.getBoundingClientRect(), r = Math.max(n.height, i);
2938
- r > 0 && r !== this._virtualization.rowHeight && (this._virtualization.rowHeight = r, this.#l.requestPhase(R.VIRTUALIZATION, "measureRowHeight"));
2965
+ r > 0 && r !== this._virtualization.rowHeight && (this._virtualization.rowHeight = r, this.#l.requestPhase(S.VIRTUALIZATION, "measureRowHeight"));
2939
2966
  }
2940
2967
  /**
2941
2968
  * Set up scroll-related event listeners on DOM elements.
@@ -2980,25 +3007,37 @@ class D extends HTMLElement {
2980
3007
  ), At(r, this.#A, { fauxScrollbar: i, scrollArea: s }, o));
2981
3008
  }
2982
3009
  this._bodyEl && Qe(this, this._bodyEl, o), this.#_?.disconnect(), this._virtualization.viewportEl && (this.#_ = new ResizeObserver(() => {
2983
- this.#l.requestPhase(R.VIRTUALIZATION, "resize-observer");
2984
- }), this.#_.observe(this._virtualization.viewportEl)), this._virtualization.enabled && (this.#l.requestPhase(R.VIRTUALIZATION, "init-virtualization"), queueMicrotask(() => this.#te()));
3010
+ this.#l.requestPhase(S.VIRTUALIZATION, "resize-observer");
3011
+ }), this.#_.observe(this._virtualization.viewportEl)), this._virtualization.enabled && this.#l.requestPhase(S.VIRTUALIZATION, "init-virtualization"), this.#o.addEventListener(
3012
+ "focusin",
3013
+ () => {
3014
+ this.dataset.hasFocus = "";
3015
+ },
3016
+ { signal: o }
3017
+ ), this.#o.addEventListener(
3018
+ "focusout",
3019
+ (r) => {
3020
+ const s = r.relatedTarget;
3021
+ (!s || !this.#o.contains(s)) && delete this.dataset.hasFocus;
3022
+ },
3023
+ { signal: o }
3024
+ );
2985
3025
  }
2986
3026
  /**
2987
- * Set up ResizeObserver on first row's cells to detect height changes.
2988
- * Called after rows are rendered to observe the actual content cells.
2989
- * Handles dynamic CSS loading, lazy images, font loading, etc.
3027
+ * Set up ResizeObserver on first row to detect height changes.
3028
+ * Called after rows are rendered to observe the actual content.
3029
+ * Handles dynamic CSS loading, lazy images, font loading, column virtualization, etc.
2990
3030
  */
2991
- #k = !1;
3031
+ #z = !1;
2992
3032
  // Only set up once per lifecycle
2993
3033
  #te() {
2994
- if (this.#k) return;
3034
+ if (this.#z) return;
2995
3035
  const e = this._bodyEl?.querySelector(".data-grid-row");
2996
- if (!e) return;
2997
- this.#k = !0, this.#y?.disconnect();
2998
- const o = e.querySelectorAll(".cell");
2999
- o.length > 0 && (this.#y = new ResizeObserver(() => {
3000
- this.#X();
3001
- }), o.forEach((i) => this.#y.observe(i)));
3036
+ e && (this.#z = !0, this.#y?.disconnect(), this.#y = new ResizeObserver(() => {
3037
+ this.#I();
3038
+ }), this.#y.observe(e), requestAnimationFrame(() => {
3039
+ this.#I();
3040
+ }));
3002
3041
  }
3003
3042
  // ---------------- Event Emitters ----------------
3004
3043
  #Y(e, o) {
@@ -3047,7 +3086,7 @@ class D extends HTMLElement {
3047
3086
  }
3048
3087
  // Individual update applicators - these do the actual work
3049
3088
  #ne() {
3050
- this._rows = Array.isArray(this.#r) ? [...this.#r] : [], this.#l.requestPhase(R.ROWS, "applyRowsUpdate");
3089
+ this._rows = Array.isArray(this.#r) ? [...this.#r] : [], this.#l.requestPhase(S.ROWS, "applyRowsUpdate");
3051
3090
  }
3052
3091
  #re() {
3053
3092
  $(this), this.#t.merge(), this.#T();
@@ -3055,21 +3094,21 @@ class D extends HTMLElement {
3055
3094
  #se() {
3056
3095
  this.#t.merge(), this.#n.fitMode === "fixed" ? (this.__didInitialAutoSize = !1, ne(this)) : (this._columns.forEach((o) => {
3057
3096
  !o.__userResized && o.__autoSized && delete o.width;
3058
- }), I(this));
3097
+ }), q(this));
3059
3098
  }
3060
3099
  #le() {
3061
- this.#t.merge(), this._rowPool.length = 0, this._bodyEl && (this._bodyEl.innerHTML = ""), this.__rowRenderEpoch++, this.#l.requestPhase(R.VIRTUALIZATION, "applyEditModeUpdate");
3100
+ this.#t.merge(), this._rowPool.length = 0, this._bodyEl && (this._bodyEl.innerHTML = ""), this.__rowRenderEpoch++, this.#l.requestPhase(S.VIRTUALIZATION, "applyEditModeUpdate");
3062
3101
  }
3063
3102
  #ae() {
3064
3103
  M(this, this.#e), z(this, this.#e);
3065
3104
  const e = !!this.#o.querySelector(".has-shell"), o = !!this.#o.querySelector(".tbw-tool-panel"), i = this.#o.querySelectorAll(".tbw-accordion-section").length;
3066
- this.#t.parseLightDomColumns(this), this.#t.merge(), this.#V(), N(this, this.#e, this.#R()), this.#t.markSourcesChanged(), this.#t.merge();
3105
+ this.#t.parseLightDomColumns(this), this.#t.merge(), this.#G(), N(this, this.#e, this.#R()), this.#t.markSourcesChanged(), this.#t.merge();
3067
3106
  const n = Le(this.#n?.shell), r = (this.#n?.shell?.toolPanels?.length ?? 0) > 0, s = (this.#n?.shell?.toolPanels?.length ?? 0) !== i;
3068
3107
  if (e !== n || !e && n || !o && r || o && s) {
3069
- this.#U(), this.#M(), this.#N();
3108
+ this.#$(), this.#M(), this.#k();
3070
3109
  return;
3071
3110
  }
3072
- e && this.#ce(), this.#l.requestPhase(R.COLUMNS, "applyGridConfigUpdate");
3111
+ e && this.#ce(), this.#l.requestPhase(S.COLUMNS, "applyGridConfigUpdate");
3073
3112
  }
3074
3113
  /**
3075
3114
  * Update the shell header DOM in place without a full re-render.
@@ -3088,19 +3127,11 @@ class D extends HTMLElement {
3088
3127
  // (e.g., setting rows, columns, gridConfig in quick succession) into a single update cycle.
3089
3128
  #de() {
3090
3129
  if (this.#i) {
3091
- const e = this.#z.length > 0 ? this.#z : this._columns, o = e.filter((r) => !r.hidden), i = e.filter((r) => r.hidden), n = this.#i.processColumns([...o]);
3130
+ const e = this.#N.length > 0 ? this.#N : this._columns, o = e.filter((r) => !r.hidden), i = e.filter((r) => r.hidden), n = this.#i.processColumns([...o]);
3092
3131
  if (n !== o) {
3093
- const r = new Map(n.map((l, a) => [l.field, { col: l, order: a }]));
3094
- if (!o.some((l) => r.has(l.field)) && n.length > 0)
3095
- this._columns = [...n, ...i];
3096
- else {
3097
- const l = e.map((a) => {
3098
- if (a.hidden) return a;
3099
- const c = r.get(a.field);
3100
- return c ? c.col : a;
3101
- });
3102
- this._columns = l;
3103
- }
3132
+ new Set(o.map((l) => l.field));
3133
+ const r = new Set(n.map((l) => l.field));
3134
+ !o.some((l) => r.has(l.field)) && n.length > 0 ? this._columns = [...n, ...i] : this._columns = [...n, ...i];
3104
3135
  } else
3105
3136
  this._columns = [...e];
3106
3137
  }
@@ -3125,7 +3156,7 @@ class D extends HTMLElement {
3125
3156
  i === !1 || i === "off" ? n = 0 : (i === !0 || i === "on") && (n = 1), this.style.setProperty("--tbw-animation-duration", `${o.duration}ms`), this.style.setProperty("--tbw-animation-easing", o.easing ?? "ease-out"), this.style.setProperty("--tbw-animation-enabled", String(n)), this.dataset.animationMode = typeof i == "boolean" ? i ? "on" : "off" : i;
3126
3157
  }
3127
3158
  // ---------------- Delegate Wrappers ----------------
3128
- #I(e, o, i = this.__rowRenderEpoch) {
3159
+ #q(e, o, i = this.__rowRenderEpoch) {
3129
3160
  this.#s || (this.#s = (n, r, s) => this.#i?.renderRow(n, r, s) ?? !1), st(this, e, o, i, this.#s);
3130
3161
  }
3131
3162
  // Cache for ARIA counts to avoid redundant DOM writes on scroll (hot path)
@@ -3159,7 +3190,7 @@ class D extends HTMLElement {
3159
3190
  const o = this.#i?.getAll() ?? [];
3160
3191
  this.#t.applyState(e, o);
3161
3192
  }
3162
- this._bodyEl && (this._bodyEl.style.display = "", this._bodyEl.style.gridTemplateColumns = ""), this.#l.requestPhase(R.FULL, "setup");
3193
+ this._bodyEl && (this._bodyEl.style.display = "", this._bodyEl.style.gridTemplateColumns = ""), this.#l.requestPhase(S.FULL, "setup");
3163
3194
  }
3164
3195
  }
3165
3196
  #fe(e) {
@@ -3269,7 +3300,7 @@ class D extends HTMLElement {
3269
3300
  * Build a CellMouseEvent from a native MouseEvent.
3270
3301
  * Extracts cell/row information from the event target.
3271
3302
  */
3272
- #q(e, o) {
3303
+ #W(e, o) {
3273
3304
  let i = null;
3274
3305
  const n = e.composedPath?.();
3275
3306
  if (n && n.length > 0 ? i = n[0] : i = e.target, i && !this.#o.contains(i)) {
@@ -3297,7 +3328,7 @@ class D extends HTMLElement {
3297
3328
  * Handle mousedown events and dispatch to plugin system.
3298
3329
  */
3299
3330
  #pe(e) {
3300
- const o = this.#q(e, "mousedown");
3331
+ const o = this.#W(e, "mousedown");
3301
3332
  (this.#i?.onCellMouseDown(o) ?? !1) && (this.#m = !0);
3302
3333
  }
3303
3334
  /**
@@ -3305,7 +3336,7 @@ class D extends HTMLElement {
3305
3336
  */
3306
3337
  #ge(e) {
3307
3338
  if (!this.#m) return;
3308
- const o = this.#q(e, "mousemove");
3339
+ const o = this.#W(e, "mousemove");
3309
3340
  this.#i?.onCellMouseMove(o);
3310
3341
  }
3311
3342
  /**
@@ -3313,14 +3344,14 @@ class D extends HTMLElement {
3313
3344
  */
3314
3345
  #we(e) {
3315
3346
  if (!this.#m) return;
3316
- const o = this.#q(e, "mouseup");
3347
+ const o = this.#W(e, "mouseup");
3317
3348
  this.#i?.onCellMouseUp(o), this.#m = !1;
3318
3349
  }
3319
3350
  async ready() {
3320
3351
  return this.#f;
3321
3352
  }
3322
3353
  async forceLayout() {
3323
- return this.#l.requestPhase(R.FULL, "forceLayout"), this.#l.whenReady();
3354
+ return this.#l.requestPhase(S.FULL, "forceLayout"), this.#l.whenReady();
3324
3355
  }
3325
3356
  /**
3326
3357
  * Trim the internal row pool to match the current visible window size.
@@ -3487,7 +3518,7 @@ class D extends HTMLElement {
3487
3518
  * Call this after dynamically modifying <tbw-grid-header> children.
3488
3519
  */
3489
3520
  refreshShellHeader() {
3490
- M(this, this.#e), z(this, this.#e), N(this, this.#e, this.#R()), this.#t.markSourcesChanged(), this.#t.merge(), this.#U(), this.#M(), this.#N();
3521
+ M(this, this.#e), z(this, this.#e), N(this, this.#e, this.#R()), this.#t.markSourcesChanged(), this.#t.merge(), this.#$(), this.#M(), this.#k();
3491
3522
  }
3492
3523
  // #region Custom Styles API
3493
3524
  /** Map of registered custom stylesheets by ID - uses adoptedStyleSheets which survive DOM rebuilds */
@@ -3567,7 +3598,7 @@ class D extends HTMLElement {
3567
3598
  ), c = document.createElement("div");
3568
3599
  c.innerHTML = a;
3569
3600
  const h = c.firstElementChild;
3570
- h && (l.replaceWith(h), this.#$());
3601
+ h && (l.replaceWith(h), this.#F());
3571
3602
  }
3572
3603
  }
3573
3604
  }, o = () => {
@@ -3597,17 +3628,17 @@ class D extends HTMLElement {
3597
3628
  ), a = document.createElement("div");
3598
3629
  a.innerHTML = l;
3599
3630
  const c = a.firstElementChild;
3600
- c && (s.replaceWith(c), this.#$());
3631
+ c && (s.replaceWith(c), this.#F());
3601
3632
  }
3602
3633
  }
3603
- this.#l.requestPhase(R.COLUMNS, "refreshColumns");
3634
+ this.#l.requestPhase(S.COLUMNS, "refreshColumns");
3604
3635
  }
3605
3636
  // ---------------- Virtual Window ----------------
3606
3637
  /**
3607
3638
  * Calculate total height for the faux scrollbar spacer element.
3608
3639
  * Used by both bypass and virtualized rendering paths to ensure consistent scroll behavior.
3609
3640
  */
3610
- #W(e) {
3641
+ #U(e) {
3611
3642
  const o = this._virtualization.rowHeight, i = this._virtualization.container ?? this, n = this._virtualization.viewportEl ?? i, r = i.clientHeight, s = n.clientHeight, a = this.shadowRoot?.querySelector(".tbw-scroll-area"), c = a ? a.clientHeight : r, d = c - s, f = this.#i?.getExtraHeight() ?? 0, p = Math.max(0, r - c);
3612
3643
  return e * o + d + f + p;
3613
3644
  }
@@ -3620,11 +3651,11 @@ class D extends HTMLElement {
3620
3651
  if (!this._bodyEl) return;
3621
3652
  const o = this._rows.length;
3622
3653
  if (!this._virtualization.enabled) {
3623
- this.#I(0, o), this.#i?.afterRender();
3654
+ this.#q(0, o), this.#i?.afterRender();
3624
3655
  return;
3625
3656
  }
3626
3657
  if (this._rows.length <= this._virtualization.bypassThreshold) {
3627
- this._virtualization.start = 0, this._virtualization.end = o, e && (this._bodyEl.style.transform = "translateY(0px)"), this.#I(0, o, e ? ++this.__rowRenderEpoch : this.__rowRenderEpoch), this._virtualization.totalHeightEl && (this._virtualization.totalHeightEl.style.height = `${this.#W(o)}px`), this.#K(o, this._visibleColumns.length), this.#i?.afterRender();
3658
+ this._virtualization.start = 0, this._virtualization.end = o, e && (this._bodyEl.style.transform = "translateY(0px)"), this.#q(0, o, e ? ++this.__rowRenderEpoch : this.__rowRenderEpoch), this._virtualization.totalHeightEl && (this._virtualization.totalHeightEl.style.height = `${this.#U(o)}px`), this.#K(o, this._visibleColumns.length), this.#i?.afterRender();
3628
3659
  return;
3629
3660
  }
3630
3661
  const i = this._virtualization.container ?? this, n = this._virtualization.viewportEl ?? i, r = n.clientHeight, s = this._virtualization.rowHeight, l = i.scrollTop;
@@ -3641,21 +3672,21 @@ class D extends HTMLElement {
3641
3672
  const f = Math.ceil(r / s) + 3;
3642
3673
  let p = a + f;
3643
3674
  if (p > o && (p = o), this._virtualization.start = a, this._virtualization.end = p, i.clientHeight === 0 && r > 0) {
3644
- this.#l.requestPhase(R.VIRTUALIZATION, "stale-refs-retry");
3675
+ this.#l.requestPhase(S.VIRTUALIZATION, "stale-refs-retry");
3645
3676
  return;
3646
3677
  }
3647
- const g = this.#W(o);
3678
+ const g = this.#U(o);
3648
3679
  this._virtualization.totalHeightEl && (this._virtualization.totalHeightEl.style.height = `${g}px`);
3649
3680
  const m = this.#i?.getExtraHeightBefore?.(a) ?? 0, b = -(l - a * s - m);
3650
- this._bodyEl.style.transform = `translateY(${b}px)`, this.#I(a, p, e ? ++this.__rowRenderEpoch : this.__rowRenderEpoch), this.#K(o, this._visibleColumns.length), e && (this.#i?.afterRender(), queueMicrotask(() => {
3681
+ this._bodyEl.style.transform = `translateY(${b}px)`, this.#q(a, p, e ? ++this.__rowRenderEpoch : this.__rowRenderEpoch), this.#K(o, this._visibleColumns.length), e && (this.#i?.afterRender(), queueMicrotask(() => {
3651
3682
  const _ = i.clientHeight, w = n.clientHeight;
3652
3683
  if (_ === 0 && w > 0) return;
3653
- const C = this.#W(o);
3684
+ const C = this.#U(o);
3654
3685
  this._virtualization.totalHeightEl && (this._virtualization.totalHeightEl.style.height = `${C}px`);
3655
3686
  }));
3656
3687
  }
3657
3688
  // ---------------- Render ----------------
3658
- #U() {
3689
+ #$() {
3659
3690
  M(this, this.#e), z(this, this.#e), N(this, this.#e, this.#R()), this.#t.markSourcesChanged(), this.#t.merge();
3660
3691
  const e = this.#n?.shell;
3661
3692
  _t(
@@ -3663,12 +3694,12 @@ class D extends HTMLElement {
3663
3694
  e,
3664
3695
  { isPanelOpen: this.#e.isPanelOpen, expandedSections: this.#e.expandedSections },
3665
3696
  this.#n?.icons
3666
- ) && (this.#$(), this.#a.setInitialized(!0));
3697
+ ) && (this.#F(), this.#a.setInitialized(!0));
3667
3698
  }
3668
3699
  /**
3669
3700
  * Set up shell event listeners after render.
3670
3701
  */
3671
- #$() {
3702
+ #F() {
3672
3703
  ft(this.#o, this.#n?.shell, this.#e, {
3673
3704
  onPanelToggle: () => this.toggleToolPanel(),
3674
3705
  onSectionToggle: (e) => this.toggleToolPanelSection(e),
@@ -3711,8 +3742,11 @@ class It {
3711
3742
  * ```
3712
3743
  */
3713
3744
  static dependencies;
3714
- /** Plugin version - override in subclass if needed */
3715
- version = "1.0.0";
3745
+ /**
3746
+ * Plugin version - defaults to grid version for built-in plugins.
3747
+ * Third-party plugins can override with their own semver.
3748
+ */
3749
+ version = "0.4.2";
3716
3750
  /** CSS styles to inject into the grid's shadow DOM */
3717
3751
  styles;
3718
3752
  /** Custom cell renderers keyed by type name */
@@ -3799,12 +3833,28 @@ class It {
3799
3833
  emit(e, o) {
3800
3834
  this.grid?.dispatchEvent?.(new CustomEvent(e, { detail: o, bubbles: !0 }));
3801
3835
  }
3836
+ /**
3837
+ * Emit a cancelable custom event from the grid.
3838
+ * @returns `true` if the event was cancelled (preventDefault called), `false` otherwise
3839
+ */
3840
+ emitCancelable(e, o) {
3841
+ const i = new CustomEvent(e, { detail: o, bubbles: !0, cancelable: !0 });
3842
+ return this.grid?.dispatchEvent?.(i), i.defaultPrevented;
3843
+ }
3802
3844
  /**
3803
3845
  * Request a re-render of the grid.
3804
3846
  */
3805
3847
  requestRender() {
3806
3848
  this.grid?.requestRender?.();
3807
3849
  }
3850
+ /**
3851
+ * Request a re-render and restore focus styling afterward.
3852
+ * Use this when a plugin action (like expand/collapse) triggers a render
3853
+ * but needs to maintain keyboard navigation focus.
3854
+ */
3855
+ requestRenderWithFocus() {
3856
+ this.grid?.requestRenderWithFocus?.();
3857
+ }
3808
3858
  /**
3809
3859
  * Request a lightweight style update without rebuilding DOM.
3810
3860
  * Use this instead of requestRender() when only CSS classes need updating.
@@ -3838,6 +3888,19 @@ class It {
3838
3888
  get visibleColumns() {
3839
3889
  return this.grid?._visibleColumns ?? [];
3840
3890
  }
3891
+ /**
3892
+ * Get the grid as an HTMLElement for direct DOM operations.
3893
+ * Use sparingly - prefer the typed GridElementRef API when possible.
3894
+ *
3895
+ * @example
3896
+ * ```ts
3897
+ * const width = this.gridElement.clientWidth;
3898
+ * this.gridElement.classList.add('my-plugin-active');
3899
+ * ```
3900
+ */
3901
+ get gridElement() {
3902
+ return this.grid;
3903
+ }
3841
3904
  /**
3842
3905
  * Get the shadow root of the grid.
3843
3906
  */
@@ -3872,6 +3935,51 @@ class It {
3872
3935
  const e = this.grid?.gridConfig?.icons ?? {};
3873
3936
  return { ...L, ...e };
3874
3937
  }
3938
+ // #region Animation Helpers
3939
+ /**
3940
+ * Check if animations are enabled at the grid level.
3941
+ * Respects gridConfig.animation.mode and the CSS variable set by the grid.
3942
+ *
3943
+ * Plugins should use this to skip animations when:
3944
+ * - Animation mode is 'off' or `false`
3945
+ * - User prefers reduced motion and mode is 'reduced-motion' (default)
3946
+ *
3947
+ * @example
3948
+ * ```ts
3949
+ * private get animationStyle(): 'slide' | 'fade' | false {
3950
+ * if (!this.isAnimationEnabled) return false;
3951
+ * return this.config.animation ?? 'slide';
3952
+ * }
3953
+ * ```
3954
+ */
3955
+ get isAnimationEnabled() {
3956
+ const e = this.grid?.effectiveConfig?.animation?.mode ?? "reduced-motion";
3957
+ if (e === !1 || e === "off") return !1;
3958
+ if (e === !0 || e === "on") return !0;
3959
+ const o = this.shadowRoot?.host;
3960
+ return o ? getComputedStyle(o).getPropertyValue("--tbw-animation-enabled").trim() !== "0" : !0;
3961
+ }
3962
+ /**
3963
+ * Get the animation duration in milliseconds from CSS variable.
3964
+ * Falls back to 200ms if not set.
3965
+ *
3966
+ * Plugins can use this for their animation timing to stay consistent
3967
+ * with the grid-level animation.duration setting.
3968
+ *
3969
+ * @example
3970
+ * ```ts
3971
+ * element.animate(keyframes, { duration: this.animationDuration });
3972
+ * ```
3973
+ */
3974
+ get animationDuration() {
3975
+ const e = this.shadowRoot?.host;
3976
+ if (e) {
3977
+ const o = getComputedStyle(e).getPropertyValue("--tbw-animation-duration").trim(), i = parseInt(o, 10);
3978
+ if (!isNaN(i)) return i;
3979
+ }
3980
+ return 200;
3981
+ }
3982
+ // #endregion
3875
3983
  /**
3876
3984
  * Resolve an icon value to string or HTMLElement.
3877
3985
  * Checks plugin config first, then grid-level icons, then defaults.
@@ -3961,7 +4069,7 @@ const E = {
3961
4069
  // TreePlugin
3962
4070
  STICKY: "data-sticky"
3963
4071
  // PinnedColumnsPlugin
3964
- }, Bt = {
4072
+ }, qt = {
3965
4073
  ROOT: `.${E.ROOT}`,
3966
4074
  HEADER: `.${E.HEADER}`,
3967
4075
  HEADER_ROW: `.${E.HEADER_ROW}`,
@@ -3978,7 +4086,7 @@ const E = {
3978
4086
  // State selectors
3979
4087
  SELECTED_ROWS: `.${E.DATA_ROW}.${E.SELECTED}`,
3980
4088
  EDITING_CELL: `.${E.DATA_CELL}.${E.EDITING}`
3981
- }, qt = {
4089
+ }, Bt = {
3982
4090
  // Colors
3983
4091
  COLOR_BG: "--tbw-color-bg",
3984
4092
  COLOR_FG: "--tbw-color-fg",
@@ -4053,25 +4161,25 @@ const E = {
4053
4161
  max: (t, e) => Math.max(...t.map((o) => Number(o[e]) || -1 / 0)),
4054
4162
  first: (t, e) => t[0]?.[e],
4055
4163
  last: (t, e) => t[t.length - 1]?.[e]
4056
- }, k = /* @__PURE__ */ new Map(), P = {
4164
+ }, I = /* @__PURE__ */ new Map(), P = {
4057
4165
  /**
4058
4166
  * Register a custom aggregator function.
4059
4167
  */
4060
4168
  register(t, e) {
4061
- k.set(t, e);
4169
+ I.set(t, e);
4062
4170
  },
4063
4171
  /**
4064
4172
  * Unregister a custom aggregator function.
4065
4173
  */
4066
4174
  unregister(t) {
4067
- k.delete(t);
4175
+ I.delete(t);
4068
4176
  },
4069
4177
  /**
4070
4178
  * Get an aggregator function by reference.
4071
4179
  */
4072
4180
  get(t) {
4073
4181
  if (t !== void 0)
4074
- return typeof t == "function" ? t : k.get(t) ?? Q[t];
4182
+ return typeof t == "function" ? t : I.get(t) ?? Q[t];
4075
4183
  },
4076
4184
  /**
4077
4185
  * Run an aggregator on a set of rows.
@@ -4084,13 +4192,13 @@ const E = {
4084
4192
  * Check if an aggregator exists.
4085
4193
  */
4086
4194
  has(t) {
4087
- return k.has(t) || t in Q;
4195
+ return I.has(t) || t in Q;
4088
4196
  },
4089
4197
  /**
4090
4198
  * List all available aggregator names.
4091
4199
  */
4092
4200
  list() {
4093
- return [...Object.keys(Q), ...k.keys()];
4201
+ return [...Object.keys(Q), ...I.keys()];
4094
4202
  }
4095
4203
  }, me = {
4096
4204
  sum: (t) => t.reduce((e, o) => e + o, 0),
@@ -4107,7 +4215,7 @@ function Nt(t) {
4107
4215
  function $t(t, e) {
4108
4216
  return Nt(t)(e);
4109
4217
  }
4110
- const Gt = P.register.bind(P), Vt = P.unregister.bind(P), Ft = P.get.bind(P), Xt = P.run.bind(P), Yt = P.list.bind(P);
4218
+ const Ft = P.register.bind(P), Vt = P.unregister.bind(P), Gt = P.get.bind(P), Xt = P.run.bind(P), Yt = P.list.bind(P);
4111
4219
  export {
4112
4220
  It as BaseGridPlugin,
4113
4221
  Me as DEFAULT_ANIMATION_CONFIG,
@@ -4115,29 +4223,29 @@ export {
4115
4223
  Wt as DGEvents,
4116
4224
  D as DataGridElement,
4117
4225
  W as FitModeEnum,
4118
- qt as GridCSSVars,
4226
+ Bt as GridCSSVars,
4119
4227
  E as GridClasses,
4120
4228
  V as GridDataAttrs,
4121
4229
  D as GridElement,
4122
- Bt as GridSelectors,
4230
+ qt as GridSelectors,
4123
4231
  kt as PLUGIN_QUERIES,
4124
4232
  Ut as PluginEvents,
4125
4233
  zt as PluginManager,
4126
- R as RenderPhase,
4127
- q as a,
4234
+ S as RenderPhase,
4235
+ k as a,
4128
4236
  P as aggregatorRegistry,
4129
4237
  tt as builtInSort,
4130
4238
  ee as c,
4131
4239
  et as defaultComparator,
4132
4240
  ve as e,
4133
4241
  ye as g,
4134
- Ft as getAggregator,
4242
+ Gt as getAggregator,
4135
4243
  Nt as getValueAggregator,
4136
4244
  Yt as listAggregators,
4137
- Gt as registerAggregator,
4245
+ Ft as registerAggregator,
4138
4246
  Xt as runAggregator,
4139
4247
  $t as runValueAggregator,
4140
- F as s,
4248
+ G as s,
4141
4249
  Vt as unregisterAggregator
4142
4250
  };
4143
4251
  //# sourceMappingURL=index.js.map