@keenmate/web-grid 1.0.0-rc05 → 1.0.0-rc07

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/grid.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Column, CellValidationState, RowToolbarConfig, ContextMenuItem, RowChangeDetail, ToolbarClickDetail, RowActionClickDetail, ContextMenuContext, EditTrigger, EditStartSelection, EditingCell, FocusedCell, SortMode, SortState, DataRequestDetail, DataRequestTrigger, BeforeCommitResult, GridMode, ToggleVisibility, PaginationLabelsCallback, SummaryContentCallback, ValidationTooltipContext } from './types.js';
1
+ import type { Column, CellValidationState, RowToolbarConfig, ContextMenuItem, RowShortcut, RowChangeDetail, ToolbarClickDetail, RowActionClickDetail, ContextMenuContext, EditTrigger, EditStartSelection, EditingCell, FocusedCell, SortMode, SortState, DataRequestDetail, DataRequestTrigger, BeforeCommitResult, GridMode, ToggleVisibility, PaginationLabelsCallback, SummaryContentCallback, ValidationTooltipContext, ToolbarPosition, GridLabels, RowLockInfo, RowLockingOptions, RowLockChangeDetail } from './types.js';
2
2
  /**
3
3
  * WebGrid - Core logic class for the data grid
4
4
  *
@@ -27,11 +27,23 @@ export declare class WebGrid<T = unknown> {
27
27
  protected _invalidCells: CellValidationState[];
28
28
  protected _showRowToolbar: boolean;
29
29
  protected _rowToolbar: RowToolbarConfig<T>[];
30
- protected _toolbarAlign: 'center' | 'top';
31
- protected _toolbarTopPosition: 'start' | 'center' | 'end' | 'cursor';
30
+ protected _toolbarVerticalAlign: 'top' | 'center' | 'bottom';
31
+ protected _toolbarHorizontalAlign: 'start' | 'center' | 'end' | 'cursor';
32
32
  protected _toolbarTrigger: 'hover' | 'click' | 'button';
33
- protected _toolbarPosition: 'auto' | 'left' | 'right' | 'top';
33
+ protected _toolbarPosition: ToolbarPosition;
34
+ protected _inlineActionsTitle: string;
34
35
  protected _contextMenu: ContextMenuItem<T>[] | undefined;
36
+ protected _contextMenuXOffset: number;
37
+ protected _contextMenuYOffset: number;
38
+ protected _rowShortcuts: RowShortcut<T>[] | undefined;
39
+ protected _showShortcutsHelp: boolean;
40
+ protected _shortcutsHelpPosition: 'top-right' | 'top-left';
41
+ protected _shortcutsHelpContentCallback: (() => string) | undefined;
42
+ protected _idValueMember: keyof T | undefined;
43
+ protected _idValueCallback: ((row: T) => unknown) | undefined;
44
+ protected _rowLocking: RowLockingOptions<T> | undefined;
45
+ protected _externalLocks: Map<unknown, RowLockInfo>;
46
+ protected _onrowlockchange: ((detail: RowLockChangeDetail<T>) => void) | undefined;
35
47
  protected _onrowchange: ((detail: RowChangeDetail<T>) => void) | undefined;
36
48
  protected _onroweditstart: ((detail: {
37
49
  row: T;
@@ -72,6 +84,7 @@ export declare class WebGrid<T = unknown> {
72
84
  protected _summaryInline: boolean;
73
85
  protected _customStylesCallback?: () => string;
74
86
  protected _rowClassCallback?: (row: T, rowIndex: number) => string | null;
87
+ protected _labels: GridLabels;
75
88
  protected _virtualScroll: boolean;
76
89
  protected _virtualScrollThreshold: number;
77
90
  protected _virtualScrollRowHeight: number;
@@ -87,15 +100,17 @@ export declare class WebGrid<T = unknown> {
87
100
  protected _focusedCell: FocusedCell;
88
101
  protected _isCommittingFromKeyboard: boolean;
89
102
  protected _skipNextDropdownAutoEdit: boolean;
103
+ protected _hoveredRowIndex: number | null;
104
+ protected _onInteractionChange: ((type: 'hoveredRow' | 'focusedCell' | 'editingCell', detail: {
105
+ prev: any;
106
+ current: any;
107
+ }) => void) | null;
90
108
  get items(): T[];
91
109
  set items(value: T[]);
92
110
  get columns(): Column<T>[];
93
111
  set columns(value: Column<T>[]);
94
112
  get sortMode(): SortMode;
95
113
  set sortMode(value: SortMode);
96
- /** @deprecated Use sortMode instead. sortable=true maps to sortMode="multi", sortable=false maps to sortMode="none" */
97
- get sortable(): boolean;
98
- set sortable(value: boolean);
99
114
  get filterable(): boolean;
100
115
  set filterable(value: boolean);
101
116
  get pageable(): boolean;
