@sheetxl/grid-react 0.7.28-beta.4 → 0.8.0-beta.2
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/browser/cjs/index.cjs +3 -3
- package/browser/esm/index.mjs +2052 -1487
- package/licenses/dependencies.txt +35 -1
- package/node/esm/index.mjs +1662 -1108
- package/package.json +3 -3
- package/types/src/cell/CellRenderer.d.ts +14 -3
- package/types/src/editor/DefaultEditable.d.ts +9 -0
- package/types/src/editor/EditSession.d.ts +6 -0
- package/types/src/editor/EditState.d.ts +6 -0
- package/types/src/editor/EditorInput.d.ts +2 -1
- package/types/src/editor/useEditorKeymap.d.ts +11 -0
- package/types/src/header/useHeaderSelectionPointer.d.ts +6 -2
- package/types/src/layer/GridFloatPanel.d.ts +18 -0
- package/types/src/layer/HoverTipLayer.d.ts +20 -47
- package/types/src/layer/RangeFloatLayer.d.ts +146 -0
- package/types/src/layer/StickyAnchor.d.ts +2 -4
- package/types/src/layer/StickyFloat.d.ts +4 -1
- package/types/src/layer/index.d.ts +3 -1
- package/types/src/layer/useGridAnchor.d.ts +23 -6
- package/types/src/layer/useRangeHover.d.ts +5 -4
- package/types/src/list/CheckboxList.d.ts +11 -0
- package/types/src/list/List.d.ts +14 -5
- package/types/src/list/ListSearch.d.ts +31 -0
- package/types/src/list/ListSurface.d.ts +93 -0
- package/types/src/list/PickList.d.ts +71 -0
- package/types/src/list/_measureText.d.ts +14 -0
- package/types/src/list/index.d.ts +3 -0
- package/types/src/range/DragHandle.d.ts +14 -0
- package/types/src/range/Draggable.d.ts +111 -6
- package/types/src/range/FillHandle.d.ts +28 -1
- package/types/src/range/RangeInsertBar.d.ts +91 -0
- package/types/src/range/index.d.ts +2 -0
- package/types/src/selection/SelectionLayer.d.ts +91 -9
- package/types/src/selection/SelectionStyle.d.ts +30 -0
- package/types/src/selection/useDragCells.d.ts +36 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sheetxl/grid-react",
|
|
3
3
|
"description": "Grid React - Advanced grid component for React",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.8.0-beta.2",
|
|
5
5
|
"license": "SEE LICENSE IN <LICENSE>",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"exports": {
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
],
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@floating-ui/react-dom": "^2.1.9",
|
|
45
|
-
"@sheetxl/utils": "^0.
|
|
46
|
-
"@sheetxl/utils-react": "^0.
|
|
45
|
+
"@sheetxl/utils": "^0.8.0-beta.2",
|
|
46
|
+
"@sheetxl/utils-react": "^0.8.0-beta.2",
|
|
47
47
|
"clsx": "^2.1.1",
|
|
48
48
|
"react-merge-refs": "^3.0.2",
|
|
49
49
|
"react-use": "^17.6.1",
|
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
import { Bounds, CellCoords, RangeCoords } from '@sheetxl/utils';
|
|
2
|
-
import { IGridPane } from '../surface';
|
|
3
2
|
export interface CellRendererProps<T = any> extends React.HTMLAttributes<HTMLElement>, React.Attributes {
|
|
4
3
|
/**
|
|
5
4
|
* A value to render.
|
|
6
5
|
*/
|
|
7
6
|
value: T;
|
|
8
7
|
/**
|
|
9
|
-
* The
|
|
8
|
+
* The zoom {@link CellRendererProps.bounds} were measured at.
|
|
9
|
+
*
|
|
10
|
+
* @defaultValue 1
|
|
11
|
+
*
|
|
12
|
+
* @remarks
|
|
13
|
+
* A renderer is handed the zoom, never the pane it came from: everything it needs to draw one cell
|
|
14
|
+
* is data (the value, the bounds, the scale), so it stays a pure function of its props and can be
|
|
15
|
+
* rendered anywhere a caller can supply bounds — a preview, a tooltip, a cell drawn outside its own
|
|
16
|
+
* column. A renderer that genuinely needs the live view (hover, scroll) reads it from context with
|
|
17
|
+
* `useGridPane`.
|
|
18
|
+
*
|
|
19
|
+
* The bounds already have the zoom applied; this is for what CSS pixels do not carry — an unscaled
|
|
20
|
+
* inset, a glyph size, a stroke width the renderer picks itself.
|
|
10
21
|
*/
|
|
11
|
-
|
|
22
|
+
zoom?: number;
|
|
12
23
|
/**
|
|
13
24
|
* The range bounds relative to the current viewport and zoom.
|
|
14
25
|
*/
|
|
@@ -40,6 +40,12 @@ export interface IEditable<C, D = string, A = EditCommitArgs> {
|
|
|
40
40
|
getSession(): EditSession<C, D, A> | null;
|
|
41
41
|
/** Subscribe to session changes (start/stop only). Returns an unsubscribe. */
|
|
42
42
|
subscribe(listener: () => void): () => void;
|
|
43
|
+
/**
|
|
44
|
+
* Subscribe to commits the model REFUSED by throwing (an expected refusal such as "You can't change
|
|
45
|
+
* part of an array", or a real fault). The edit stays open either way; this is the seam through
|
|
46
|
+
* which the reason reaches a host that can show it. Returns an unsubscribe.
|
|
47
|
+
*/
|
|
48
|
+
subscribeCommitError(listener: (error: unknown) => void): () => void;
|
|
43
49
|
/** Begin an edit on `coords`. Returns `false` (and does nothing) if the cell is not editable. */
|
|
44
50
|
startEdit(coords: CellCoords, options?: StartEditOptions<D>): boolean;
|
|
45
51
|
/** Commit the current edit. On success clears the session; returns whether it succeeded. */
|
|
@@ -100,12 +106,15 @@ export declare class DefaultEditable<C, D = string, A = EditCommitArgs> implemen
|
|
|
100
106
|
private readonly unsubscribeAnchor;
|
|
101
107
|
private current;
|
|
102
108
|
private readonly listeners;
|
|
109
|
+
private readonly commitErrorListeners;
|
|
103
110
|
constructor(anchor: ICellAnchor, createEdit: CreateEdit<C, D, A>, options?: DefaultEditableOptions);
|
|
104
111
|
private onAnchorChange;
|
|
105
112
|
/** @inheritdoc IEditable.getAnchor */
|
|
106
113
|
getAnchor(): ICellAnchor;
|
|
107
114
|
/** @inheritdoc IEditable.subscribe */
|
|
108
115
|
subscribe(listener: () => void): () => void;
|
|
116
|
+
/** @inheritdoc IEditable.subscribeCommitError */
|
|
117
|
+
subscribeCommitError(listener: (error: unknown) => void): () => void;
|
|
109
118
|
/** @inheritdoc IEditable.getSession */
|
|
110
119
|
getSession(): EditSession<C, D, A> | null;
|
|
111
120
|
/** @inheritdoc IEditable.startEdit */
|
|
@@ -49,6 +49,11 @@ export interface EditModel<C, D = string, A = EditCommitArgs> {
|
|
|
49
49
|
export interface EditSessionInit<C, D = string, A = EditCommitArgs> extends EditModel<C, D, A> {
|
|
50
50
|
/** The cell being edited. */
|
|
51
51
|
coords: CellCoords;
|
|
52
|
+
/**
|
|
53
|
+
* Hears the error a THROWING model write rejected the commit with (see {@link EditModel.commit}).
|
|
54
|
+
* The rejection itself only keeps the edit open; this is how the reason reaches whoever can show it.
|
|
55
|
+
*/
|
|
56
|
+
onCommitError?: (error: unknown) => void;
|
|
52
57
|
}
|
|
53
58
|
/**
|
|
54
59
|
* Options applied when an edit begins (`DefaultEditable.startEdit` → the `EditSession` constructor).
|
|
@@ -96,6 +101,7 @@ export interface CommitContext<D = string, A = EditCommitArgs> {
|
|
|
96
101
|
*/
|
|
97
102
|
export declare class EditSession<C, D = string, A = EditCommitArgs> implements ICellAnchor {
|
|
98
103
|
private readonly commitFn;
|
|
104
|
+
private readonly onCommitError?;
|
|
99
105
|
private state;
|
|
100
106
|
private readonly listeners;
|
|
101
107
|
private readonly commitListeners;
|
|
@@ -20,6 +20,12 @@ export interface EditCommitArgs {
|
|
|
20
20
|
* Excel's `Ctrl+Enter`. The active cell does not move (the leave-key does not navigate/traverse).
|
|
21
21
|
*/
|
|
22
22
|
broadcast?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Array-enter the value over the **current selection** — Excel's `Ctrl+Shift+Enter`: one formula
|
|
25
|
+
* at the selection's top-left whose result is fitted to the selection's extent, rather than
|
|
26
|
+
* spilling from the active cell. The active cell does not move.
|
|
27
|
+
*/
|
|
28
|
+
arrayFixed?: boolean;
|
|
23
29
|
}
|
|
24
30
|
/**
|
|
25
31
|
* A text selection range within the editor input. Mirrors the `HTMLTextAreaElement` selection API.
|
|
@@ -67,7 +67,8 @@ export interface EditorInputProps<C, D = string> {
|
|
|
67
67
|
* (a rejected/invalid value) the input keeps the session open and stops the key so the selection
|
|
68
68
|
* does not move away.
|
|
69
69
|
*
|
|
70
|
-
* `args` carries the commit "signal" — e.g. {@link EditCommitArgs.broadcast} for a Ctrl+Enter fill
|
|
70
|
+
* `args` carries the commit "signal" — e.g. {@link EditCommitArgs.broadcast} for a Ctrl+Enter fill,
|
|
71
|
+
* {@link EditCommitArgs.arrayFixed} for a Ctrl+Shift+Enter array entry.
|
|
71
72
|
*/
|
|
72
73
|
onCommit(args?: EditCommitArgs): boolean;
|
|
73
74
|
/** Cancel/revert the edit. */
|
|
@@ -54,6 +54,17 @@ export interface EditorKeymapProps {
|
|
|
54
54
|
*/
|
|
55
55
|
setCaret?(caret: number): void;
|
|
56
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* The commit "signal" a leave key carries: `Ctrl+Shift+Enter` array-enters over the selection
|
|
59
|
+
* ({@link EditCommitArgs.arrayFixed}), `Ctrl+Enter` fills it ({@link EditCommitArgs.broadcast}), and
|
|
60
|
+
* anything else is a plain commit (`undefined`). Both modified forms keep the active cell put.
|
|
61
|
+
*/
|
|
62
|
+
export declare const commitArgsFromKey: (e: {
|
|
63
|
+
which: number;
|
|
64
|
+
}, native: {
|
|
65
|
+
ctrlKey: boolean;
|
|
66
|
+
shiftKey: boolean;
|
|
67
|
+
}) => EditCommitArgs | undefined;
|
|
57
68
|
/**
|
|
58
69
|
* The shared spreadsheet editor keymap, as a `<textarea>` `onKeyDown` handler. Both the default and
|
|
59
70
|
* the cell-aware inputs use it so the interaction contract stays identical:
|
|
@@ -55,8 +55,12 @@ export interface HeaderSelectionPointerOptions {
|
|
|
55
55
|
onPointerDownInterceptor?: (e: React.PointerEvent, cell: CellCoords) => boolean | void;
|
|
56
56
|
/** Called once at the start of a pointer gesture (before the selection changes). */
|
|
57
57
|
onDragStart?: () => void;
|
|
58
|
-
/**
|
|
59
|
-
|
|
58
|
+
/**
|
|
59
|
+
* Called at the end of a pointer gesture — on release AND on an abort (Escape / OS `pointercancel`),
|
|
60
|
+
* so whatever {@link HeaderSelectionPointerOptions.onDragStart} armed is always disarmed. The event is
|
|
61
|
+
* absent on an abort.
|
|
62
|
+
*/
|
|
63
|
+
onDragEnd?: (e?: React.PointerEvent) => void;
|
|
60
64
|
/** Called on pointer-up, after {@link HeaderSelectionPointerOptions.onDragEnd} (e.g. refocus the grid). */
|
|
61
65
|
onPointerUp?: (e: React.PointerEvent) => void;
|
|
62
66
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { FloatPanelProps } from '@sheetxl/utils-react';
|
|
3
|
+
/**
|
|
4
|
+
* A **float stack panel positioned by the grid**: pass {@link renderGridFloatPanel} as a
|
|
5
|
+
* `useFloatStack` `renderFloatPanel`, and a {@link GridAnchor} (a cell or range) as its `anchor`.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* The stack keeps what it does for every popup — the portal, light-dismiss, Escape, focus restore and
|
|
9
|
+
* stacking. The position comes from {@link StickyFloat}, the engine grid buttons and labels use, so the
|
|
10
|
+
* popup moves with its cell as the grid scrolls (which no DOM event reports), flips against the same
|
|
11
|
+
* boundary, and closes once its cell has scrolled out of view.
|
|
12
|
+
*
|
|
13
|
+
* The stack's `propsPopper` `placement` and `offsets` are read as the grid placement and offset.
|
|
14
|
+
*/
|
|
15
|
+
export declare const GridFloatPanel: React.FC<FloatPanelProps>;
|
|
16
|
+
/** {@link GridFloatPanel} as a `useFloatStack` `renderFloatPanel`. */
|
|
17
|
+
export declare const renderGridFloatPanel: (props: FloatPanelProps) => React.ReactElement;
|
|
18
|
+
//# sourceMappingURL=GridFloatPanel.d.ts.map
|
|
@@ -1,29 +1,25 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
2
|
import { CellCoords, RangeCoords } from '@sheetxl/utils';
|
|
3
3
|
import { IGridPane } from '../surface';
|
|
4
|
-
import { LayerProps } from './Layer';
|
|
5
4
|
import { StickyState } from './StickyAnchor';
|
|
6
5
|
import { HoverTipProps } from './useHoverIntent';
|
|
7
|
-
import {
|
|
8
|
-
/**
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
* one target is a no-op). Defaults to the range's coords.
|
|
15
|
-
*/
|
|
16
|
-
key?: string;
|
|
17
|
-
/** Payload passed to the render-prop (the message, the table, …). */
|
|
18
|
-
data: T;
|
|
19
|
-
}
|
|
6
|
+
import { RangeFloatTarget, RangeFloatLayerProps } from './RangeFloatLayer';
|
|
7
|
+
/**
|
|
8
|
+
* A hit returned by a {@link HoverTipLayerProps.probe} — the range to anchor on plus arbitrary payload.
|
|
9
|
+
*
|
|
10
|
+
* The hover-flavored name for a {@link RangeFloatTarget}; they are the same shape.
|
|
11
|
+
*/
|
|
12
|
+
export type HoverTarget<T = unknown> = RangeFloatTarget<T>;
|
|
20
13
|
/** The context passed to a {@link HoverTipLayerProps} render-prop. */
|
|
21
14
|
export interface HoverTipRender<T = unknown> {
|
|
22
15
|
/** The anchored range. */
|
|
23
16
|
range: RangeCoords;
|
|
24
17
|
/** The probe payload. */
|
|
25
18
|
data: T;
|
|
26
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* Spread onto the tip element to keep it open while hovered (`pointer-events:auto` + enter/leave).
|
|
21
|
+
* The same object {@link RangeFloatLayer} calls `floatProps`.
|
|
22
|
+
*/
|
|
27
23
|
tipProps: HoverTipProps;
|
|
28
24
|
/** The resolved sticky state (e.g. `state.scrollIntoView()`). */
|
|
29
25
|
state: StickyState;
|
|
@@ -31,44 +27,21 @@ export interface HoverTipRender<T = unknown> {
|
|
|
31
27
|
/**
|
|
32
28
|
* Props for {@link HoverTipLayer}.
|
|
33
29
|
*/
|
|
34
|
-
export interface HoverTipLayerProps<T = unknown> extends Omit<
|
|
35
|
-
/** Class for the floated tip container. */
|
|
36
|
-
className?: string;
|
|
37
|
-
/** Style for the floated tip container. */
|
|
38
|
-
style?: React.CSSProperties;
|
|
30
|
+
export interface HoverTipLayerProps<T = unknown> extends Omit<RangeFloatLayerProps<T>, 'activateOn' | 'selection' | 'target' | 'probe' | 'children'> {
|
|
39
31
|
/** Probe the hovered cell → a {@link HoverTarget} (range + data), or `null` when nothing should show. */
|
|
40
32
|
probe: (coords: CellCoords, pane: IGridPane) => HoverTarget<T> | null;
|
|
41
|
-
/** Which side of the range the tip attaches to. @defaultValue `{ side: 't' }` */
|
|
42
|
-
placement?: GridPlacement;
|
|
43
|
-
/** Gap (px) perpendicular to the edge. @defaultValue 6 */
|
|
44
|
-
offset?: number;
|
|
45
|
-
/** Offset (px) along the edge (only `start` / `end` align). @defaultValue 0 */
|
|
46
|
-
alignOffset?: number;
|
|
47
|
-
/** Dwell (ms) before the tip shows. @defaultValue 300 */
|
|
48
|
-
openDelay?: number;
|
|
49
|
-
/** Grace (ms) before the tip hides (bridges the gap to the tip). @defaultValue 150 */
|
|
50
|
-
closeDelay?: number;
|
|
51
|
-
/** What happens when the anchor leaves the data area. @defaultValue 'hide' */
|
|
52
|
-
whenOff?: GridWhenOff;
|
|
53
|
-
/** Clip / clamp boundary. @defaultValue 'data' */
|
|
54
|
-
boundary?: GridBoundary;
|
|
55
|
-
/** @defaultValue 1250 */
|
|
56
|
-
zIndex?: number;
|
|
57
|
-
/**
|
|
58
|
-
* Edge-triggered hard dismissal: when this transitions truthy the current tip closes **immediately**
|
|
59
|
-
* (bypassing `closeDelay`) — e.g. the anchored cell entered edit mode. It does not hold the tip
|
|
60
|
-
* closed; a subsequent hover re-opens it normally.
|
|
61
|
-
*/
|
|
62
|
-
dismiss?: boolean;
|
|
63
33
|
/** Render the tip. **Spread `tipProps`** on the returned element so hovering it keeps the tip open. */
|
|
64
34
|
children: (info: HoverTipRender<T>) => React.ReactNode;
|
|
65
35
|
}
|
|
66
36
|
/**
|
|
67
|
-
* The
|
|
68
|
-
* `
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
37
|
+
* The **hover preset** of {@link RangeFloatLayer} — `activateOn: 'hover'`, with the render-prop's
|
|
38
|
+
* `floatProps` surfaced under its original name `tipProps`.
|
|
39
|
+
*
|
|
40
|
+
* @remarks
|
|
41
|
+
* The engine (pointer tap, hover intent, anchoring, dismissal) lives in {@link RangeFloatLayer}; this
|
|
42
|
+
* is the ergonomic entry point for the pure-tooltip case and the shape `CellErrorLayer` uses. Reach
|
|
43
|
+
* for `RangeFloatLayer` directly when the float is activated by the selection, driven by a gesture, or
|
|
44
|
+
* is something other than a tip.
|
|
72
45
|
*/
|
|
73
46
|
export declare const HoverTipLayer: <T>(props: HoverTipLayerProps<T>) => React.ReactElement;
|
|
74
47
|
//# sourceMappingURL=HoverTipLayer.d.ts.map
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { CellCoords, RangeCoords } from '@sheetxl/utils';
|
|
3
|
+
import { IGridPane } from '../surface';
|
|
4
|
+
import { ICellAnchor } from '../selection/ICellAnchor';
|
|
5
|
+
import { LayerProps } from './Layer';
|
|
6
|
+
import { StickyState } from './StickyAnchor';
|
|
7
|
+
import { HoverTipProps } from './useHoverIntent';
|
|
8
|
+
import { GridPlacement, GridWhenOff, GridBoundary } from './useGridAnchor';
|
|
9
|
+
/**
|
|
10
|
+
* How the layer decides WHICH range is floating.
|
|
11
|
+
*
|
|
12
|
+
* - `'hover'` — the pointer, through the shared hover intent (open / close delays, keep-open-on-float).
|
|
13
|
+
* - `'selection'` — the active cell of {@link RangeFloatLayerProps.selection}, with no delay: a resting
|
|
14
|
+
* affordance, not a transient tip.
|
|
15
|
+
*
|
|
16
|
+
* Pass an array to accept EITHER (`['hover','selection']` — not an AND; each one opens the float on its
|
|
17
|
+
* own). Omit entirely and drive {@link RangeFloatLayerProps.target} yourself (gesture-driven action
|
|
18
|
+
* popups — paste options, autofill options).
|
|
19
|
+
*/
|
|
20
|
+
export type RangeFloatActivation = 'hover' | 'selection';
|
|
21
|
+
/** A hit from a {@link RangeFloatLayerProps.probe} — the range to anchor on plus arbitrary payload. */
|
|
22
|
+
export interface RangeFloatTarget<T = unknown> {
|
|
23
|
+
/** The range the float anchors to (e.g. the cell's own range, a merge, or an enclosing table). */
|
|
24
|
+
range: RangeCoords;
|
|
25
|
+
/**
|
|
26
|
+
* Stable identity for dedupe — the float re-opens only when this changes (a `pointermove` storm
|
|
27
|
+
* within one target is a no-op). Defaults to the range's coords.
|
|
28
|
+
*/
|
|
29
|
+
key?: string;
|
|
30
|
+
/** Payload passed to the render-prop (the message, the validation, the table, …). */
|
|
31
|
+
data: T;
|
|
32
|
+
/**
|
|
33
|
+
* Where this target's float attaches, for a layer whose targets do not all belong on one side.
|
|
34
|
+
* Defaults to the layer's {@link RangeFloatLayerProps.placement}.
|
|
35
|
+
*/
|
|
36
|
+
placement?: GridPlacement;
|
|
37
|
+
}
|
|
38
|
+
/** The context passed to a {@link RangeFloatLayerProps} render-prop. */
|
|
39
|
+
export interface RangeFloatRender<T = unknown> {
|
|
40
|
+
/** The anchored range. */
|
|
41
|
+
range: RangeCoords;
|
|
42
|
+
/** The probe payload. */
|
|
43
|
+
data: T;
|
|
44
|
+
/**
|
|
45
|
+
* Spread onto the floated element. Supplies `pointer-events: auto` (a layer's box never takes the
|
|
46
|
+
* pointer, so content must opt back in) and — under `'hover'` — the enter/leave handlers that keep
|
|
47
|
+
* the float open while the pointer is on it.
|
|
48
|
+
*/
|
|
49
|
+
floatProps: HoverTipProps;
|
|
50
|
+
/** The resolved sticky state (e.g. `state.scrollIntoView()`, `state.slid`). */
|
|
51
|
+
state: StickyState;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Props for {@link RangeFloatLayer}.
|
|
55
|
+
*/
|
|
56
|
+
export interface RangeFloatLayerProps<T = unknown> extends Omit<LayerProps, 'children'> {
|
|
57
|
+
/** Class for the floated container. */
|
|
58
|
+
className?: string;
|
|
59
|
+
/** Style for the floated container. */
|
|
60
|
+
style?: React.CSSProperties;
|
|
61
|
+
/**
|
|
62
|
+
* What makes a float appear. Omit to drive {@link target} yourself.
|
|
63
|
+
* @defaultValue none (controlled)
|
|
64
|
+
*/
|
|
65
|
+
activateOn?: RangeFloatActivation | readonly RangeFloatActivation[];
|
|
66
|
+
/**
|
|
67
|
+
* Identity for the hover state this layer brokers across its per-pane copies. Defaults to the
|
|
68
|
+
* layer's z-slot, which is already unique per grid child — pass one only when a SINGLE grid child
|
|
69
|
+
* hosts more than one `RangeFloatLayer` (they would otherwise share a cell and fight).
|
|
70
|
+
*/
|
|
71
|
+
name?: string;
|
|
72
|
+
/**
|
|
73
|
+
* Ask whether a cell has something to float — the anchor range + payload, or `null` for nothing.
|
|
74
|
+
* Called with the hovered cell (`'hover'`) and with the selection's active cell (`'selection'`), so
|
|
75
|
+
* one probe serves both. Not needed when {@link target} is controlled.
|
|
76
|
+
*/
|
|
77
|
+
probe?: (coords: CellCoords, pane: IGridPane) => RangeFloatTarget<T> | null;
|
|
78
|
+
/**
|
|
79
|
+
* The selection to follow for `activateOn: 'selection'`. An {@link ICellAnchor} rather than a full
|
|
80
|
+
* selection — the layer only ever reads the active cell and subscribes to it.
|
|
81
|
+
*/
|
|
82
|
+
selection?: ICellAnchor;
|
|
83
|
+
/**
|
|
84
|
+
* Controlled target: supply it (including `null`) and the layer floats exactly what you say,
|
|
85
|
+
* ignoring `activateOn` / `probe`. The escape hatch for gesture-driven popups whose lifetime is the
|
|
86
|
+
* action's, not the pointer's.
|
|
87
|
+
*/
|
|
88
|
+
target?: RangeFloatTarget<T> | null;
|
|
89
|
+
/**
|
|
90
|
+
* Hard close. Under `'hover'` it is **edge-triggered**: the float drops now, bypassing `closeDelay`,
|
|
91
|
+
* and a later hover re-opens normally. Under `'selection'` there is no gesture to re-arm it, so it
|
|
92
|
+
* reads as a **level**: the float stays closed while this holds and returns when it clears (e.g. the
|
|
93
|
+
* anchored cell is in edit mode). Ignored when {@link target} is controlled — the lifetime is yours
|
|
94
|
+
* there, so close it by passing `null`.
|
|
95
|
+
*/
|
|
96
|
+
dismiss?: boolean;
|
|
97
|
+
/** Which side of the range the float attaches to. @defaultValue `{ side: 't' }` */
|
|
98
|
+
placement?: GridPlacement;
|
|
99
|
+
/** Gap (px) perpendicular to the edge. @defaultValue 6 */
|
|
100
|
+
offset?: number;
|
|
101
|
+
/** Offset (px) along the edge (only `start` / `end` align). @defaultValue 0 */
|
|
102
|
+
alignOffset?: number;
|
|
103
|
+
/** Dwell (ms) before a hovered float shows. @defaultValue 300 */
|
|
104
|
+
openDelay?: number;
|
|
105
|
+
/** Grace (ms) before a hovered float hides (bridges the gap to the float). @defaultValue 150 */
|
|
106
|
+
closeDelay?: number;
|
|
107
|
+
/** What happens when the anchor leaves the data area. @defaultValue 'hide' */
|
|
108
|
+
whenOff?: GridWhenOff;
|
|
109
|
+
/** Where the float may live. @defaultValue 'data' */
|
|
110
|
+
boundary?: GridBoundary;
|
|
111
|
+
/** @defaultValue 1250 */
|
|
112
|
+
zIndex?: number;
|
|
113
|
+
/** Render the float. **Spread `floatProps`** on the returned element. */
|
|
114
|
+
children: (info: RangeFloatRender<T>) => React.ReactNode;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* The **range float layer**: content anchored to a range that portals out of the pane clip. It owns
|
|
118
|
+
* the three things every such float needs — **anchoring** (a {@link StickyFloat} on the probed range),
|
|
119
|
+
* **activation** (what makes it appear) and **dismissal**. What it draws is entirely the consumer's:
|
|
120
|
+
* a tooltip, a button, a toolbar, an action popup.
|
|
121
|
+
*
|
|
122
|
+
* @remarks
|
|
123
|
+
* This is the **float half** of the grid's two mechanisms. A `CellTileDiv` covers everything whose
|
|
124
|
+
* content is a function of the cell alone — clicks and hover styling included — as a cached DOM
|
|
125
|
+
* snapshot. A float is for content that depends on transient UI state (selection, hover, open/closed)
|
|
126
|
+
* or that must leave the cell box. "Only on the active cell" is the expensive predicate: it would
|
|
127
|
+
* dirty a tile per selection move, which is exactly why it belongs here.
|
|
128
|
+
*
|
|
129
|
+
* Activation is pluggable and the rest of the layer is identical across the choices:
|
|
130
|
+
*
|
|
131
|
+
* ```tsx
|
|
132
|
+
* <RangeFloatLayer activateOn="hover" probe={probeError}>
|
|
133
|
+
* {({ data, floatProps }) => <div {...floatProps}>{data.message}</div>}
|
|
134
|
+
* </RangeFloatLayer>
|
|
135
|
+
*
|
|
136
|
+
* <RangeFloatLayer activateOn="selection" selection={selection} probe={probeList}>
|
|
137
|
+
* {({ range, floatProps }) => <Chevron {...floatProps} onPointerDown={() => open(range)} />}
|
|
138
|
+
* </RangeFloatLayer>
|
|
139
|
+
* ```
|
|
140
|
+
*
|
|
141
|
+
* When either can activate it, hover is the transient override and selection is the resting state:
|
|
142
|
+
* while the pointer holds a target the float shows that one, and it falls back to the selection's when
|
|
143
|
+
* the pointer leaves.
|
|
144
|
+
*/
|
|
145
|
+
export declare const RangeFloatLayer: <T>(props: RangeFloatLayerProps<T>) => React.ReactElement;
|
|
146
|
+
//# sourceMappingURL=RangeFloatLayer.d.ts.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
2
|
import { Bounds, Point, AnchorLocation } from '@sheetxl/utils';
|
|
3
3
|
import { IGridPane } from '../surface';
|
|
4
|
-
import { GridAnchor, GridPlacement, GridBoundary, GridWhenOff, GridSlide } from './useGridAnchor';
|
|
4
|
+
import { GridAnchor, GridAnchorReference, GridPlacement, GridBoundary, GridWhenOff, GridSlide } from './useGridAnchor';
|
|
5
5
|
/**
|
|
6
6
|
* The state a {@link StickyAnchor} publishes to its child. Carries the resolved `anchorPoint` (+ owner /
|
|
7
7
|
* clip / slide state) so the child alone decides how to render:
|
|
@@ -14,9 +14,7 @@ import { GridAnchor, GridPlacement, GridBoundary, GridWhenOff, GridSlide } from
|
|
|
14
14
|
*/
|
|
15
15
|
export interface StickyState {
|
|
16
16
|
/** Client-space Floating UI virtual reference (stable identity; reads live). */
|
|
17
|
-
reference:
|
|
18
|
-
getBoundingClientRect: () => DOMRect;
|
|
19
|
-
};
|
|
17
|
+
reference: GridAnchorReference;
|
|
20
18
|
/** Client-space boundary rect (for `flip`/`shift`/`hide` limiters). */
|
|
21
19
|
getBoundaryRect: () => DOMRect;
|
|
22
20
|
/** The placement's anchor pixel (client px). */
|
|
@@ -32,7 +32,10 @@ export interface StickyFloatProps {
|
|
|
32
32
|
placement?: GridPlacement;
|
|
33
33
|
/** What happens when the anchor leaves the data area. @defaultValue 'hide' */
|
|
34
34
|
whenOff?: GridWhenOff;
|
|
35
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* Where the float may LIVE — one rect, resolved by {@link GridBoundary}: it is both the anchor's
|
|
37
|
+
* clip / clamp boundary and the rect `flip` / `shift` collide against. @defaultValue 'data'
|
|
38
|
+
*/
|
|
36
39
|
boundary?: GridBoundary;
|
|
37
40
|
/** Px overlap below which a geometried anchor reads as clipped. @defaultValue 0 */
|
|
38
41
|
minVisible?: number;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
export * from './LayerTypes';
|
|
2
2
|
export * from './Layer';
|
|
3
3
|
export * from './VirtualDiv';
|
|
4
|
-
export type { GridAnchor, GridPlacement, GridWhenOff, GridBoundary, GridFloatSide, GridAlign, GridSlide } from './useGridAnchor';
|
|
4
|
+
export type { GridAnchor, GridAnchorReference, GridPlacement, GridWhenOff, GridBoundary, GridFloatSide, GridAlign, GridSlide } from './useGridAnchor';
|
|
5
5
|
export * from './StickyAnchor';
|
|
6
6
|
export * from './StickyFloat';
|
|
7
|
+
export * from './GridFloatPanel';
|
|
7
8
|
export * from './useHoverIntent';
|
|
8
9
|
export * from './useRangeHover';
|
|
10
|
+
export * from './RangeFloatLayer';
|
|
9
11
|
export * from './HoverTipLayer';
|
|
10
12
|
export * from './RangePrompt';
|
|
11
13
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -60,15 +60,18 @@ export type GridAnchor = {
|
|
|
60
60
|
point: Point;
|
|
61
61
|
};
|
|
62
62
|
/**
|
|
63
|
-
* The clip / clamp boundary — a **rect fed to the positioning math**, NOT a DOM parent.
|
|
64
|
-
*
|
|
63
|
+
* The clip / clamp boundary — a **rect fed to the positioning math**, NOT a DOM parent. One prop, one
|
|
64
|
+
* meaning: *where may this thing live*. It governs the anchor's clip / clamp AND (via `StickyFloat`)
|
|
65
|
+
* where `flip` / `shift` may land the float. This is how "don't slide under the headers" is expressed:
|
|
66
|
+
* clamp to the data viewport.
|
|
65
67
|
*
|
|
66
68
|
* - `'data'` — the union of the panes' cell areas (headers excluded). Default.
|
|
67
69
|
* - `'pane'` — just the resolving pane's cell area.
|
|
68
70
|
* - `'grid'` — currently the same as `'data'` (until a surface/header rect is threaded).
|
|
71
|
+
* - `'viewport'` — the browser viewport: the opt-out, for a float that may cover grid chrome.
|
|
69
72
|
* - a {@link Bounds} — an explicit **client-px** rect.
|
|
70
73
|
*/
|
|
71
|
-
export type GridBoundary = 'data' | 'pane' | 'grid' | Bounds;
|
|
74
|
+
export type GridBoundary = 'data' | 'pane' | 'grid' | 'viewport' | Bounds;
|
|
72
75
|
/** A `DOMRect`-shaped plain object (works in Floating UI and in Node tests without a DOM). */
|
|
73
76
|
export interface GridAnchorRect {
|
|
74
77
|
x: number;
|
|
@@ -106,15 +109,29 @@ export interface GridAnchorResolved {
|
|
|
106
109
|
*/
|
|
107
110
|
outOfView: boolean;
|
|
108
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* The Floating UI **virtual reference** for a grid anchor. Stable identity (so `autoUpdate` subscribes
|
|
114
|
+
* once), but both members read **live**.
|
|
115
|
+
*/
|
|
116
|
+
export interface GridAnchorReference {
|
|
117
|
+
/** The anchor's client rect, read live on every call (`autoUpdate` calls it between React renders). */
|
|
118
|
+
getBoundingClientRect: () => DOMRect;
|
|
119
|
+
/**
|
|
120
|
+
* The pane element. `autoUpdate` unwraps a virtual reference to *this* element and gates **every**
|
|
121
|
+
* DOM-side trigger on it — ancestor `scroll`, the `observeMove` layout-shift detector, element resize.
|
|
122
|
+
* Without it only the window `resize` listener survives, which is why the float used to need a 60fps
|
|
123
|
+
* `animationFrame` poll. A **getter**: the pane element only exists after mount, and resolving it
|
|
124
|
+
* lazily keeps this object's identity stable.
|
|
125
|
+
*/
|
|
126
|
+
readonly contextElement?: Element;
|
|
127
|
+
}
|
|
109
128
|
/** The hook result: stable live accessors + render-time snapshot values. */
|
|
110
129
|
export interface UseGridAnchorResult {
|
|
111
130
|
/**
|
|
112
131
|
* A Floating UI **virtual reference** with **stable identity** — its `getBoundingClientRect` reads
|
|
113
132
|
* the anchor **live** on every call (Floating UI's `autoUpdate` invokes it between React renders).
|
|
114
133
|
*/
|
|
115
|
-
reference:
|
|
116
|
-
getBoundingClientRect: () => DOMRect;
|
|
117
|
-
};
|
|
134
|
+
reference: GridAnchorReference;
|
|
118
135
|
/** Live accessor for the boundary rect (for `shift`/`flip`/`hide` limiters). */
|
|
119
136
|
getBoundaryRect: () => DOMRect;
|
|
120
137
|
/** Render-time snapshot: anchor outside the boundary. Updates each scroll frame (pane re-render). */
|
|
@@ -26,10 +26,11 @@ export interface UseRangeHoverResult {
|
|
|
26
26
|
*
|
|
27
27
|
* @remarks
|
|
28
28
|
* Registers a passive `pointermove` / `pointerleave` responder on the pane's Stage (mirrors
|
|
29
|
-
* a {@link Layer} tap); it never consumes the event. Because a grid child renders per pane, the
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* the
|
|
29
|
+
* a {@link Layer} tap); it never consumes the event. Because a grid child renders per pane, the pointer
|
|
30
|
+
* is seen by whichever pane it is over while the tip renders on the pane owning the anchor — which for
|
|
31
|
+
* a range straddling a freeze is a DIFFERENT pane. The aimed target is therefore brokered through
|
|
32
|
+
* {@link useSurfaceState}, so every pane copy runs its intent off the same signal and the owner is
|
|
33
|
+
* armed no matter where the pointer is.
|
|
33
34
|
*/
|
|
34
35
|
export declare const useRangeHover: (range: RangeCoords, options?: UseHoverIntentOptions) => UseRangeHoverResult;
|
|
35
36
|
//# sourceMappingURL=useRangeHover.d.ts.map
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
2
|
import { ISelection } from '../selection';
|
|
3
|
+
import { ListProps } from './List';
|
|
3
4
|
export interface CheckboxListAttributes {
|
|
4
5
|
isCheckboxList: () => true;
|
|
6
|
+
/** The highlighted row, or `-1` when the list is empty. */
|
|
7
|
+
getHighlightIndex: () => number;
|
|
8
|
+
/** Move the highlight `delta` rows (clamped to the list) and bring it into view. */
|
|
9
|
+
moveHighlight: (delta: number) => void;
|
|
10
|
+
/** Toggle the selected rows, as Space does: the anchor's opposite, applied to every one of them. */
|
|
11
|
+
toggleHighlighted: () => void;
|
|
5
12
|
}
|
|
6
13
|
export interface ICheckboxListElement extends HTMLDivElement, CheckboxListAttributes {
|
|
7
14
|
}
|
|
@@ -41,6 +48,10 @@ export interface CheckboxListProps extends React.HTMLAttributes<HTMLDivElement>
|
|
|
41
48
|
selection?: ISelection;
|
|
42
49
|
/** Content cache-bust; bump when checked state changes without `isChecked`'s identity changing. */
|
|
43
50
|
cacheToken?: unknown;
|
|
51
|
+
/** See `ListSurfaceProps.autoFocus`. */
|
|
52
|
+
autoFocus?: boolean;
|
|
53
|
+
/** See `ListSurfaceProps.viewport`. */
|
|
54
|
+
viewport?: ListProps['viewport'];
|
|
44
55
|
/** Ref for the Element. */
|
|
45
56
|
ref?: React.Ref<ICheckboxListElement>;
|
|
46
57
|
}
|
package/types/src/list/List.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
2
|
import { ISelection } from '../selection';
|
|
3
|
+
import { ListSurface } from './ListSurface';
|
|
3
4
|
export interface ListAttributes {
|
|
4
5
|
isList: () => true;
|
|
5
6
|
}
|
|
@@ -36,20 +37,28 @@ export interface ListProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
36
37
|
* *rendered* content changed without `renderItem`'s identity changing.
|
|
37
38
|
*/
|
|
38
39
|
cacheToken?: unknown;
|
|
40
|
+
/** See `ListSurfaceProps.scrollTo`. */
|
|
41
|
+
scrollTo?: {
|
|
42
|
+
row: number;
|
|
43
|
+
} | null;
|
|
44
|
+
/** See `ListSurfaceProps.autoFocus`. */
|
|
45
|
+
autoFocus?: boolean;
|
|
46
|
+
/** See `ListSurfaceProps.viewport`. */
|
|
47
|
+
viewport?: React.ComponentProps<typeof ListSurface>['viewport'];
|
|
39
48
|
/** Ref for the Element. */
|
|
40
49
|
ref?: React.Ref<IListElement>;
|
|
41
50
|
}
|
|
42
51
|
/**
|
|
43
|
-
* A virtualized **list**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
52
|
+
* A virtualized **list** of arbitrary React content, built on {@link ListSurface} — which is the
|
|
53
|
+
* grid's own machinery (a `CellLayer` for the items and a `SelectionLayer` for the active-row
|
|
54
|
+
* highlight + Arrow keys) dressed as a list.
|
|
46
55
|
*
|
|
47
56
|
* @remarks
|
|
48
57
|
* The List's whole state is its {@link ListProps.selection}; it has no per-item callbacks and no notion
|
|
49
58
|
* of "checked" or "toggle". Pointer selection is the `SelectionLayer`'s job (it hit-tests the pointer),
|
|
50
59
|
* so the cells are inert, transparent content; the keyboard is the caller's via {@link ListProps.onKeyDown}.
|
|
51
|
-
*
|
|
52
|
-
*
|
|
60
|
+
* See {@link CheckboxList} for the checkbox-list specialization and {@link PickList} for the
|
|
61
|
+
* single-choice text list.
|
|
53
62
|
*/
|
|
54
63
|
export declare const List: React.ForwardRefExoticComponent<Omit<ListProps, "ref"> & React.RefAttributes<IListElement>>;
|
|
55
64
|
//# sourceMappingURL=List.d.ts.map
|