@alaarab/ogrid-js 2.1.1 → 2.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/esm/OGrid.js CHANGED
@@ -131,6 +131,8 @@ export class OGrid {
131
131
  this.contextMenu = null;
132
132
  this.events = new EventEmitter();
133
133
  this.unsubscribes = [];
134
+ this.isFullScreen = false;
135
+ this.fullscreenBtn = null;
134
136
  this.options = options;
135
137
  this.state = new GridState(options);
136
138
  this.api = this.state.getApi();
@@ -146,6 +148,29 @@ export class OGrid {
146
148
  // Left spacer keeps column chooser on the right via justify-content: space-between
147
149
  const toolbarSpacer = document.createElement('div');
148
150
  this.toolbarEl.appendChild(toolbarSpacer);
151
+ // Fullscreen toggle button
152
+ if (options.fullScreen) {
153
+ const toolbarRight = document.createElement('div');
154
+ toolbarRight.style.display = 'flex';
155
+ toolbarRight.style.alignItems = 'center';
156
+ toolbarRight.style.gap = '8px';
157
+ this.fullscreenBtn = document.createElement('button');
158
+ this.fullscreenBtn.type = 'button';
159
+ this.fullscreenBtn.className = 'ogrid-fullscreen-btn';
160
+ this.fullscreenBtn.title = 'Fullscreen';
161
+ this.fullscreenBtn.setAttribute('aria-label', 'Fullscreen');
162
+ this.fullscreenBtn.innerHTML = '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="10 2 14 2 14 6"/><polyline points="6 14 2 14 2 10"/><line x1="14" y1="2" x2="10" y2="6"/><line x1="2" y1="14" x2="6" y2="10"/></svg>';
163
+ this.fullscreenBtn.addEventListener('click', () => this.toggleFullScreen());
164
+ toolbarRight.appendChild(this.fullscreenBtn);
165
+ this.toolbarEl.appendChild(toolbarRight);
166
+ // ESC key to exit fullscreen
167
+ const handleEscKey = (e) => {
168
+ if (e.key === 'Escape' && this.isFullScreen)
169
+ this.toggleFullScreen();
170
+ };
171
+ document.addEventListener('keydown', handleEscKey);
172
+ this.unsubscribes.push(() => document.removeEventListener('keydown', handleEscKey));
173
+ }
149
174
  this.containerEl.appendChild(this.toolbarEl);
150
175
  // Body area (holds sidebar + table, side by side)
151
176
  this.bodyArea = document.createElement('div');
@@ -504,6 +529,24 @@ export class OGrid {
504
529
  off(event, handler) {
505
530
  this.events.off(event, handler);
506
531
  }
532
+ /** Toggle fullscreen mode. */
533
+ toggleFullScreen() {
534
+ this.isFullScreen = !this.isFullScreen;
535
+ if (this.isFullScreen) {
536
+ this.containerEl.classList.add('ogrid-fullscreen');
537
+ }
538
+ else {
539
+ this.containerEl.classList.remove('ogrid-fullscreen');
540
+ }
541
+ // Update button icon + label
542
+ if (this.fullscreenBtn) {
543
+ this.fullscreenBtn.title = this.isFullScreen ? 'Exit fullscreen' : 'Fullscreen';
544
+ this.fullscreenBtn.setAttribute('aria-label', this.isFullScreen ? 'Exit fullscreen' : 'Fullscreen');
545
+ this.fullscreenBtn.innerHTML = this.isFullScreen
546
+ ? '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 10 0 10 0 14"/><polyline points="12 6 16 6 16 2"/><line x1="0" y1="10" x2="4" y2="6"/><line x1="16" y1="6" x2="12" y2="10"/></svg>'
547
+ : '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="10 2 14 2 14 6"/><polyline points="6 14 2 14 2 10"/><line x1="14" y1="2" x2="10" y2="6"/><line x1="2" y1="14" x2="6" y2="10"/></svg>';
548
+ }
549
+ }
507
550
  /** Clean up all event listeners and DOM. */
508
551
  destroy() {
509
552
  this.unsubscribes.forEach((unsub) => unsub());
@@ -192,6 +192,9 @@ export class TableRenderer {
192
192
  this.table.className = 'ogrid-table';
193
193
  // Render header
194
194
  this.thead = document.createElement('thead');
195
+ if (this.state.stickyHeader) {
196
+ this.thead.classList.add('ogrid-sticky-header');
197
+ }
195
198
  this.renderHeader();
196
199
  this.attachHeaderDelegation();
197
200
  this.table.appendChild(this.thead);
@@ -33,6 +33,8 @@ export class GridState {
33
33
  this._onFirstDataRendered = options.onFirstDataRendered;
34
34
  this._rowHeight = options.rowHeight;
35
35
  this._ariaLabel = options.ariaLabel;
36
+ this._stickyHeader = options.stickyHeader ?? true;
37
+ this._fullScreen = options.fullScreen ?? false;
36
38
  // Derive initial filter options for client-side data
37
39
  if (!this._dataSource) {
38
40
  this._filterOptions = deriveFilterOptionsFromData(this._data, this._columns);
@@ -61,6 +63,8 @@ export class GridState {
61
63
  get allColumns() { return this._allColumns; }
62
64
  get getRowId() { return this._getRowId; }
63
65
  get isServerSide() { return this._dataSource != null; }
66
+ get stickyHeader() { return this._stickyHeader; }
67
+ get fullScreen() { return this._fullScreen; }
64
68
  get filterOptions() { return this._filterOptions; }
65
69
  get columnOrder() { return this._columnOrder; }
66
70
  get rowHeight() { return this._rowHeight; }
@@ -128,6 +128,30 @@
128
128
  overflow: hidden;
129
129
  }
130
130
 
131
+ .ogrid-container.ogrid-fullscreen {
132
+ position: fixed;
133
+ inset: 0;
134
+ z-index: 9999;
135
+ border-radius: 0;
136
+ border: none;
137
+ }
138
+
139
+ .ogrid-fullscreen-btn {
140
+ background: none;
141
+ border: 1px solid var(--ogrid-border, #e0e0e0);
142
+ border-radius: 4px;
143
+ padding: 4px 6px;
144
+ cursor: pointer;
145
+ display: flex;
146
+ align-items: center;
147
+ justify-content: center;
148
+ color: var(--ogrid-fg, #242424);
149
+ }
150
+
151
+ .ogrid-fullscreen-btn:hover {
152
+ background: var(--ogrid-hover-bg, rgba(0, 0, 0, 0.04));
153
+ }
154
+
131
155
  .ogrid-toolbar {
132
156
  display: flex;
133
157
  align-items: center;
@@ -199,9 +223,12 @@
199
223
 
200
224
  .ogrid-table thead {
201
225
  background: var(--ogrid-bg-subtle, #f3f2f1);
226
+ z-index: 8;
227
+ }
228
+
229
+ .ogrid-table thead.ogrid-sticky-header {
202
230
  position: sticky;
203
231
  top: 0;
204
- z-index: 8;
205
232
  }
206
233
 
207
234
  .ogrid-table thead th {
@@ -378,6 +405,8 @@
378
405
  z-index: 6;
379
406
  background: var(--ogrid-bg, #fff);
380
407
  will-change: transform;
408
+ border-right: 1px solid var(--ogrid-border, rgba(0, 0, 0, 0.12));
409
+ box-shadow: 2px 0 4px -1px var(--ogrid-pinned-shadow, rgba(0, 0, 0, 0.1));
381
410
  }
382
411
 
383
412
  .ogrid-table thead th[data-pinned='left'] {
@@ -391,6 +420,8 @@
391
420
  z-index: 6;
392
421
  background: var(--ogrid-bg, #fff);
393
422
  will-change: transform;
423
+ border-left: 1px solid var(--ogrid-border, rgba(0, 0, 0, 0.12));
424
+ box-shadow: -2px 0 4px -1px var(--ogrid-pinned-shadow, rgba(0, 0, 0, 0.1));
394
425
  }
395
426
 
396
427
  .ogrid-table thead th[data-pinned='right'] {
@@ -128,6 +128,8 @@ export declare class OGrid<T> {
128
128
  private paginationContainer;
129
129
  private statusBarContainer;
130
130
  private options;
131
+ private isFullScreen;
132
+ private fullscreenBtn;
131
133
  private renderingHelper;
132
134
  private eventWiringHelper;
133
135
  /** The imperative grid API (extends React's IOGridApi with JS-specific methods). */
@@ -146,6 +148,8 @@ export declare class OGrid<T> {
146
148
  on<K extends keyof OGridEvents<T>>(event: K, handler: (data: OGridEvents<T>[K]) => void): void;
147
149
  /** Unsubscribe from grid events. */
148
150
  off<K extends keyof OGridEvents<T>>(event: K, handler: (data: OGridEvents<T>[K]) => void): void;
151
+ /** Toggle fullscreen mode. */
152
+ private toggleFullScreen;
149
153
  /** Clean up all event listeners and DOM. */
150
154
  destroy(): void;
151
155
  }
@@ -26,6 +26,8 @@ export declare class GridState<T> {
26
26
  private _firstDataRendered;
27
27
  private _rowHeight?;
28
28
  private _ariaLabel?;
29
+ private _stickyHeader;
30
+ private _fullScreen;
29
31
  private _filterOptions;
30
32
  private _columnOrder;
31
33
  private _visibleColsCache;
@@ -45,6 +47,8 @@ export declare class GridState<T> {
45
47
  get allColumns(): (IColumnDef<T> | IColumnGroupDef<T>)[];
46
48
  get getRowId(): (item: T) => RowId;
47
49
  get isServerSide(): boolean;
50
+ get stickyHeader(): boolean;
51
+ get fullScreen(): boolean;
48
52
  get filterOptions(): Record<string, string[]>;
49
53
  get columnOrder(): string[];
50
54
  get rowHeight(): number | undefined;
@@ -68,6 +68,10 @@ export interface OGridOptions<T> {
68
68
  /** Layout mode: 'content' sizes to content, 'fill' fills container. Default: 'fill'. */
69
69
  layoutMode?: 'content' | 'fill';
70
70
  suppressHorizontalScroll?: boolean;
71
+ /** When true (default), header row sticks to the top of the scroll container. */
72
+ stickyHeader?: boolean;
73
+ /** When true, shows a fullscreen toggle button in the toolbar. Default: false. */
74
+ fullScreen?: boolean;
71
75
  /** Custom empty state message. */
72
76
  emptyMessage?: string;
73
77
  /** Accessible label for the grid. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alaarab/ogrid-js",
3
- "version": "2.1.1",
3
+ "version": "2.1.3",
4
4
  "description": "OGrid vanilla JS – framework-free data grid with sorting, filtering, pagination, and spreadsheet-style editing.",
5
5
  "main": "dist/esm/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -36,9 +36,11 @@
36
36
  "node": ">=18"
37
37
  },
38
38
  "dependencies": {
39
- "@alaarab/ogrid-core": "2.1.1"
39
+ "@alaarab/ogrid-core": "2.1.3"
40
40
  },
41
- "sideEffects": ["**/*.css"],
41
+ "sideEffects": [
42
+ "**/*.css"
43
+ ],
42
44
  "publishConfig": {
43
45
  "access": "public"
44
46
  },