@@ -139,20 +154,39 @@ export declare class WebGrid<T = unknown> {
139
154
  get editingCell(): EditingCell;
140
155
  get isValidating(): boolean;
141
156
  get currentCellError(): string | null;
157
+ get hoveredRowIndex(): number | null;
142
158
  get showRowToolbar(): boolean;
143
159
  set showRowToolbar(value: boolean);
144
160
  get rowToolbar(): RowToolbarConfig<T>[];
145
161
  set rowToolbar(value: RowToolbarConfig<T>[]);
146
- get toolbarAlign(): 'center' | 'top';
147
- set toolbarAlign(value: 'center' | 'top');
162
+ get toolbarVerticalAlign(): 'top' | 'center' | 'bottom';
163
+ set toolbarVerticalAlign(value: 'top' | 'center' | 'bottom');
164
+ get toolbarHorizontalAlign(): 'start' | 'center' | 'end' | 'cursor';
165
+ set toolbarHorizontalAlign(value: 'start' | 'center' | 'end' | 'cursor');
166
+ get toolbarAlign(): 'top' | 'center' | 'bottom';
167
+ set toolbarAlign(value: 'top' | 'center' | 'bottom');
148
168
  get toolbarTopPosition(): 'start' | 'center' | 'end' | 'cursor';
149
169
  set toolbarTopPosition(value: 'start' | 'center' | 'end' | 'cursor');
150
170
  get toolbarTrigger(): 'hover' | 'click' | 'button';
151
171
  set toolbarTrigger(value: 'hover' | 'click' | 'button');
152
- get toolbarPosition(): 'auto' | 'left' | 'right' | 'top';
153
- set toolbarPosition(value: 'auto' | 'left' | 'right' | 'top');
172
+ get toolbarPosition(): ToolbarPosition;
173
+ set toolbarPosition(value: ToolbarPosition);
174
+ get inlineActionsTitle(): string;
175
+ set inlineActionsTitle(value: string);
154
176
  get contextMenu(): ContextMenuItem<T>[] | undefined;
155
177
  set contextMenu(value: ContextMenuItem<T>[] | undefined);
178
+ get contextMenuXOffset(): number;
179
+ set contextMenuXOffset(value: number);
180
+ get contextMenuYOffset(): number;
181
+ set contextMenuYOffset(value: number);
182
+ get rowShortcuts(): RowShortcut<T>[] | undefined;
183
+ set rowShortcuts(value: RowShortcut<T>[] | undefined);
184
+ get showShortcutsHelp(): boolean;
185
+ set showShortcutsHelp(value: boolean);
186
+ get shortcutsHelpPosition(): 'top-right' | 'top-left';
187
+ set shortcutsHelpPosition(value: 'top-right' | 'top-left');
188
+ get shortcutsHelpContentCallback(): (() => string) | undefined;
189
+ set shortcutsHelpContentCallback(value: (() => string) | undefined);
156
190
  get sort(): SortState[];
157
191
  set sort(value: SortState[]);
158
192
  get currentPage(): number;
@@ -179,6 +213,8 @@ export declare class WebGrid<T = unknown> {
179
213
  set customStylesCallback(value: (() => string) | undefined);
180
214
  get rowClassCallback(): ((row: T, rowIndex: number) => string | null) | undefined;
181
215
  set rowClassCallback(value: ((row: T, rowIndex: number) => string | null) | undefined);
216
+ get labels(): GridLabels;
217
+ set labels(value: Partial<GridLabels>);
182
218
  get virtualScroll(): boolean;
183
219
  set virtualScroll(value: boolean);
184
220
  get virtualScrollThreshold(): number;
@@ -236,6 +272,14 @@ export declare class WebGrid<T = unknown> {
236
272
  rowIndex: number;
237
273
  row: T;
238
274
  }) => void) | undefined);
275
+ get idValueMember(): keyof T | undefined;
276
+ set idValueMember(value: keyof T | undefined);
277
+ get idValueCallback(): ((row: T) => unknown) | undefined;
278
+ set idValueCallback(value: ((row: T) => unknown) | undefined);
279
+ get rowLocking(): RowLockingOptions<T> | undefined;
280
+ set rowLocking(value: RowLockingOptions<T> | undefined);
281
+ get onrowlockchange(): ((detail: RowLockChangeDetail<T>) => void) | undefined;
282
+ set onrowlockchange(value: ((detail: RowLockChangeDetail<T>) => void) | undefined);
239
283
  get isNavigateMode(): boolean;
240
284
  get filteredItems(): T[];
241
285
  get sortedItems(): T[];
