@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 +43 -0
- package/dist/esm/renderer/TableRenderer.js +3 -0
- package/dist/esm/state/GridState.js +4 -0
- package/dist/styles/ogrid.css +32 -1
- package/dist/types/OGrid.d.ts +4 -0
- package/dist/types/state/GridState.d.ts +4 -0
- package/dist/types/types/gridTypes.d.ts +4 -0
- package/package.json +5 -3
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; }
|
package/dist/styles/ogrid.css
CHANGED
|
@@ -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'] {
|
package/dist/types/OGrid.d.ts
CHANGED
|
@@ -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.
|
|
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.
|
|
39
|
+
"@alaarab/ogrid-core": "2.1.3"
|
|
40
40
|
},
|
|
41
|
-
"sideEffects": [
|
|
41
|
+
"sideEffects": [
|
|
42
|
+
"**/*.css"
|
|
43
|
+
],
|
|
42
44
|
"publishConfig": {
|
|
43
45
|
"access": "public"
|
|
44
46
|
},
|