@sheetxl/grid-react 0.8.0-beta.2 → 0.8.0-beta.21
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/LICENSE.md +8 -7
- package/README.md +21 -8
- package/browser/esm/index.mjs +3632 -3122
- package/licenses/dependencies.txt +0 -208
- package/node/esm/index.mjs +3968 -2545
- package/package.json +9 -13
- package/types/src/cell/CellRenderer.d.ts +32 -0
- package/types/src/cell/GridlineLayer.d.ts +39 -1
- package/types/src/editor/DefaultEditable.d.ts +16 -6
- package/types/src/editor/EditSession.d.ts +28 -5
- package/types/src/editor/EditorDiv.d.ts +3 -2
- package/types/src/editor/EditorInput.d.ts +5 -2
- package/types/src/editor/EditorLayer.d.ts +9 -4
- package/types/src/editor/EditorStartLayer.d.ts +33 -0
- package/types/src/editor/index.d.ts +1 -0
- package/types/src/editor/useEditorKeymap.d.ts +7 -2
- package/types/src/grid/Grid.d.ts +1 -1
- package/types/src/grid/IGrid.d.ts +4 -4
- package/types/src/header/GridFreezeAnchor.d.ts +29 -0
- package/types/src/header/HeaderDividerAnchor.d.ts +36 -1
- package/types/src/header/HeaderFreezeAnchor.d.ts +37 -0
- package/types/src/header/_freezeSnap.d.ts +28 -0
- package/types/src/header/_useFreezeGrip.d.ts +28 -0
- package/types/src/header/index.d.ts +2 -0
- package/types/src/header/useHeaderSelectionPointer.d.ts +4 -4
- package/types/src/layer/GestureTip.d.ts +77 -0
- package/types/src/layer/GridFloatPanel.d.ts +3 -2
- package/types/src/layer/Layer.d.ts +6 -0
- package/types/src/layer/RangeFloatLayer.d.ts +145 -53
- package/types/src/layer/RangePrompt.d.ts +8 -8
- package/types/src/layer/RangeTooltip.d.ts +128 -0
- package/types/src/layer/RangeTooltipLayer.d.ts +53 -0
- package/types/src/layer/StickyAnchor.d.ts +15 -5
- package/types/src/layer/StickyPortal.d.ts +73 -0
- package/types/src/layer/TooltipProvider.d.ts +104 -0
- package/types/src/layer/_Utils.d.ts +9 -3
- package/types/src/layer/index.d.ts +6 -4
- package/types/src/layer/useGridAnchor.d.ts +45 -4
- package/types/src/layer/useHoverIntent.d.ts +35 -8
- package/types/src/list/CheckboxList.d.ts +18 -2
- package/types/src/list/ListSearch.d.ts +24 -3
- package/types/src/list/PickList.d.ts +6 -1
- package/types/src/range/DragHandle.d.ts +13 -6
- package/types/src/range/Draggable.d.ts +29 -3
- package/types/src/range/FillHandle.d.ts +11 -2
- package/types/src/range/RangeGlide.d.ts +160 -0
- package/types/src/range/RangeRect.d.ts +7 -0
- package/types/src/range/RangeResizer.d.ts +7 -1
- package/types/src/range/index.d.ts +2 -0
- package/types/src/range/useRangeGlide.d.ts +11 -0
- package/types/src/selection/RangesPickerLayer.d.ts +4 -1
- package/types/src/selection/SelectionLayer.d.ts +71 -15
- package/types/src/selection/SelectionStyle.d.ts +4 -1
- package/types/src/selection/SelectionTouchGrips.d.ts +6 -4
- package/types/src/selection/_SelectionUtils.d.ts +6 -0
- package/types/src/selection/useDragCells.d.ts +29 -9
- package/types/src/surface/GridPane.d.ts +2 -0
- package/types/src/surface/IGridPane.d.ts +15 -2
- package/types/src/surface/SurfaceStateProvider.d.ts +1 -1
- package/types/src/surface/getPrimaryPane.d.ts +13 -0
- package/types/src/surface/index.d.ts +1 -0
- package/types/src/surface/useSurfaceState.d.ts +29 -0
- package/types/src/svg/RectangleSVG.d.ts +21 -4
- package/types/src/theme/GridTheme.d.ts +1 -1
- package/browser/cjs/index.cjs +0 -3
- package/types/src/layer/HoverTipLayer.d.ts +0 -47
- package/types/src/layer/StickyFloat.d.ts +0 -68
- package/types/src/layer/useRangeHover.d.ts +0 -36
package/package.json
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sheetxl/grid-react",
|
|
3
3
|
"description": "Grid React - Advanced grid component for React",
|
|
4
|
-
"version": "0.8.0-beta.
|
|
5
|
-
"license": "SEE LICENSE IN
|
|
4
|
+
"version": "0.8.0-beta.21",
|
|
5
|
+
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": {
|
|
9
9
|
"types": "./types/index.d.ts",
|
|
10
10
|
"browser": "./browser/esm/index.mjs",
|
|
11
11
|
"node": "./node/esm/index.mjs",
|
|
12
|
-
"
|
|
13
|
-
"require": "./browser/cjs/index.cjs"
|
|
12
|
+
"default": "./browser/esm/index.mjs"
|
|
14
13
|
}
|
|
15
14
|
},
|
|
16
15
|
"types": "./types/index.d.ts",
|
|
17
16
|
"module": "./browser/esm/index.mjs",
|
|
18
|
-
"main": "./browser/
|
|
17
|
+
"main": "./browser/esm/index.mjs",
|
|
19
18
|
"sideEffects": [
|
|
20
19
|
"*.css",
|
|
21
20
|
"**/*.css"
|
|
@@ -41,20 +40,17 @@
|
|
|
41
40
|
"table"
|
|
42
41
|
],
|
|
43
42
|
"dependencies": {
|
|
44
|
-
"@
|
|
45
|
-
"@sheetxl/utils": "^0.8.0-beta.
|
|
46
|
-
"@sheetxl/utils-react": "^0.8.0-beta.2",
|
|
43
|
+
"@sheetxl/utils": "^0.8.0-beta.21",
|
|
44
|
+
"@sheetxl/utils-react": "^0.8.0-beta.21",
|
|
47
45
|
"clsx": "^2.1.1",
|
|
48
|
-
"react-merge-refs": "^3.0.2"
|
|
49
|
-
"react-use": "^17.6.1",
|
|
50
|
-
"tiny-invariant": "^1.3.3"
|
|
46
|
+
"react-merge-refs": "^3.0.2"
|
|
51
47
|
},
|
|
52
48
|
"peerDependencies": {
|
|
53
49
|
"react": "^19.0.0",
|
|
54
50
|
"react-dom": "^19.0.0"
|
|
55
51
|
},
|
|
56
52
|
"devDependencies": {
|
|
57
|
-
"@types/react": "^19.
|
|
58
|
-
"@types/react-dom": "^19.
|
|
53
|
+
"@types/react": "^19.3.0",
|
|
54
|
+
"@types/react-dom": "^19.3.0"
|
|
59
55
|
}
|
|
60
56
|
}
|
|
@@ -50,4 +50,36 @@ export interface CellRendererProps<T = any> extends React.HTMLAttributes<HTMLEle
|
|
|
50
50
|
*/
|
|
51
51
|
'data-rc'?: string;
|
|
52
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* The attribute that marks cell content as **interactive**: an element a rendered cell draws that
|
|
55
|
+
* takes the pointer itself (a checkbox, a button, a slider's thumb). Spread
|
|
56
|
+
* {@link CELL_INTERACTIVE_PROPS} onto that element rather than writing the attribute by hand.
|
|
57
|
+
*
|
|
58
|
+
* @remarks
|
|
59
|
+
* A rendered cell is `pointer-events: none`, and the selection layer above the cells starts a
|
|
60
|
+
* gesture on every press, so without this nothing drawn in a cell can take a press. A primary
|
|
61
|
+
* press on a marked element selects its cell and starts no drag; the event then reaches the
|
|
62
|
+
* element's own handlers, which decide what the press does (and stop it, so nothing below acts).
|
|
63
|
+
* A press with a modifier (Shift, Ctrl) is a selection press as usual. Layers above the selection
|
|
64
|
+
* still hear the press first.
|
|
65
|
+
*/
|
|
66
|
+
export declare const CELL_INTERACTIVE_ATTRIBUTE = "data-cell-interactive";
|
|
67
|
+
/**
|
|
68
|
+
* The props that make an element of cell content interactive ({@link CELL_INTERACTIVE_ATTRIBUTE}):
|
|
69
|
+
* spread them onto the element that takes the pointer, then add its handlers (`onPointerDown`,
|
|
70
|
+
* `onPointerMove`, …) as on any element. The cell layer gives it `pointer-events: auto`; a drag
|
|
71
|
+
* captures the pointer on the element itself (`setPointerCapture`), as the Stage honors capture.
|
|
72
|
+
*/
|
|
73
|
+
export declare const CELL_INTERACTIVE_PROPS: Readonly<Record<string, string>>;
|
|
74
|
+
/**
|
|
75
|
+
* Whether `target` is, or is inside, interactive cell content ({@link CELL_INTERACTIVE_ATTRIBUTE}).
|
|
76
|
+
*/
|
|
77
|
+
export declare const isCellInteractiveTarget: (target: EventTarget | null) => boolean;
|
|
78
|
+
/**
|
|
79
|
+
* The cell the interactive content under `target` belongs to, read from the layer's `data-rc`
|
|
80
|
+
* stamp on the content's cell root, or `null` when `target` is not interactive content or the
|
|
81
|
+
* content carries no stamp. Content can reach past its cell (overflowing link text), so a press
|
|
82
|
+
* on it is about the content's cell, not the cell under the pointer.
|
|
83
|
+
*/
|
|
84
|
+
export declare const getCellInteractiveCoords: (target: EventTarget | null) => CellCoords | null;
|
|
53
85
|
//# sourceMappingURL=CellRenderer.d.ts.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import { OrientationFlags } from '@sheetxl/utils';
|
|
2
|
+
import { RangeCoords, OrientationFlags } from '@sheetxl/utils';
|
|
3
|
+
import { IGridPane } from '../surface';
|
|
3
4
|
import { LayerProps } from '../layer';
|
|
4
5
|
import { CellModelOptions } from './_CellModel';
|
|
5
6
|
/**
|
|
@@ -28,6 +29,43 @@ export interface GridlineLayerProps extends Omit<LayerProps, 'children'>, CellMo
|
|
|
28
29
|
/** Per-`<path>` props for the vertical (column) lines. */
|
|
29
30
|
propsColumns?: React.SVGProps<SVGPathElement>;
|
|
30
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Options for {@link buildGridlinePath}.
|
|
34
|
+
*/
|
|
35
|
+
export interface GridlinePathOptions {
|
|
36
|
+
/**
|
|
37
|
+
* Stroke width in device pixels; decides how each line center snaps.
|
|
38
|
+
*
|
|
39
|
+
* @defaultValue 1
|
|
40
|
+
*/
|
|
41
|
+
width?: number;
|
|
42
|
+
/**
|
|
43
|
+
* CSS px added to each line's cross-axis position before it snaps (an even-width stroke that
|
|
44
|
+
* grows toward the trailing side).
|
|
45
|
+
*
|
|
46
|
+
* @defaultValue 0
|
|
47
|
+
*/
|
|
48
|
+
shift?: number;
|
|
49
|
+
/**
|
|
50
|
+
* More gaps for one line, as view-relative `[start0, end0, start1, end1, ...]` along the line,
|
|
51
|
+
* sorted by start. `trailIndex` is the row (horizontal) or column (vertical) whose trailing edge
|
|
52
|
+
* the line is.
|
|
53
|
+
*/
|
|
54
|
+
breaksAt?: (trailIndex: number) => readonly number[] | undefined;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Build a single SVG path `d` for one orientation's gridlines — each line broken around the merged
|
|
58
|
+
* ranges that straddle it. ONE path with many `M…L…` subpaths (vs one `<path>` per segment) keeps the
|
|
59
|
+
* DOM to a single node per axis; the segment count changes every scroll tick, so per-segment elements
|
|
60
|
+
* would thrash the DOM. Device snapping is baked into each subpath's coordinates and the stroke width
|
|
61
|
+
* is uniform, so a single path renders identically to N separate paths at any dpr.
|
|
62
|
+
*
|
|
63
|
+
* @param pane The pane to draw for.
|
|
64
|
+
* @param isHorizontal `true` for the row lines, `false` for the column lines.
|
|
65
|
+
* @param ranges Index-space ranges the lines break around (merges, overflow).
|
|
66
|
+
* @param options See {@link GridlinePathOptions}.
|
|
67
|
+
*/
|
|
68
|
+
export declare const buildGridlinePath: (pane: IGridPane, isHorizontal: boolean, ranges: readonly RangeCoords[], options?: GridlinePathOptions) => string;
|
|
31
69
|
/**
|
|
32
70
|
* A **layer** (pane-aware): paints the gridlines for its pane, broken around merged cells, inside a
|
|
33
71
|
* single full-pane {@link Layer} host box. Sources the merge spans from the merges-only
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CellCoords } from '@sheetxl/utils';
|
|
1
|
+
import { CellCoords, MaybePromise } from '@sheetxl/utils';
|
|
2
2
|
import { ICellAnchor } from '../selection';
|
|
3
3
|
import { EditCommitArgs } from './EditState';
|
|
4
4
|
import { EditSession, StartEditOptions, EditModel } from './EditSession';
|
|
@@ -10,7 +10,7 @@ import { EditSession, StartEditOptions, EditModel } from './EditSession';
|
|
|
10
10
|
* @remarks
|
|
11
11
|
* An implementation detail of {@link DefaultEditable}, not part of the layer-facing contract. Collapses
|
|
12
12
|
* the former `getClean` + `canEdit` + `commit` (`null` ⇒ "not editable"). A story closes over a values
|
|
13
|
-
* map; the real app reads an `
|
|
13
|
+
* map; the real app reads an `IWorksheet` (and returns `null` for a protected cell).
|
|
14
14
|
*
|
|
15
15
|
* @typeParam C - clean type. @typeParam D - dirty type. @typeParam A - commit args.
|
|
16
16
|
*/
|
|
@@ -25,7 +25,7 @@ export type CreateEdit<C, D = string, A = EditCommitArgs> = (coords: CellCoords)
|
|
|
25
25
|
* (`startEdit`/`commit`/`cancel`); an app-side bridge can publish {@link getSession} onto the edit-mode
|
|
26
26
|
* bus on each `subscribe` notification. It does **not** vend sessions — there is only
|
|
27
27
|
* ever one active edit, held here. {@link DefaultEditable} is the default implementation; the real app
|
|
28
|
-
* supplies its own (or reuses it with an `
|
|
28
|
+
* supplies its own (or reuses it with an `IWorksheet`-backed {@link CreateEdit}).
|
|
29
29
|
*
|
|
30
30
|
* @typeParam C - clean type. @typeParam D - dirty type. @typeParam A - commit args.
|
|
31
31
|
*/
|
|
@@ -48,8 +48,12 @@ export interface IEditable<C, D = string, A = EditCommitArgs> {
|
|
|
48
48
|
subscribeCommitError(listener: (error: unknown) => void): () => void;
|
|
49
49
|
/** Begin an edit on `coords`. Returns `false` (and does nothing) if the cell is not editable. */
|
|
50
50
|
startEdit(coords: CellCoords, options?: StartEditOptions<D>): boolean;
|
|
51
|
-
/**
|
|
52
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Commit the current edit. On success clears the session; returns whether it succeeded, or a
|
|
53
|
+
* promise of that while the model's {@link EditModel.validate} answers asynchronously (the session
|
|
54
|
+
* stays open until then).
|
|
55
|
+
*/
|
|
56
|
+
commit(args?: A): MaybePromise<boolean>;
|
|
53
57
|
/** Cancel the current edit (revert + clear the session). */
|
|
54
58
|
cancel(): void;
|
|
55
59
|
/**
|
|
@@ -79,6 +83,10 @@ export interface DefaultEditableOptions {
|
|
|
79
83
|
* — an invalid entry keeps you in the cell); the owner — who holds the writable selection the
|
|
80
84
|
* anchor reads — performs the move. When omitted, the editable **cancels** the failed edit instead
|
|
81
85
|
* (the typed value is discarded, but session and selection stay in sync).
|
|
86
|
+
*
|
|
87
|
+
* A click-away whose commit is still being checked ({@link EditModel.validate} answering
|
|
88
|
+
* asynchronously) is held on the edited cell the same way, and once the commit succeeds this is
|
|
89
|
+
* called again with the cell the user went to.
|
|
82
90
|
*/
|
|
83
91
|
revertAnchor?: (coords: CellCoords) => void;
|
|
84
92
|
}
|
|
@@ -105,6 +113,7 @@ export declare class DefaultEditable<C, D = string, A = EditCommitArgs> implemen
|
|
|
105
113
|
private readonly revertAnchor?;
|
|
106
114
|
private readonly unsubscribeAnchor;
|
|
107
115
|
private current;
|
|
116
|
+
private leaveTarget;
|
|
108
117
|
private readonly listeners;
|
|
109
118
|
private readonly commitErrorListeners;
|
|
110
119
|
constructor(anchor: ICellAnchor, createEdit: CreateEdit<C, D, A>, options?: DefaultEditableOptions);
|
|
@@ -120,7 +129,8 @@ export declare class DefaultEditable<C, D = string, A = EditCommitArgs> implemen
|
|
|
120
129
|
/** @inheritdoc IEditable.startEdit */
|
|
121
130
|
startEdit(coords: CellCoords, options?: StartEditOptions<D>): boolean;
|
|
122
131
|
/** @inheritdoc IEditable.commit */
|
|
123
|
-
commit(args?: A): boolean
|
|
132
|
+
commit(args?: A): MaybePromise<boolean>;
|
|
133
|
+
private end;
|
|
124
134
|
/** @inheritdoc IEditable.cancel */
|
|
125
135
|
cancel(): void;
|
|
126
136
|
/** @inheritdoc IEditable.dispose */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CellCoords } from '@sheetxl/utils';
|
|
1
|
+
import { CellCoords, MaybePromise } from '@sheetxl/utils';
|
|
2
2
|
import { ICellAnchor } from '../selection';
|
|
3
3
|
import { EditState, EditorMode, EditorTextSelection, EditCommitArgs } from './EditState';
|
|
4
4
|
/**
|
|
@@ -36,10 +36,25 @@ export interface IInputHandle {
|
|
|
36
36
|
* @typeParam C - clean type. @typeParam D - dirty type. @typeParam A - commit args.
|
|
37
37
|
*/
|
|
38
38
|
export interface EditModel<C, D = string, A = EditCommitArgs> {
|
|
39
|
+
/**
|
|
40
|
+
* The cell as the model homes it, when that is more than the cell it was asked to edit (a sheet
|
|
41
|
+
* model adds the sheet's scope). The session reports these; omitted, it reports the cell asked for.
|
|
42
|
+
*/
|
|
43
|
+
coords?: CellCoords;
|
|
39
44
|
/** The clean value, captured now (edit start). */
|
|
40
45
|
clean: C;
|
|
41
46
|
/** Write the dirty value to the model. Return `false`, or throw, to reject (keeps the edit open). */
|
|
42
47
|
commit(dirty: D, args?: A): boolean | void;
|
|
48
|
+
/**
|
|
49
|
+
* Check the dirty value before it is written. Return `false` to refuse: the edit stays open and
|
|
50
|
+
* the leave-key does not navigate.
|
|
51
|
+
*
|
|
52
|
+
* @remarks
|
|
53
|
+
* May answer with a promise, and the commit then waits for it with the edit still open. If the
|
|
54
|
+
* edit is cancelled, or its value changes, before the answer arrives, nothing is written. Whoever
|
|
55
|
+
* refuses says why: the edit only stays open.
|
|
56
|
+
*/
|
|
57
|
+
validate?(dirty: D, args?: A): MaybePromise<boolean>;
|
|
43
58
|
}
|
|
44
59
|
/**
|
|
45
60
|
* What the {@link EditSession} constructor takes: the {@link EditModel} bits plus the cell. The owning
|
|
@@ -101,6 +116,9 @@ export interface CommitContext<D = string, A = EditCommitArgs> {
|
|
|
101
116
|
*/
|
|
102
117
|
export declare class EditSession<C, D = string, A = EditCommitArgs> implements ICellAnchor {
|
|
103
118
|
private readonly commitFn;
|
|
119
|
+
private readonly validateFn?;
|
|
120
|
+
private pending;
|
|
121
|
+
private cancelled;
|
|
104
122
|
private readonly onCommitError?;
|
|
105
123
|
private state;
|
|
106
124
|
private readonly listeners;
|
|
@@ -171,11 +189,16 @@ export declare class EditSession<C, D = string, A = EditCommitArgs> implements I
|
|
|
171
189
|
/**
|
|
172
190
|
* @internal Driven by {@link DefaultEditable.commit}. Runs **every** beforeCommit consumer (a
|
|
173
191
|
* `veto()` or throw rejects — a throw is also logged, never silently swallowed), then the model's
|
|
174
|
-
* write. Returns whether it succeeded
|
|
175
|
-
*
|
|
176
|
-
*
|
|
192
|
+
* {@link EditModel.validate}, then its write. Returns whether it succeeded, or a promise of that
|
|
193
|
+
* while `validate` answers asynchronously. A no-op (nothing typed) skips the check and the write —
|
|
194
|
+
* the listeners still run (and may veto), so a consumer observing "commit happened" is never
|
|
195
|
+
* skipped. Does NOT clear the owning editable's session — `editable.commit` does that on success.
|
|
177
196
|
*/
|
|
178
|
-
commit(args?: A): boolean
|
|
197
|
+
commit(args?: A): MaybePromise<boolean>;
|
|
198
|
+
private write;
|
|
199
|
+
private reportCommitError;
|
|
200
|
+
/** Whether a commit is waiting on an asynchronous {@link EditModel.validate}. */
|
|
201
|
+
isCommitPending(): boolean;
|
|
179
202
|
/** @internal Driven by {@link DefaultEditable.cancel}. Notifies cancel observers; the editable clears the session. */
|
|
180
203
|
cancel(): void;
|
|
181
204
|
/** Register a beforeCommit consumer (validation, peers, …). Many may register; any may veto. */
|
|
@@ -55,8 +55,9 @@ export interface EditorDivProps<C, D = string, A = EditCommitArgs> {
|
|
|
55
55
|
*
|
|
56
56
|
* @remarks
|
|
57
57
|
* Unlike the layer, this is **always visible** — while idle it shows {@link EditorDivProps.idleClean}
|
|
58
|
-
* (the active cell). It
|
|
59
|
-
*
|
|
58
|
+
* (the active cell). It does not grab focus for an ordinary edit: the field is focused by the user's
|
|
59
|
+
* click, so the in-grid editor and the formula bar don't fight over focus when an edit begins. An edit
|
|
60
|
+
* whose session names this host as its active editor from the start is the exception: it opens here.
|
|
60
61
|
*/
|
|
61
62
|
export declare function EditorDiv<C, D = string, A = EditCommitArgs>(props: EditorDivProps<C, D, A>): React.ReactElement;
|
|
62
63
|
export declare namespace EditorDiv {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CellCoords, Size } from '@sheetxl/utils';
|
|
1
|
+
import { CellCoords, MaybePromise, Size } from '@sheetxl/utils';
|
|
2
2
|
import { EditorMode, EditorTextSelection, EditCommitArgs } from './EditState';
|
|
3
3
|
/**
|
|
4
4
|
* Props passed to the (swappable) editor input — the visual + keyboard surface of the editor. The
|
|
@@ -69,8 +69,11 @@ export interface EditorInputProps<C, D = string> {
|
|
|
69
69
|
*
|
|
70
70
|
* `args` carries the commit "signal" — e.g. {@link EditCommitArgs.broadcast} for a Ctrl+Enter fill,
|
|
71
71
|
* {@link EditCommitArgs.arrayFixed} for a Ctrl+Shift+Enter array entry.
|
|
72
|
+
*
|
|
73
|
+
* A promise means the commit is still being checked (the model's `validate`); the input stops
|
|
74
|
+
* the key and the session stays open until it lands.
|
|
72
75
|
*/
|
|
73
|
-
onCommit(args?: EditCommitArgs): boolean
|
|
76
|
+
onCommit(args?: EditCommitArgs): MaybePromise<boolean>;
|
|
74
77
|
/** Cancel/revert the edit. */
|
|
75
78
|
onCancel(): void;
|
|
76
79
|
/**
|
|
@@ -60,10 +60,15 @@ export interface EditorLayerProps<C, D = string, A = EditCommitArgs> extends Vir
|
|
|
60
60
|
* Always-mounted inline cell editor, as a grid layer.
|
|
61
61
|
*
|
|
62
62
|
* @remarks
|
|
63
|
-
* The input is mounted for the life of the grid (hidden when idle);
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
63
|
+
* The input is mounted for the life of the grid (hidden when idle); starting an edit seeds the first
|
|
64
|
+
* character **by value** into the {@link IEditable} and focuses the input. Mount it as the grid's LAST
|
|
65
|
+
* child so the box paints over everything; with frozen panes each pane instantiates one, and only the
|
|
66
|
+
* pane containing the active cell shows it.
|
|
67
|
+
*
|
|
68
|
+
* This layer carries no event handlers. The ready-mode starters (typed key / F2 / double-click) are
|
|
69
|
+
* the {@link EditorStartLayer}, mounted as the grid's FIRST child: a Layer's handlers are its slot's
|
|
70
|
+
* tap, heard on every layer's turn top first, so start handlers on the top layer would intercept keys
|
|
71
|
+
* and double-clicks aimed at any widget below it before that widget's own handlers ran.
|
|
67
72
|
*/
|
|
68
73
|
export declare function EditorLayer<C, D = string, A = EditCommitArgs>(props: EditorLayerProps<C, D, A>): React.ReactElement;
|
|
69
74
|
//# sourceMappingURL=EditorLayer.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { EditCommitArgs } from './EditState';
|
|
2
|
+
import { IEditable } from './DefaultEditable';
|
|
3
|
+
/**
|
|
4
|
+
* Props for {@link EditorStartLayer}.
|
|
5
|
+
*
|
|
6
|
+
* @typeParam C - The clean value type. @typeParam D - The dirty value type. @typeParam A - Commit args.
|
|
7
|
+
*/
|
|
8
|
+
export interface EditorStartLayerProps<C, D = string, A = EditCommitArgs> {
|
|
9
|
+
/** The editable to start edits on — the same instance the {@link EditorLayer} renders. */
|
|
10
|
+
editable: IEditable<C, D, A>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The grid's **ready-mode** edit starters, as a content-less grid layer: a typed character / `F2` /
|
|
14
|
+
* `Backspace` opens an edit on the anchor, a double-click opens one on the cell under the pointer.
|
|
15
|
+
*
|
|
16
|
+
* @remarks
|
|
17
|
+
* This is deliberately a separate layer from the {@link EditorLayer} that paints the box. The box must
|
|
18
|
+
* sit at the **top** of the stack to paint over everything, but a Layer's handlers are its slot's tap
|
|
19
|
+
* — grid-wide ears that fire on every layer's turn, top first — so handlers on the top layer would
|
|
20
|
+
* intercept keys and double-clicks aimed at any widget below it (a chart, a note) before that widget's
|
|
21
|
+
* own handlers ran. Starting an edit is the grid *floor's* behavior: it belongs at the **bottom** of
|
|
22
|
+
* the stack, where it only hears what no widget above consumed. Mount it as the grid's first child.
|
|
23
|
+
*
|
|
24
|
+
* Keys are positionless, so the floor position alone is not enough for them: a focused widget that
|
|
25
|
+
* does not consume a printable key (it has no use for it, and must let keys through so its own
|
|
26
|
+
* commands can resolve) would otherwise still reach this tap. The key start therefore acts only when
|
|
27
|
+
* the key is aimed at the grid surface itself — the surface (or the pane's focus target, which
|
|
28
|
+
* stands in for it) is the focused element — which is what "the grid is in
|
|
29
|
+
* ready mode" means. A double-click needs no such guard: it has a position, and a widget that owns
|
|
30
|
+
* that position consumes it.
|
|
31
|
+
*/
|
|
32
|
+
export declare function EditorStartLayer<C, D = string, A = EditCommitArgs>(props: EditorStartLayerProps<C, D, A>): React.ReactElement;
|
|
33
|
+
//# sourceMappingURL=EditorStartLayer.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RefObject } from 'react';
|
|
2
|
-
import { Direction, RangeAxis } from '@sheetxl/utils';
|
|
2
|
+
import { Direction, RangeAxis, MaybePromise } from '@sheetxl/utils';
|
|
3
3
|
import { EditorMode, EditCommitArgs } from './EditState';
|
|
4
4
|
import { StartEditOptions } from './EditSession';
|
|
5
5
|
/**
|
|
@@ -29,7 +29,12 @@ export interface EditorKeymapProps {
|
|
|
29
29
|
value: string;
|
|
30
30
|
onDirtyChange(dirty: string): void;
|
|
31
31
|
onModeChange(mode: EditorMode): void;
|
|
32
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Commit the edit. A promise means the commit is still being checked: the key is consumed, and the
|
|
34
|
+
* move it asks for is made through {@link onNavigate} / {@link onTraverse} once the commit lands
|
|
35
|
+
* (with neither supplied, the active cell stays put).
|
|
36
|
+
*/
|
|
37
|
+
onCommit(args?: EditCommitArgs): MaybePromise<boolean>;
|
|
33
38
|
onCancel(): void;
|
|
34
39
|
/**
|
|
35
40
|
* Optional. When provided, a successful **enter-mode arrow** commit **navigates here, in the input**,
|
package/types/src/grid/Grid.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { GridProps, IGrid } from './IGrid';
|
|
|
3
3
|
/**
|
|
4
4
|
* A virtualized grid: a thin wrapper around {@link GridSurface} that re-adds the cell + gridline
|
|
5
5
|
* rendering the surface itself is agnostic to. It composes a `CellLayer` (cells), a `GridlineLayer`
|
|
6
|
-
* (gridlines) and an optional `
|
|
6
|
+
* (gridlines) and an optional `borderLayers` slot as ordinary layers — in the conventional z-order
|
|
7
7
|
* (gridlines → borders → below-layers → cells → above-layers) — and owns the content cache token the
|
|
8
8
|
* cells bust on. Everything else is forwarded to the surface.
|
|
9
9
|
*
|
|
@@ -36,13 +36,13 @@ export interface GridProps extends GridSurfaceProps {
|
|
|
36
36
|
* Layer(s) rendered BELOW the cells/borders (but above the gridlines) — the place for fills and
|
|
37
37
|
* highlights. The `children` are the layers ABOVE the cells/borders.
|
|
38
38
|
*/
|
|
39
|
-
|
|
39
|
+
layersBelow?: LayerNode;
|
|
40
40
|
/**
|
|
41
|
-
* Optional border layer(s), rendered just below the cells (above {@link GridProps.
|
|
42
|
-
* gridlines)
|
|
41
|
+
* Optional border layer(s), rendered just below the cells (above {@link GridProps.layersBelow} /
|
|
42
|
+
* gridlines), for a custom border treatment — distinct from the light
|
|
43
43
|
* {@link GridProps.showGridLines} gridlines.
|
|
44
44
|
*/
|
|
45
|
-
|
|
45
|
+
borderLayers?: LayerNode;
|
|
46
46
|
/**
|
|
47
47
|
* Show grid lines. Useful for spreadsheets.
|
|
48
48
|
*/
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { RangeAxis } from '@sheetxl/utils';
|
|
2
|
+
import { FreezeDragPosition } from './_freezeSnap';
|
|
3
|
+
export interface GridFreezeAnchorProps {
|
|
4
|
+
/** The axis the freeze moves along: `Column` drags the vertical freeze line. */
|
|
5
|
+
axis: RangeAxis;
|
|
6
|
+
/** Disable the grip (the pointer falls through to the cells). */
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
/** The pointer has moved past the threshold and the drag has begun. */
|
|
9
|
+
onFreezeDragStart?: (position: FreezeDragPosition) => void;
|
|
10
|
+
/** Called on every move while dragging. */
|
|
11
|
+
onFreezeDrag?: (position: FreezeDragPosition) => void;
|
|
12
|
+
/** The pointer was released after a drag. */
|
|
13
|
+
onFreezeDragEnd?: (position: FreezeDragPosition) => void;
|
|
14
|
+
/** The drag was abandoned (Escape); nothing should be committed. */
|
|
15
|
+
onFreezeDragCancel?: () => void;
|
|
16
|
+
/** The grip became active (hovered or dragging) or stopped being so — e.g. to highlight the freeze line. */
|
|
17
|
+
onActiveChange?: (active: boolean) => void;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The freeze grip over the cells: a hit strip along the main grid's freeze line, dragged like
|
|
21
|
+
* {@link HeaderFreezeAnchor}. It draws nothing — the grid draws the line, and can highlight it from
|
|
22
|
+
* `onActiveChange`.
|
|
23
|
+
*
|
|
24
|
+
* @remarks
|
|
25
|
+
* Render it in the main grid's layers. It exists only while the axis is frozen, in the frozen panes whose
|
|
26
|
+
* trailing edge is the line (for columns, the left and top-left panes).
|
|
27
|
+
*/
|
|
28
|
+
export declare const GridFreezeAnchor: import('react').MemoExoticComponent<(props: GridFreezeAnchorProps) => string | number | bigint | boolean | Iterable<import('react').ReactNode> | Promise<string | number | bigint | boolean | import('react').ReactPortal | import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>> | Iterable<import('react').ReactNode> | null | undefined> | import("react").JSX.Element | null | undefined>;
|
|
29
|
+
//# sourceMappingURL=GridFreezeAnchor.d.ts.map
|
|
@@ -56,15 +56,34 @@ export interface IHeaderDividerAttributes {
|
|
|
56
56
|
export interface IHeaderDividerElement extends HTMLDivElement, IHeaderDividerAttributes {
|
|
57
57
|
}
|
|
58
58
|
export interface HeaderDividerRendererProps extends HeaderDividerProps {
|
|
59
|
+
/** The pane the divider is drawn in. */
|
|
60
|
+
pane: IGridPane;
|
|
61
|
+
/**
|
|
62
|
+
* The divider's line in pane coordinates — zero-width for a column divider, zero-height for a row —
|
|
63
|
+
* snapped to the device pixel the gridline paints. The renderer positions its element (hit area and
|
|
64
|
+
* visible line) around it.
|
|
65
|
+
*/
|
|
59
66
|
bounds: Bounds;
|
|
60
67
|
/**
|
|
61
68
|
* Handle mouse down and all dragging
|
|
62
69
|
*/
|
|
63
70
|
onPointerDown: React.PointerEventHandler<HTMLDivElement>;
|
|
64
71
|
onAutoFit: () => void;
|
|
72
|
+
/**
|
|
73
|
+
* Reveal the hidden headers this divider sits on. Present only when the divider has hidden headers
|
|
74
|
+
* to reveal and the consumer handles it.
|
|
75
|
+
*/
|
|
76
|
+
onUnhide?: () => void;
|
|
77
|
+
/** The divider is pressed or being dragged. */
|
|
78
|
+
isActive?: boolean;
|
|
65
79
|
}
|
|
66
80
|
export interface HeaderDividerAnchorProps extends HeaderDividerProps {
|
|
67
|
-
renderDivider?: (props: HeaderDividerRendererProps
|
|
81
|
+
renderDivider?: (props: HeaderDividerRendererProps) => React.ReactNode;
|
|
82
|
+
/**
|
|
83
|
+
* The clipped bounds of the pane's visible headers, from {@link getHeaderDividerBounds}. Computed when
|
|
84
|
+
* omitted; pass it when rendering a pane's worth of dividers so it is computed once.
|
|
85
|
+
*/
|
|
86
|
+
visibleBounds?: Bounds | null;
|
|
68
87
|
/**
|
|
69
88
|
* The number of pixels to mouse before resizing starts.
|
|
70
89
|
* If this number is less than 1 then it will be 1.
|
|
@@ -110,11 +129,27 @@ export interface HeaderDividerAnchorProps extends HeaderDividerProps {
|
|
|
110
129
|
* @param index
|
|
111
130
|
*/
|
|
112
131
|
onDividerAutoFit?: (index: number) => void;
|
|
132
|
+
/**
|
|
133
|
+
* Called when the unhide button on a divider over hidden headers is clicked. Without it the divider
|
|
134
|
+
* shows no unhide button.
|
|
135
|
+
*
|
|
136
|
+
* @param index the index of the divider.
|
|
137
|
+
*/
|
|
138
|
+
onDividerUnhide?: (index: number) => void;
|
|
113
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* The class on the default divider's root element, for styling and for finding dividers in the DOM.
|
|
142
|
+
*/
|
|
143
|
+
export declare const HEADER_DIVIDER_CLASS = "sxl-header-divider";
|
|
114
144
|
export declare const DefaultHeaderDivider: import('react').NamedExoticComponent<Omit<HeaderDividerRendererProps, "ref"> & import('react').RefAttributes<IHeaderDividerElement>>;
|
|
115
145
|
/**
|
|
116
146
|
* A divider placed between headers to provider a visual cue for various actions.
|
|
117
147
|
* Resize, hide/unhide, etc.
|
|
118
148
|
*/
|
|
119
149
|
export declare const HeaderDividerAnchor: import('react').NamedExoticComponent<Omit<HeaderDividerAnchorProps, "ref"> & import('react').RefAttributes<IHeaderDividerElement>>;
|
|
150
|
+
/**
|
|
151
|
+
* The clipped bounds of a pane's visible headers on an axis — the span every divider in the pane shares —
|
|
152
|
+
* or `null` when none are visible.
|
|
153
|
+
*/
|
|
154
|
+
export declare const getHeaderDividerBounds: (pane: IGridPane, axis: RangeAxis) => Bounds | null;
|
|
120
155
|
//# sourceMappingURL=HeaderDividerAnchor.d.ts.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { RangeAxis } from '@sheetxl/utils';
|
|
2
|
+
import { FreezeDragPosition } from './_freezeSnap';
|
|
3
|
+
export type { FreezeDragPosition } from './_freezeSnap';
|
|
4
|
+
export interface HeaderFreezeAnchorProps {
|
|
5
|
+
/** The axis the freeze moves along: `Column` drags the vertical freeze line along the column header. */
|
|
6
|
+
axis: RangeAxis;
|
|
7
|
+
/** Disable the grip entirely (no hit area, no hover). */
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Draw the bar in its active color although this grip is not hovered — e.g. while the freeze line's grip
|
|
11
|
+
* in the body is.
|
|
12
|
+
*/
|
|
13
|
+
highlight?: boolean;
|
|
14
|
+
/** The pointer has moved past the threshold and the drag has begun. */
|
|
15
|
+
onFreezeDragStart?: (position: FreezeDragPosition) => void;
|
|
16
|
+
/** Called on every move while dragging. */
|
|
17
|
+
onFreezeDrag?: (position: FreezeDragPosition) => void;
|
|
18
|
+
/** The pointer was released after a drag. */
|
|
19
|
+
onFreezeDragEnd?: (position: FreezeDragPosition) => void;
|
|
20
|
+
/** The drag was abandoned (Escape); nothing should be committed. */
|
|
21
|
+
onFreezeDragCancel?: () => void;
|
|
22
|
+
/** The grip became active (hovered or dragging) or stopped being so — e.g. to highlight the freeze line. */
|
|
23
|
+
onActiveChange?: (active: boolean) => void;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The freeze grip: a bar in a header on the freeze line (or at the header's start when nothing is frozen
|
|
27
|
+
* on this axis). Dragging it snaps the freeze to the nearest header boundary on screen.
|
|
28
|
+
*
|
|
29
|
+
* @remarks
|
|
30
|
+
* Render it in the header's layers, above the resize dividers. It draws in one pane only: the frozen pane,
|
|
31
|
+
* centered on its trailing edge (frozen panes sit over the scrolling one, so the grip covers the last
|
|
32
|
+
* frozen header's divider), or the scrolling pane's leading edge when nothing is frozen. The drag reports
|
|
33
|
+
* positions only — committing the freeze is the caller's. {@link GridFreezeAnchor} is the same grip on the
|
|
34
|
+
* freeze line over the cells.
|
|
35
|
+
*/
|
|
36
|
+
export declare const HeaderFreezeAnchor: import('react').MemoExoticComponent<(props: HeaderFreezeAnchorProps) => import("react").JSX.Element | null>;
|
|
37
|
+
//# sourceMappingURL=HeaderFreezeAnchor.d.ts.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { IGridPane } from '../surface';
|
|
2
|
+
/**
|
|
3
|
+
* Where a freeze drag would land: the snapped boundary and the raw pointer, both as CLIENT coordinates
|
|
4
|
+
* on the drag axis so any pane (header or body) maps them with `getPanePointFromPointer`.
|
|
5
|
+
*/
|
|
6
|
+
export interface FreezeDragPosition {
|
|
7
|
+
/**
|
|
8
|
+
* The freeze count the drop commits: the index of the first track in the scrolling area. `0` ⇒
|
|
9
|
+
* unfreeze this axis.
|
|
10
|
+
*/
|
|
11
|
+
index: number;
|
|
12
|
+
/** Client coordinate (x for columns, y for rows) of the snapped boundary — the solid line. */
|
|
13
|
+
snapClient: number;
|
|
14
|
+
/**
|
|
15
|
+
* Client coordinate of the pointer — the dashed line. Absent once the pointer is past the start of the
|
|
16
|
+
* header (where the drop unfreezes), so no line is drawn outside the grid.
|
|
17
|
+
*/
|
|
18
|
+
pointerClient?: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Snap a client coordinate to the nearest track boundary on screen across the header's panes.
|
|
22
|
+
*
|
|
23
|
+
* Candidates are the leading edges of the visible tracks in the frozen pane and the scrolling pane, plus
|
|
24
|
+
* the surface's own leading edge (which unfreezes). Only boundaries actually on screen are candidates, so
|
|
25
|
+
* a drag can never freeze past what is visible.
|
|
26
|
+
*/
|
|
27
|
+
export declare const snapToBoundary: (pane: IGridPane, isColumn: boolean, pointerClient: number, crossClient: number) => FreezeDragPosition;
|
|
28
|
+
//# sourceMappingURL=_freezeSnap.d.ts.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { RangeAxis } from '@sheetxl/utils';
|
|
2
|
+
import { FreezeDragPosition } from './_freezeSnap';
|
|
3
|
+
export interface FreezeGripOptions {
|
|
4
|
+
axis: RangeAxis;
|
|
5
|
+
disabled: boolean;
|
|
6
|
+
/** Whether this pane draws the grip. A pane that stops drawing it never hears the pointer leave. */
|
|
7
|
+
isOwner: boolean;
|
|
8
|
+
onFreezeDragStart?: (position: FreezeDragPosition) => void;
|
|
9
|
+
onFreezeDrag?: (position: FreezeDragPosition) => void;
|
|
10
|
+
onFreezeDragEnd?: (position: FreezeDragPosition) => void;
|
|
11
|
+
onFreezeDragCancel?: () => void;
|
|
12
|
+
onActiveChange?: (active: boolean) => void;
|
|
13
|
+
}
|
|
14
|
+
export interface FreezeGrip {
|
|
15
|
+
/** Hovered or dragging, in the owning pane, while enabled. */
|
|
16
|
+
isActive: boolean;
|
|
17
|
+
cursor: string;
|
|
18
|
+
/** Spread onto the hit area. */
|
|
19
|
+
hitProps: React.HTMLAttributes<HTMLDivElement>;
|
|
20
|
+
/** The drag backdrop (forces the cursor, shields other components); render it alongside the hit area. */
|
|
21
|
+
backdrop: React.ReactNode;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The gesture behind a freeze grip, wherever its hit area sits: press, threshold, snapped drag positions,
|
|
25
|
+
* Escape to abandon, and the active (hovered or dragging) state.
|
|
26
|
+
*/
|
|
27
|
+
export declare const useFreezeGrip: (options: FreezeGripOptions) => FreezeGrip;
|
|
28
|
+
//# sourceMappingURL=_useFreezeGrip.d.ts.map
|