@@ -327,5 +371,57 @@ export declare class WebGrid<T = unknown> {
327
371
  * NOTE: Does NOT call requestUpdate() - GridElement handles DOM updates surgically
328
372
  */
329
373
  clearFocusedCell(): void;
374
+ /**
375
+ * Set the hovered row index (for toolbar/shortcuts)
376
+ * NOTE: Does NOT call requestUpdate() - GridElement handles UI updates
377
+ */
378
+ setHoveredRow(rowIndex: number | null): void;
379
+ /**
380
+ * Get the unique ID for a row using configured idValueMember/idValueCallback
381
+ */
382
+ getRowId(row: T): unknown | undefined;
383
+ /**
384
+ * Find a row by its ID
385
+ */
386
+ findRowById(id: unknown): {
387
+ row: T;
388
+ index: number;
389
+ } | null;
390
+ /**
391
+ * Get lock info for a row (combines all sources: external, callback, property)
392
+ */
393
+ getRowLockInfo(rowOrId: T | unknown): RowLockInfo | null;
394
+ /**
395
+ * Check if a row is locked
396
+ */
397
+ isRowLocked(rowOrId: T | unknown): boolean;
398
+ /**
399
+ * Lock a row by ID (external lock for WebSocket scenarios)
400
+ */
401
+ lockRowById(id: unknown, lockerInfo?: Partial<RowLockInfo>): boolean;
402
+ /**
403
+ * Unlock a row by ID
404
+ */
405
+ unlockRowById(id: unknown): boolean;
406
+ /**
407
+ * Get all external locks (for debugging/inspection)
408
+ */
409
+ getExternalLocks(): Map<unknown, RowLockInfo>;
410
+ /**
411
+ * Clear all external locks
412
+ */
413
+ clearExternalLocks(): void;
414
+ /**
415
+ * Update a row's data by ID (partial update, preserves other fields)
416
+ */
417
+ updateRowById(id: unknown, newData: Partial<T>): boolean;
418
+ /**
419
+ * Replace entire row by ID
420
+ */
421
+ replaceRowById(id: unknown, newRow: T): boolean;
422
+ /**
423
+ * Check if a cell can be edited (respects lock state)
424
+ */
425
+ canEditCell(rowIndex: number, field: string): boolean;
330
426
  }
331
427
  export default WebGrid;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { GridElement } from './web-component.js';
2
2
  export { WebGrid } from './grid.js';
3
- export type { EditorType, EditTrigger, OptionsLoadTrigger, DateOutputFormat, EditorOption, EditorOptions, CustomEditorContext, CellValidationState, ValidationResult, BeforeCommitContext, BeforeCommitResult, Column, CellRenderCallback, RowChangeDetail, PredefinedToolbarItemType, RowToolbarItem, RowToolbarConfig, NormalizedToolbarItem, ToolbarClickDetail, RowActionType, RowActionClickDetail, ContextMenuContext, ContextMenuItem, QuickGridProps, SortState, DataRequestDetail, DataRequestTrigger, EditingCell, FocusedCell, SortDirection, ToolbarRowGroup, PopupPosition, ConnectorArrowDir } from './types.js';
3
+ export type { EditorType, EditTrigger, OptionsLoadTrigger, DateOutputFormat, EditorOption, EditorOptions, CustomEditorContext, CellValidationState, ValidationResult, BeforeCommitContext, BeforeCommitResult, Column, CellRenderCallback, RowChangeDetail, PredefinedToolbarItemType, ToolbarPosition, ToolbarTooltip, RowToolbarItem, RowToolbarConfig, NormalizedToolbarItem, ToolbarClickDetail, RowActionType, RowActionClickDetail, ContextMenuContext, ContextMenuItem, QuickGridProps, SortState, DataRequestDetail, DataRequestTrigger, GridLabels, RowLockInfo, RowLockingOptions, RowLockChangeDetail, LockedRowEditBehavior, EditingCell, FocusedCell, SortDirection, ToolbarRowGroup, PopupPosition, ConnectorArrowDir } from './types.js';
4
4
  export { GridElement as default } from './web-component.js';
@@ -3,7 +3,7 @@ import type { GridContext } from '../types.js';
3
3
  /**
4
4
  * Open context menu at position
5
5
  */
6
- export declare function openContextMenu<T>(ctx: GridContext<T>, x: number, y: number, items: ContextMenuItem<T>[], menuContext: ContextMenuContext<T>, onItemClick: (itemId: string) => void, onClose: () => void): HTMLElement | null;
6
+ export declare function openContextMenu<T>(ctx: GridContext<T>, x: number, y: number, xOffset: number, yOffset: number, items: ContextMenuItem<T>[], menuContext: ContextMenuContext<T>, onItemClick: (itemId: string) => void, onClose: () => void): HTMLElement | null;
7
7
  /**
8
8
  * Close context menu and cleanup
9
9
  */
@@ -1,2 +1,2 @@
1
- export { commitCurrentEditor, handleCheckboxChange, toggleCheckboxAndMove, handleEditorBlur, moveFocusAfterCommit, focusCellAfterCancel } from './lifecycle.js';
1
+ export { commitCurrentEditor, handleCheckboxChange, toggleCheckboxAndMove, handleEditorBlur, moveFocusAfterCommit, focusCellAfterCancel, restoreCellToDisplayMode } from './lifecycle.js';
2
2
  export { renderCellEditor, renderTextEditor, renderNumberEditor, renderCheckboxEditor, renderSelectEditor, renderComboboxEditor, renderAutocompleteEditor } from './renderers.js';
@@ -1,4 +1,9 @@
1
1
  import type { GridContext } from '../types.js';
