@guiexpert/table 1.1.104 → 1.1.106
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/index.cjs +25 -25
- package/index.js +1433 -1301
- package/lib/common/platform.d.ts +10 -0
- package/lib/table/data/tablemodel/areamodel/cover-grid-body-model.d.ts +16 -1
- package/lib/table/data/tablemodel/cover-grid-table-model.d.ts +15 -1
- package/lib/table/ele-scope.d.ts +33 -0
- package/lib/table/factory/cover-grid-factory.d.ts +66 -1
- package/lib/table/mouse-handler.d.ts +6 -1
- package/lib/table/render-scope.d.ts +16 -0
- package/lib/table/sheet-editing/editors/select-cell-editor.d.ts +8 -0
- package/package.json +3 -2
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* macOS or not – the one place where the table asks for the platform (⌘ shortcuts, ⌥+letter types text,
|
|
3
|
+
* `aria-keyshortcuts`). Reads `navigator.platform` ("MacIntel", also iPadOS Safari with a keyboard); without a
|
|
4
|
+
* `navigator` (SSR, Node) `false`. Tests switch the platform here with `vi.spyOn(navigator, "platform", "get")`.
|
|
5
|
+
*
|
|
6
|
+
* `navigator.userAgentData.platform` is not used on purpose: only Chromium has it, and the result would be the same.
|
|
7
|
+
*
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
export declare function isMacPlatform(): boolean;
|
|
@@ -7,7 +7,22 @@ import { SortItem } from '../../common/sort-item.js';
|
|
|
7
7
|
import { AreaIdent } from '../area-ident.type.js';
|
|
8
8
|
import { SorterService } from '../../../service/sorter.service.js';
|
|
9
9
|
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Body of a cover grid: `filteredItems[row * columns + column]` is the item of a tile (`getValueAt`), `columns` =
|
|
12
|
+
* `floor(width / coverWidth)`. `items` = all items, `filteredItems` = shown items (filter and `sort()` work on it).
|
|
13
|
+
* Change `coverWidth`/`coverHeight` or the items and call `tableApi.repaintHard()`.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* declare const grid: CoverGridTableModel<string>;
|
|
18
|
+
* const tiles = grid.bodyModel;
|
|
19
|
+
* tiles.items = ["new-1.jpg", "new-2.jpg"];
|
|
20
|
+
* tiles.filteredItems = tiles.items; // or tableApi.externalFilterChanged() with a filter
|
|
21
|
+
* tableApi.repaintHard();
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @category Area models
|
|
25
|
+
*/
|
|
11
26
|
export declare class CoverGridBodyModel<T> implements AreaModelIf {
|
|
12
27
|
items: T[];
|
|
13
28
|
cellRenderer: CellRendererIf;
|
|
@@ -9,7 +9,20 @@ import { ColumnDefIf } from './column/column-def.if.js';
|
|
|
9
9
|
import { Padding } from './padding.js';
|
|
10
10
|
import { SelectionModelIf } from '../../selection/selection-model.if.js';
|
|
11
11
|
|
|
12
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* Table model of a cover grid (created by {@link CoverGridFactory.createCoverGridModel}): items as tiles, the number of
|
|
14
|
+
* columns follows the width (`floor(width / coverWidth)`), header and footer are hidden. The data and the tile size
|
|
15
|
+
* live in {@link CoverGridBodyModel} (`tableModel.bodyModel`).
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* declare const grid: CoverGridTableModel<{ title: string }>;
|
|
20
|
+
* const columns = grid.getColumnCount();
|
|
21
|
+
* tableApi.scrollToIndex(0, Math.floor(500 / columns)); // the row of item 500
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @category Table model
|
|
25
|
+
*/
|
|
13
26
|
export declare class CoverGridTableModel<T> implements TableModelIf {
|
|
14
27
|
bodyModel: CoverGridBodyModel<T>;
|
|
15
28
|
paddingTop: number;
|
|
@@ -39,6 +52,7 @@ export declare class CoverGridTableModel<T> implements TableModelIf {
|
|
|
39
52
|
setColumnWidth(_columnIndex: number, width: number): void;
|
|
40
53
|
recalcSize(_clientWidth: number): void;
|
|
41
54
|
recalcPadding(): void;
|
|
55
|
+
/** No-op: the height follows from the item count, the column count and `coverHeight` – `repaintHard()` is enough. */
|
|
42
56
|
recalcHeightAndPadding(): void;
|
|
43
57
|
getPadding(): Padding;
|
|
44
58
|
getContentHeightInPixel(): number;
|
package/lib/table/ele-scope.d.ts
CHANGED
|
@@ -47,6 +47,16 @@ export declare class EleScope {
|
|
|
47
47
|
protected hoverColumn: HTMLDivElement;
|
|
48
48
|
protected draggingColumn: HTMLDivElement;
|
|
49
49
|
protected scrollTop: number;
|
|
50
|
+
/**
|
|
51
|
+
* Height of the horizontal scroll bar of {@link scrollViewport} in px, measured in {@link adjustContainersAndRows}.
|
|
52
|
+
* 0 without a horizontal scroll bar and with overlay scroll bars (macOS default, mobile) – they take no space.
|
|
53
|
+
*/
|
|
54
|
+
protected horizontalScrollBarHeight: number;
|
|
55
|
+
/**
|
|
56
|
+
* Width of the vertical scroll bar of {@link scrollViewport} in px (at the end of the rows: right, in right-to-left
|
|
57
|
+
* on the left), measured in {@link adjustContainersAndRows}. 0 without one and with overlay scroll bars.
|
|
58
|
+
*/
|
|
59
|
+
protected verticalScrollBarWidth: number;
|
|
50
60
|
protected areaBodyWestGeo: GeoData;
|
|
51
61
|
protected areaBodyCenterGeo: GeoData;
|
|
52
62
|
protected areaBodyEastGeo: GeoData;
|
|
@@ -135,6 +145,29 @@ export declare class EleScope {
|
|
|
135
145
|
* @return {void}
|
|
136
146
|
*/
|
|
137
147
|
adjustContainersAndRows(): void;
|
|
148
|
+
/**
|
|
149
|
+
* The height the table lays out header, body and footer in: the host height minus a horizontal scroll bar that
|
|
150
|
+
* takes space (see {@link horizontalScrollBarHeight}).
|
|
151
|
+
*
|
|
152
|
+
* @returns {number} px
|
|
153
|
+
* @since 1.1.104
|
|
154
|
+
*/
|
|
155
|
+
getLayoutHeight(): number;
|
|
156
|
+
/**
|
|
157
|
+
* The width the table lays out header, body and footer in: the host width minus a vertical scroll bar that takes
|
|
158
|
+
* space (see {@link verticalScrollBarWidth}). A logical width – in right-to-left the bar is on the left.
|
|
159
|
+
*
|
|
160
|
+
* @returns {number} px
|
|
161
|
+
* @since 1.1.104
|
|
162
|
+
*/
|
|
163
|
+
getLayoutWidth(): number;
|
|
164
|
+
/**
|
|
165
|
+
* Height of the horizontal scroll bar of the scroll viewport: offsetHeight − clientHeight (the viewport has no
|
|
166
|
+
* border, see the constructor).
|
|
167
|
+
*/
|
|
168
|
+
protected measureHorizontalScrollBarHeight(): number;
|
|
169
|
+
/** Width of the vertical scroll bar of the scroll viewport: offsetWidth − clientWidth. */
|
|
170
|
+
protected measureVerticalScrollBarWidth(): number;
|
|
138
171
|
/**
|
|
139
172
|
* Position and size of the detail layer (master/detail) in the host – overwritten in {@link RenderScope}.
|
|
140
173
|
*
|
|
@@ -2,8 +2,73 @@ import { CoverGridTableModel } from '../data/tablemodel/cover-grid-table-model.j
|
|
|
2
2
|
import { CellRendererIf } from '../renderer/cell-render.if.js';
|
|
3
3
|
import { TableOptionsIf } from '../data/options/table-options.if.js';
|
|
4
4
|
|
|
5
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* Creates cover grids: a flat array of items shown as tiles (book covers, photos, products) – as many per row as fit
|
|
7
|
+
* into the width of the table (`floor(width / coverWidth)`), without header and footer. Only the visible rows are
|
|
8
|
+
* rendered, like in every GuiExpert Table; filter (`externalFilterFunction`), `sort()` and the scroll position work as
|
|
9
|
+
* usual. Guide: instructions.md 5.10, showcase https://gui.expert/showcase/covergrid/run.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* interface Book { title: string; }
|
|
14
|
+
* declare const books: Book[];
|
|
15
|
+
*
|
|
16
|
+
* const renderer: CellRendererIf = {
|
|
17
|
+
* render(cellDiv: HTMLDivElement, _r: number, _c: number, _a: AreaIdent, _m: AreaModelIf, book: any) {
|
|
18
|
+
* if (book) cellDiv.textContent = (book as Book).title; // the item of this tile (undefined after the last one)
|
|
19
|
+
* return undefined;
|
|
20
|
+
* }
|
|
21
|
+
* };
|
|
22
|
+
* const gridModel = CoverGridFactory.createCoverGridModel(books, renderer, 160, 240);
|
|
23
|
+
* const gridOptions = CoverGridFactory.createCoverGrisDefaultOptions(240, () => "books");
|
|
24
|
+
* const gridApi = new TableScope(host, gridModel, new SimpleDomService(), gridOptions, new EventAdapter())
|
|
25
|
+
* .firstInit()
|
|
26
|
+
* .getApi();
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @category Table model
|
|
30
|
+
*/
|
|
6
31
|
export declare class CoverGridFactory {
|
|
32
|
+
/**
|
|
33
|
+
* Creates the model of a cover grid.
|
|
34
|
+
*
|
|
35
|
+
* @param items - the items, one per tile (the renderer gets the item as `cellValue`)
|
|
36
|
+
* @param cellRenderer - draws one tile into the cell `<div>`
|
|
37
|
+
* @param coverWidth - width of a tile in px (default 200) – change it later via `bodyModel.coverWidth` + `repaintHard()`
|
|
38
|
+
* @param coverHeight - height of a tile in px (default 300)
|
|
39
|
+
* @param width - initial width of the grid; the table sets the width of its host on start and after a resize
|
|
40
|
+
* @param firstRowPaddingTop - extra height of the first row in px (room above the first tiles, e.g. for a toolbar)
|
|
41
|
+
* @returns the table model; `tableModel.bodyModel` holds `items`, `filteredItems`, `coverWidth`, `coverHeight`
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* declare const renderer: CellRendererIf;
|
|
46
|
+
* const gridModel = CoverGridFactory.createCoverGridModel(["a.jpg", "b.jpg", "c.jpg"], renderer, 120, 180);
|
|
47
|
+
* // bigger tiles – no new model:
|
|
48
|
+
* gridModel.bodyModel.coverWidth = 200;
|
|
49
|
+
* gridModel.bodyModel.coverHeight = 300;
|
|
50
|
+
* tableApi.repaintHard();
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
7
53
|
static createCoverGridModel<T>(items: T[], cellRenderer: CellRendererIf, coverWidth?: number, coverHeight?: number, width?: number, firstRowPaddingTop?: number): CoverGridTableModel<T>;
|
|
54
|
+
/**
|
|
55
|
+
* Options for a cover grid: no borders and separators, no row or column hover, header and footer height 0, and the
|
|
56
|
+
* scroll position restored under the key of `getStorageKeyFn` (`localStorage`). (The name has a typo – kept for
|
|
57
|
+
* compatibility.)
|
|
58
|
+
*
|
|
59
|
+
* @param defaultRowHeight - the height of a tile (`coverHeight`)
|
|
60
|
+
* @param getStorageKeyFn - storage key of the scroll position (default `"CoverGrid"`)
|
|
61
|
+
* @returns new options – add your own fields with a spread
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* let photoFilter = "";
|
|
66
|
+
* const gridOptions: TableOptionsIf = {
|
|
67
|
+
* ...CoverGridFactory.createCoverGrisDefaultOptions(240, () => "photos"),
|
|
68
|
+
* externalFilterFunction: (photo: { name: string }) => photo.name.includes(photoFilter),
|
|
69
|
+
* shortcutActionsDisabled: true
|
|
70
|
+
* };
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
8
73
|
static createCoverGrisDefaultOptions(defaultRowHeight: number, getStorageKeyFn?: () => string): TableOptionsIf;
|
|
9
74
|
}
|
|
@@ -27,6 +27,10 @@ export declare class MouseHandler {
|
|
|
27
27
|
private mouseDown;
|
|
28
28
|
private repaintAfterMouseUp;
|
|
29
29
|
private dragging;
|
|
30
|
+
/** Counts the drags: a frame callback of a drag that is over (a new one started) does nothing. */
|
|
31
|
+
private dragGeneration;
|
|
32
|
+
/** The end of the last drag, until its frame ran – a new mousedown handles it at once (see {@link flushDraggingEnd}). */
|
|
33
|
+
private pendingDraggingEnd?;
|
|
30
34
|
constructor(tableScope: TableScope);
|
|
31
35
|
/**
|
|
32
36
|
* Handles the "contextmenu" event.
|
|
@@ -76,7 +80,8 @@ export declare class MouseHandler {
|
|
|
76
80
|
private onMouseMove;
|
|
77
81
|
private onMouseUp;
|
|
78
82
|
private mouseDraggingOnFrame;
|
|
79
|
-
|
|
83
|
+
/** Handles the end of the last drag now (in its frame, or earlier when the next mousedown comes first). */
|
|
84
|
+
private flushDraggingEnd;
|
|
80
85
|
private mouseMoveOnFrame;
|
|
81
86
|
/** A mouse event on a blocking loading overlay ({@link TableOverlay.isEventBlocked}): the table ignores it. */
|
|
82
87
|
private isBlocked;
|
|
@@ -312,6 +312,18 @@ export declare class RenderScope extends EleScope {
|
|
|
312
312
|
* @return {undefined}
|
|
313
313
|
*/
|
|
314
314
|
recalcColumnWidths(clientWidth?: number): void;
|
|
315
|
+
/** `TableModelIf.setParentWidth` – remembers the width for {@link adjustRelativeColumnWidthsToScrollBar}. */
|
|
316
|
+
protected setParentWidth(widthInPixel: number): void;
|
|
317
|
+
/** True if a column has a % or weight width (it depends on the width of the host). */
|
|
318
|
+
protected hasRelativeColumnWidths(): boolean;
|
|
319
|
+
adjustContainersAndRows(): void;
|
|
320
|
+
/**
|
|
321
|
+
* % and weight columns share the width next to the vertical scroll bar. The bar appears (or disappears) only after
|
|
322
|
+
* the rows are laid out – the first layout, rows added or removed, a filter: then the columns were computed for the
|
|
323
|
+
* wrong width – too wide by the width of the bar, so a horizontal scroll bar appeared and covered the last row. Here
|
|
324
|
+
* they are computed again (once – the flag stops a second pass) with the width that is available now.
|
|
325
|
+
*/
|
|
326
|
+
protected adjustRelativeColumnWidthsToScrollBar(): void;
|
|
315
327
|
/**
|
|
316
328
|
* The width that % and weight columns share: host width minus the fixed west columns and a vertical scroll bar.
|
|
317
329
|
*
|
|
@@ -590,6 +602,10 @@ export declare class RenderScope extends EleScope {
|
|
|
590
602
|
private rowNumberWidth?;
|
|
591
603
|
/** true while the containers are adjusted to a new row number width (no second change in that nested pass). */
|
|
592
604
|
private adjustingRowNumberWidth;
|
|
605
|
+
/** Guards {@link adjustRelativeColumnWidthsToScrollBar} against re-entry. */
|
|
606
|
+
private adjustingRelativeWidths;
|
|
607
|
+
/** The width % and weight columns were last computed for (`TableModelIf.setParentWidth`), -1 = unknown. */
|
|
608
|
+
protected relativeWidthsBase: number;
|
|
593
609
|
/** the approximate first width is measured again once (see adjustAfterScrolling). */
|
|
594
610
|
private rowNumberRemeasureScheduled;
|
|
595
611
|
/**
|
|
@@ -17,6 +17,8 @@ import { ValueLabelIf } from '../../data/common/value-label.if.js';
|
|
|
17
17
|
export declare class SelectCellEditor implements CellEditorIf {
|
|
18
18
|
protected readonly options: ValueLabelIf[];
|
|
19
19
|
private select?;
|
|
20
|
+
/** The text of the cell when the editor opened: "nothing chosen" counts as unchanged (since 1.1.106). */
|
|
21
|
+
private startText;
|
|
20
22
|
private readonly abort;
|
|
21
23
|
constructor(options: ValueLabelIf[]);
|
|
22
24
|
/**
|
|
@@ -28,6 +30,12 @@ export declare class SelectCellEditor implements CellEditorIf {
|
|
|
28
30
|
static create(values: string[]): SelectCellEditor;
|
|
29
31
|
open(container: HTMLDivElement, ctx: CellEditorContextIf): void;
|
|
30
32
|
getValue(): unknown;
|
|
33
|
+
/**
|
|
34
|
+
* The chosen value as text; with nothing chosen (the cell's value is not in the list) the start text, so that
|
|
35
|
+
* Enter without a choice writes nothing (before 1.1.106 it emptied the cell).
|
|
36
|
+
*
|
|
37
|
+
* @returns {string} the text
|
|
38
|
+
*/
|
|
31
39
|
getText(): string;
|
|
32
40
|
focus(): void;
|
|
33
41
|
getFocusElement(): HTMLElement | undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@guiexpert/table",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.106",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Dr. Marc Kronberg <info@gui.expert> (https://gui.expert)",
|
|
6
6
|
"repository": {
|
|
@@ -69,7 +69,8 @@
|
|
|
69
69
|
"docs:check": "node scripts/check-doc-examples.mjs",
|
|
70
70
|
"test": "vitest run",
|
|
71
71
|
"test:unit": "vitest run --project unit",
|
|
72
|
-
"test:browser": "vitest run --project browser",
|
|
72
|
+
"test:browser": "vitest run --project browser --project browser-scrollbars",
|
|
73
|
+
"test:browser:scrollbars": "GE_ALL_SCROLLBARS=1 vitest run --project browser-scrollbars",
|
|
73
74
|
"test:watch": "vitest --project unit",
|
|
74
75
|
"test:coverage": "vitest run --coverage",
|
|
75
76
|
"test:types": "tsc -p tsconfig.spec.json --noEmit",
|