2
+ /**
3
+ * Surgically restore a cell from editing mode to display mode.
4
+ * Uses centralized renderCell() to ensure all states are correct.
5
+ */
6
+ export declare function restoreCellToDisplayMode<T>(ctx: GridContext<T>, rowIndex: number, colIndex: number): void;
2
7
  /**
3
8
  * Commit the value from the current editor
4
9
  */
@@ -12,15 +12,21 @@ export declare function focusCellElement<T>(ctx: GridContext<T>, rowIndex: numbe
12
12
  export declare function scrollToRowPosition<T>(ctx: GridContext<T>, rowIndex: number): void;
13
13
  /**
14
14
  * Update focus visual state surgically (without full re-render)
15
- * This directly manipulates CSS classes on existing DOM elements
15
+ * Uses centralized renderCell() to ensure all states are correct
16
16
  */
17
17
  export declare function updateFocusVisual<T>(ctx: GridContext<T>, oldFocus: FocusedCell | null, newFocus: FocusedCell | null): void;
18
18
  /**
19
19
  * Surgically remove the editing visual (blue border) from current editing cell.
20
- * Call this BEFORE cancelEdit() to ensure the DOM class is removed immediately,
21
- * rather than waiting for the async re-render.
20
+ * Call this BEFORE cancelEdit() to ensure the DOM class is removed immediately.
21
+ * NOTE: This just removes the class - full cell restoration happens via renderCell()
22
+ * after cancelEdit() clears the state.
22
23
  */
23
24
  export declare function clearEditingVisual<T>(ctx: GridContext<T>): void;
25
+ /**
26
+ * Fully restore an editing cell to display mode.
27
+ * Must be called AFTER cancelEdit() so the cell renders in display mode.
28
+ */
29
+ export declare function restoreEditingCellToDisplayMode<T>(ctx: GridContext<T>, rowIndex: number, colIndex: number): void;
24
30
  /**
25
31
  * Handle cell focus event
26
32
  */
@@ -31,6 +37,7 @@ export declare function handleCellFocus<T>(ctx: GridContext<T>, rowIndex: number
31
37
  export declare function moveFocus<T>(ctx: GridContext<T>, newRowIndex: number, newColIndex: number): void;
32
38
  /**
33
39
  * Try to start editing a cell (checks if editable first)
40
+ * Uses centralized renderCell() for surgical DOM update
34
41
  */
35
42
  export declare function tryStartEdit<T>(ctx: GridContext<T>, rowIndex: number, colIndex: number, options?: {
36
43
  initialSearchQuery?: string;
@@ -0,0 +1,19 @@
1
+ import type { GridContext } from '../types.js';
2
+ export type RenderCellOptions = {
3
+ /** Focus the editor after rendering (for edit mode) */
4
+ focusEditor?: boolean;
5
+ /** Cursor position for text inputs */
6
+ cursorPosition?: number;
7
+ /** Initial search query (type-to-start) */
8
+ initialSearchQuery?: string;
9
+ };
10
+ /**
11
+ * Surgically update a single cell's DOM based on current grid state.
12
+ * This is the single source of truth for cell appearance.
13
+ *
14
+ * Handles:
15
+ * - All CSS classes (focused, editing, editable, invalid, etc.)
16
+ * - Cell content (editor vs display mode)
17
+ * - Editor focus and cursor positioning
18
+ */
19
+ export declare function renderCell<T>(ctx: GridContext<T>, rowIndex: number, colIndex: number, options?: RenderCellOptions): void;
@@ -1,3 +1,5 @@
1
1
  export { getContainerClasses, renderHeaderRow, renderDataRows, renderDataRowsVirtual, renderPagination, renderSummary } from './table.js';
2
2
  export type { VirtualScrollParams } from './table.js';
3
3
  export { renderCellDisplay } from './display.js';
4
+ export { renderCell } from './cell.js';
5
+ export type { RenderCellOptions } from './cell.js';
@@ -12,10 +12,18 @@ export type ConnectorState = {
12
12
  * Convert toolbar config (strings or objects) to normalized items
13
13
  */
14
14
  export declare function normalizeToolbarItems<T>(config: RowToolbarConfig<T>[]): NormalizedToolbarItem<T>[];
15
+ /**
16
+ * Build rich tooltip HTML for a toolbar item
17
+ * @param item - The toolbar item
18
+ * @param shortcutKey - Optional keyboard shortcut from rowShortcuts
19
+ */
20
+ export declare function buildToolbarTooltipHtml<T>(item: NormalizedToolbarItem<T>, shortcutKey?: string): string;
15
21
  /**
16
22
  * Render toolbar HTML for a specific row
23
+ * @param reverseRows - If true, reverse row order so Row 1 ends up at top visually
24
+ * (CSS column-reverse makes last HTML row appear at top)
17
25
  */
18
- export declare function renderToolbarHTML<T>(items: NormalizedToolbarItem<T>[], row: T, rowIndex: number): string;
26
+ export declare function renderToolbarHTML<T>(items: NormalizedToolbarItem<T>[], row: T, rowIndex: number, reverseRows?: boolean): string;
19
27
  /**
20
28
  * Open toolbar for a specific row
21
29
  */
@@ -53,4 +61,4 @@ export declare function updateConnector<T>(ctx: GridContext<T>, displayItems: T[
53
61
  /**
54
62
  * Render the toolbar trigger button HTML
55
63
  */
56
- export declare function renderTriggerButton(rowIndex: number, isActive: boolean): string;
64
+ export declare function renderTriggerButton(rowIndex: number, isActive: boolean, title?: string): string;
package/dist/types.d.ts CHANGED
@@ -38,6 +38,8 @@ export type EditorOptions<T = unknown> = {
38
38
  onselect?: (option: EditorOption, row: T) => void;
39
39
  allowEmpty?: boolean;
40
40
  emptyLabel?: string;
41
+ noOptionsText?: string;
42
+ searchingText?: string;
41
43
  maxLength?: number;
42
44
  placeholder?: string;
43
45
  pattern?: string;
@@ -138,6 +140,11 @@ export type RowChangeDetail<T> = {
138
140
  validationError?: string | null;
139
141
  };
140
142
  export type PredefinedToolbarItemType = 'add' | 'delete' | 'duplicate' | 'moveUp' | 'moveDown';
143
+ export type ToolbarPosition = 'auto' | 'left' | 'right' | 'top' | 'inline';
144
+ export type ToolbarTooltip = {
145
+ description?: string;
146
+ shortcut?: string;
147
+ };
141
148
  export type RowToolbarItem<T> = {
142
149
  id: string;
143
150
  icon: string;
@@ -148,13 +155,19 @@ export type RowToolbarItem<T> = {
148
155
  type?: PredefinedToolbarItemType;
149
156
  danger?: boolean;
150
157
  disabled?: boolean | ((row: T, rowIndex: number) => boolean);
158
+ hidden?: boolean | ((row: T, rowIndex: number) => boolean);
159
+ tooltip?: ToolbarTooltip;
160
+ tooltipCallback?: (row: T, rowIndex: number) => string;
151
161
  onclick?: (detail: {
152
162
  row: T;
153
163
  rowIndex: number;
154
164
  }) => void | Promise<void>;
155
165
  };
156
166
  export type RowToolbarConfig<T> = PredefinedToolbarItemType | RowToolbarItem<T>;
157
- export type NormalizedToolbarItem<T> = Required<Pick<RowToolbarItem<T>, 'id' | 'icon' | 'title' | 'row' | 'group'>> & Omit<RowToolbarItem<T>, 'id' | 'icon' | 'title' | 'row' | 'group'>;
167
+ export type NormalizedToolbarItem<T> = Required<Pick<RowToolbarItem<T>, 'id' | 'icon' | 'title' | 'row' | 'group'>> & Omit<RowToolbarItem<T>, 'id' | 'icon' | 'title' | 'row' | 'group'> & {
168
+ tooltip?: ToolbarTooltip;
169
+ tooltipCallback?: (row: T, rowIndex: number) => string;
170
+ };
158
171
  export type ToolbarClickDetail<T> = {
159
172
  item: NormalizedToolbarItem<T>;
160
173
  rowIndex: number;
@@ -177,17 +190,37 @@ export type ContextMenuItem<T> = {
177
190
  id: string;
178
191
  label: string | ((context: ContextMenuContext<T>) => string);
179
192
  icon?: string | ((context: ContextMenuContext<T>) => string);
193
+ shortcut?: string;
180
194
  disabled?: boolean | ((context: ContextMenuContext<T>) => boolean);
181
195
  visible?: boolean | ((context: ContextMenuContext<T>) => boolean);
182
196
  danger?: boolean;
183
197
  dividerBefore?: boolean;
184
198
  onclick?: (context: ContextMenuContext<T>) => void | Promise<void>;
185
199
  };
200
+ export type ShortcutContext<T> = {
201
+ row: T;
202
+ rowIndex: number;
203
+ colIndex: number;
204
+ column: Column<T>;
205
+ cellValue: unknown;
206
+ };
207
+ export type RowShortcut<T> = {
208
+ key: string;
209
+ id: string;
210
+ label: string;
211
+ action: (ctx: ShortcutContext<T>) => void | Promise<void>;
212
+ disabled?: boolean | ((ctx: ShortcutContext<T>) => boolean);
213
+ };
214
+ export type ParsedKeyCombo = {
215
+ key: string;
216
+ ctrl: boolean;
217
+ shift: boolean;
218
+ alt: boolean;
219
+ meta: boolean;
220
+ };
186
221
  export type QuickGridProps<T> = {
187
222
  items: T[];
188
223
  columns: Column<T>[];
189
- /** @deprecated Use sortMode instead */
190
- sortable?: boolean;
191
224
  filterable?: boolean;
192
225
  pageable?: boolean;
193
226
  pageSize?: number;
@@ -221,14 +254,23 @@ export type QuickGridProps<T> = {
221
254
  invalidCells?: CellValidationState[];
222
255
  showRowToolbar?: boolean;
223
256
  rowToolbar?: RowToolbarConfig<T>[];
224
- toolbarAlign?: 'center' | 'top';
225
- toolbarTopPosition?: 'start' | 'center' | 'end' | 'cursor';
257
+ toolbarVerticalAlign?: 'top' | 'center' | 'bottom';
258
+ toolbarHorizontalAlign?: 'start' | 'center' | 'end' | 'cursor';
226
259
  toolbarTrigger?: 'hover' | 'click' | 'button';
227
- toolbarPosition?: 'auto' | 'left' | 'right' | 'top';
260
+ toolbarPosition?: ToolbarPosition;
261
+ inlineActionsTitle?: string;
228
262
  showRowActions?: boolean;
229
263
  rowActions?: RowToolbarConfig<T>[];
264
+ toolbarAlign?: 'top' | 'center' | 'bottom';
265
+ toolbarTopPosition?: 'start' | 'center' | 'end' | 'cursor';
230
266
  contextMenu?: ContextMenuItem<T>[];
267
+ contextMenuXOffset?: number;
268
+ contextMenuYOffset?: number;
231
269
  oncontextmenuopen?: (context: ContextMenuContext<T>) => void;
270
+ rowShortcuts?: RowShortcut<T>[];
271
+ showShortcutsHelp?: boolean;
272
+ shortcutsHelpPosition?: 'top-right' | 'top-left';
273
+ shortcutsHelpContentCallback?: () => string;
232
274
  virtualScroll?: boolean;
233
275
  virtualScrollThreshold?: number;
234
276
  virtualScrollRowHeight?: number;
@@ -314,6 +356,20 @@ export type PaginationLabelsContext = {
314
356
  pageSize: number;
315
357
  };
316
358
  export type PaginationLabelsCallback = (context: PaginationLabelsContext) => Partial<PaginationLabels>;
359
+ export type GridLabels = {
360
+ rowActions: string;
361
+ inlineActionsHeader: string;
362
+ keyboardShortcuts: string;
363
+ paginationFirst: string;
364
+ paginationPrevious: string;
365
+ paginationNext: string;
366
+ paginationLast: string;
367
+ paginationPageInfo: string;
368
+ paginationItemCount: string;
369
+ paginationPerPage: string;
370
+ dropdownNoOptions: string;
371
+ dropdownSearching: string;
372
+ };
317
373
  export type SummaryContext<T> = {
318
374
  items: T[];
319
375
  allItems: T[];
@@ -323,3 +379,27 @@ export type SummaryContext<T> = {
323
379
  metadata: unknown;
324
380
  };
325
381
  export type SummaryContentCallback<T> = (context: SummaryContext<T>) => string;
382
+ export type RowLockInfo = {
383
+ isLocked: boolean;
384
+ lockedBy?: string;
385
+ lockedAt?: Date | string;
386
+ reason?: string;
387
+ [key: string]: unknown;
388
+ };
389
+ export type LockedRowEditBehavior = 'block' | 'allow' | 'callback';
390
+ export type RowLockingOptions<T> = {
391
+ lockedMember?: keyof T;
392
+ lockInfoMember?: keyof T;
393
+ isLockedCallback?: (row: T, rowIndex: number) => boolean;
394
+ getLockInfoCallback?: (row: T, rowIndex: number) => RowLockInfo | null;
395
+ lockedEditBehavior?: LockedRowEditBehavior;
396
+ canEditLockedCallback?: (row: T, lockInfo: RowLockInfo) => boolean;
397
+ lockTooltipCallback?: (lockInfo: RowLockInfo, row: T) => string | null;
398
+ };
399
+ export type RowLockChangeDetail<T> = {
400
+ rowId: unknown;
401
+ row: T | null;
402
+ rowIndex: number;
403
+ lockInfo: RowLockInfo | null;
404
+ source: 'property' | 'callback' | 'external';
405
+ };
@@ -1,5 +1,5 @@
1
1
  import { WebGrid } from './grid.js';
2
- import type { Column, CellValidationState, RowToolbarConfig, ContextMenuItem, RowChangeDetail, ToolbarClickDetail, RowActionClickDetail, ContextMenuContext, EditTrigger, EditStartSelection, EditorOption, EditorOptions, GridMode, ToggleVisibility, DataRequestDetail, SortState, SortMode, PaginationLabelsCallback, SummaryContentCallback, ValidationTooltipContext } from './types.js';
2
+ import type { Column, CellValidationState, RowToolbarConfig, ContextMenuItem, RowShortcut, RowChangeDetail, ToolbarClickDetail, RowActionClickDetail, ContextMenuContext, EditTrigger, EditStartSelection, EditorOption, EditorOptions, GridMode, ToggleVisibility, DataRequestDetail, SortState, SortMode, PaginationLabelsCallback, SummaryContentCallback, ValidationTooltipContext, ToolbarPosition, GridLabels, RowLockInfo, RowLockingOptions, RowLockChangeDetail } from './types.js';
3
3
  import type { GridContext } from './modules/types.js';
4
4
  /**
5
5
  * GridElement - Custom HTML Element for WebGrid
@@ -31,6 +31,8 @@ export declare class GridElement<T = unknown> extends HTMLElement implements Gri
31
31
  private toolbarMoveInProgress;
32
32
  private toolbarHideTimeout;
33
33
  private toolbarHovered;
34
+ private toolbarShortcutHandler;
35
+ private inlineShortcutHandler;
34
36
  dropdownOpen: boolean;
35
37
  dropdownOptions: EditorOption[];
36
38
  highlightedIndex: number;
@@ -38,6 +40,7 @@ export declare class GridElement<T = unknown> extends HTMLElement implements Gri
38
40
  isUserFiltering: boolean;
39
41
  justSelected: boolean;
40
42
  isOpeningDropdown: boolean;
43
+ private isProgrammaticScroll;
41
44
  searchDebounceTimer: ReturnType<typeof setTimeout> | null;
42
45
  searchAbortController: AbortController | null;
43
46
  isSearching: boolean;
@@ -65,8 +68,6 @@ export declare class GridElement<T = unknown> extends HTMLElement implements Gri
65
68
  set items(value: T[]);
66
69
  get columns(): Column<T>[];
67
70
  set columns(value: Column<T>[]);
68
- get sortable(): boolean;
69
- set sortable(value: boolean);
70
71
  get filterable(): boolean;
71
72
  set filterable(value: boolean);
72
73
  get pageable(): boolean;
@@ -103,16 +104,34 @@ export declare class GridElement<T = unknown> extends HTMLElement implements Gri
103
104
  set showRowToolbar(value: boolean);
104
105
  get rowToolbar(): RowToolbarConfig<T>[];
105
106
  set rowToolbar(value: RowToolbarConfig<T>[]);
106
- get toolbarAlign(): 'center' | 'top';
107
- set toolbarAlign(value: 'center' | 'top');
107
+ get toolbarVerticalAlign(): 'top' | 'center' | 'bottom';
108
+ set toolbarVerticalAlign(value: 'top' | 'center' | 'bottom');
109
+ get toolbarHorizontalAlign(): 'start' | 'center' | 'end' | 'cursor';
110
+ set toolbarHorizontalAlign(value: 'start' | 'center' | 'end' | 'cursor');
111
+ get toolbarAlign(): 'top' | 'center' | 'bottom';
112
+ set toolbarAlign(value: 'top' | 'center' | 'bottom');
108
113
  get toolbarTopPosition(): 'start' | 'center' | 'end' | 'cursor';
109
114
  set toolbarTopPosition(value: 'start' | 'center' | 'end' | 'cursor');
110
115
  get toolbarTrigger(): 'hover' | 'click' | 'button';
111
116
  set toolbarTrigger(value: 'hover' | 'click' | 'button');
112
- get toolbarPosition(): 'auto' | 'left' | 'right' | 'top';
113
- set toolbarPosition(value: 'auto' | 'left' | 'right' | 'top');
117
+ get toolbarPosition(): ToolbarPosition;
118
+ set toolbarPosition(value: ToolbarPosition);
119
+ get inlineActionsTitle(): string;
120
+ set inlineActionsTitle(value: string);
114
121
  get contextMenu(): ContextMenuItem<T>[] | undefined;
115
122
  set contextMenu(value: ContextMenuItem<T>[] | undefined);
123
+ get contextMenuXOffset(): number;
124
+ set contextMenuXOffset(value: number);
125
+ get contextMenuYOffset(): number;
126
+ set contextMenuYOffset(value: number);
127
+ get rowShortcuts(): RowShortcut<T>[] | undefined;
128
+ set rowShortcuts(value: RowShortcut<T>[] | undefined);
129
+ get showShortcutsHelp(): boolean;
130
+ set showShortcutsHelp(value: boolean);
131
+ get shortcutsHelpPosition(): 'top-right' | 'top-left';
132
+ set shortcutsHelpPosition(value: 'top-right' | 'top-left');
133
+ get shortcutsHelpContentCallback(): (() => string) | undefined;
134
+ set shortcutsHelpContentCallback(value: (() => string) | undefined);
116
135
  get showRowActions(): boolean;
117
136
  set showRowActions(value: boolean);
118
137
  get rowActions(): RowToolbarConfig<T>[];
@@ -173,10 +192,20 @@ export declare class GridElement<T = unknown> extends HTMLElement implements Gri
173
192
  set customStylesCallback(value: (() => string) | undefined);
174
193
  get rowClassCallback(): ((row: T, rowIndex: number) => string | null) | undefined;
175
194
  set rowClassCallback(value: ((row: T, rowIndex: number) => string | null) | undefined);
195
+ get labels(): GridLabels;
196
+ set labels(value: Partial<GridLabels>);
176
197
  get summaryMetadata(): unknown;
177
198
  set summaryMetadata(value: unknown);
178
199
  get summaryInline(): boolean;
179
200
  set summaryInline(value: boolean);
201
+ get idValueMember(): keyof T | undefined;
202
+ set idValueMember(value: keyof T | undefined);
203
+ get idValueCallback(): ((row: T) => unknown) | undefined;
204
+ set idValueCallback(value: ((row: T) => unknown) | undefined);
205
+ get rowLocking(): RowLockingOptions<T> | undefined;
206
+ set rowLocking(value: RowLockingOptions<T> | undefined);
207
+ get onrowlockchange(): ((detail: RowLockChangeDetail<T>) => void) | undefined;
208
+ set onrowlockchange(value: ((detail: RowLockChangeDetail<T>) => void) | undefined);
180
209
  get virtualScroll(): boolean;
181
210
  set virtualScroll(value: boolean);
182
211
  get virtualScrollThreshold(): number;
@@ -201,6 +230,30 @@ export declare class GridElement<T = unknown> extends HTMLElement implements Gri
201
230
  discardAllDrafts(): void;
202
231
  isCellInvalid(rowIndex: number, field: string): boolean;
203
232
  getCellValidationError(rowIndex: number, field: string): string | null;
233
+ getRowId(row: T): unknown | undefined;
234
+ findRowById(id: unknown): {
235
+ row: T;
236
+ index: number;
237
+ } | null;
238
+ isRowLocked(rowOrId: T | unknown): boolean;
239
+ getRowLockInfo(rowOrId: T | unknown): RowLockInfo | null;
240
+ lockRowById(id: unknown, lockerInfo?: Partial<RowLockInfo>): boolean;
241
+ unlockRowById(id: unknown): boolean;
242
+ getExternalLocks(): Map<unknown, RowLockInfo>;
243
+ clearExternalLocks(): void;
244
+ updateRowById(id: unknown, newData: Partial<T>): boolean;
245
+ replaceRowById(id: unknown, newRow: T): boolean;
246
+ canEditCell(rowIndex: number, field: string): boolean;
247
+ /**
248
+ * Programmatically focus a cell. Updates state and focuses the DOM element.
249
+ * State is updated immediately so pending renders use the correct position.
250
+ */
251
+ focusCell(rowIndex: number, colIndex: number): void;
252
+ /**
253
+ * Programmatically start editing a cell.
254
+ * Uses surgical DOM update instead of full re-render.
255
+ */
256
+ startEditing(rowIndex: number, colIndex: number): void;
204
257
  escapeHtml(text: string): string;
205
258
  getCurrentEditingColumn(): Column<T> | null;
206
259
  getCurrentEditorOptions(): EditorOptions;
@@ -219,6 +272,12 @@ export declare class GridElement<T = unknown> extends HTMLElement implements Gri
219
272
  */
220
273
  private handleEditorKeyDown;
221
274
  private attachEventListeners;
275
+ /**
276
+ * Scroll to a row position programmatically (keyboard navigation).
277
+ * Pre-renders the target row range ONCE, then scrolls. Flag prevents
278
+ * the scroll event from redundantly calling handleVirtualScroll.
279
+ */
280
+ private scrollToRowProgrammatically;
222
281
  /**
223
282
  * Handle virtual scroll - recalculate visible range and re-render if changed
224
283
  */
@@ -232,6 +291,10 @@ export declare class GridElement<T = unknown> extends HTMLElement implements Gri
232
291
  * Handle infinite scroll - trigger load more when near bottom
233
292
  */
234
293
  private handleInfiniteScroll;
294
+ /**
295
+ * Render the shortcuts help icon and overlay
296
+ */
297
+ private renderShortcutsHelpIcon;
235
298
  private render;
236
299
  /**
237
300
  * Render the SVG connector arrow for toolbar row tracking
@@ -265,6 +328,25 @@ export declare class GridElement<T = unknown> extends HTMLElement implements Gri
265
328
  * Handle context menu (right-click) on cells
266
329
  */
267
330
  private handleContextMenu;
331
+ /**
332
+ * Setup document-level keyboard shortcut listener for toolbar row
333
+ * Allows shortcuts to work on hovered row without cell focus
334
+ */
335
+ private setupToolbarShortcuts;
336
+ /**
337
+ * Setup keyboard shortcuts for inline toolbar mode
338
+ * Uses hoveredRowIndex to determine which row to act on
339
+ */
340
+ private setupInlineShortcuts;
341
+ /**
342
+ * Remove inline shortcuts listener
343
+ */
344
+ private removeInlineShortcuts;
345
+ /**
346
+ * Setup rich tooltips for toolbar buttons
347
+ * Shows title, description, and keyboard shortcut on hover
348
+ */
349
+ private setupToolbarTooltips;
268
350
  /**
269
351
  * Show toolbar for a specific row
270
352
  */
@@ -277,6 +359,10 @@ export declare class GridElement<T = unknown> extends HTMLElement implements Gri
277
359
  * Handle toolbar item click
278
360
  */
279
361
  private handleToolbarItemClick;
362
+ /**
363
+ * Handle inline action button click (toolbarPosition="inline")
364
+ */
365
+ private handleInlineActionClick;
280
366
  /**
281
367
  * Handle paste event in navigate mode
282
368
  */