@sheetxl/grid-react 0.8.0-beta.1 → 0.8.0-beta.10
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/README.md +16 -5
- package/browser/esm/index.mjs +3419 -2810
- package/licenses/dependencies.txt +0 -208
- package/node/esm/index.mjs +3699 -2172
- package/package.json +8 -12
- package/types/src/cell/CellRenderer.d.ts +14 -3
- package/types/src/editor/DefaultEditable.d.ts +23 -4
- package/types/src/editor/EditSession.d.ts +34 -5
- package/types/src/editor/EditState.d.ts +6 -0
- package/types/src/editor/EditorInput.d.ts +7 -3
- package/types/src/editor/EditorLayer.d.ts +9 -4
- package/types/src/editor/EditorStartLayer.d.ts +32 -0
- package/types/src/editor/index.d.ts +1 -0
- package/types/src/editor/useEditorKeymap.d.ts +18 -2
- package/types/src/header/GridFreezeAnchor.d.ts +29 -0
- package/types/src/header/HeaderDividerAnchor.d.ts +29 -0
- 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 +10 -6
- package/types/src/layer/GestureTip.d.ts +69 -0
- package/types/src/layer/GridFloatPanel.d.ts +19 -0
- package/types/src/layer/Layer.d.ts +6 -0
- package/types/src/layer/RangeFloatLayer.d.ts +143 -51
- package/types/src/layer/RangePrompt.d.ts +8 -8
- package/types/src/layer/RangeTooltip.d.ts +123 -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 +101 -0
- package/types/src/layer/index.d.ts +7 -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 +22 -1
- package/types/src/list/List.d.ts +11 -2
- package/types/src/list/ListSearch.d.ts +52 -0
- package/types/src/list/ListSurface.d.ts +25 -5
- 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 +2 -0
- package/types/src/range/DragHandle.d.ts +19 -2
- package/types/src/range/Draggable.d.ts +132 -7
- package/types/src/range/FillHandle.d.ts +33 -3
- 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 +128 -15
- package/types/src/selection/SelectionStyle.d.ts +33 -0
- package/types/src/selection/SelectionTouchGrips.d.ts +0 -4
- package/types/src/selection/_SelectionUtils.d.ts +6 -0
- package/types/src/selection/useDragCells.d.ts +65 -9
- package/types/src/surface/useSurfaceState.d.ts +19 -0
- package/types/src/svg/_Glide.d.ts +9 -0
- 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
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { GridAnchor, GridPlacement, GridBoundary } from './useGridAnchor';
|
|
3
|
+
/**
|
|
4
|
+
* A gesture readout anchored to a DOM element rather than to the grid — a scrollbar thumb, which lives
|
|
5
|
+
* outside every pane. The element moves with the drag and no DOM event says so, so the readout is
|
|
6
|
+
* repositioned each time it renders: the owner re-renders it as the gesture moves (as it changes the text).
|
|
7
|
+
*/
|
|
8
|
+
export interface GestureTipElementAnchor {
|
|
9
|
+
element: Element;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* How a {@link GestureTip} travels between positions.
|
|
13
|
+
*/
|
|
14
|
+
export interface GestureTipGlide {
|
|
15
|
+
/** How long a move takes, in ms. `0` jumps. */
|
|
16
|
+
duration: number;
|
|
17
|
+
/** The CSS easing it travels on. @defaultValue 'ease-in-out' */
|
|
18
|
+
easing?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Props for {@link GestureTip}.
|
|
22
|
+
*/
|
|
23
|
+
export interface GestureTipProps {
|
|
24
|
+
/**
|
|
25
|
+
* The gesture is in flight. While it is, the tip holds the tooltip group — no hover tip opens — even
|
|
26
|
+
* when there is nothing to say (`children` empty).
|
|
27
|
+
*/
|
|
28
|
+
active: boolean;
|
|
29
|
+
/** What the readout anchors to — the in-flight range, a frame's bounds, or a dragged element. */
|
|
30
|
+
anchor: GridAnchor | GestureTipElementAnchor;
|
|
31
|
+
/** Which side + align of the anchor the readout sits on. @defaultValue `{ side: 'b', align: 'end' }` */
|
|
32
|
+
placement?: GridPlacement;
|
|
33
|
+
/** Gap (px) between the anchor and the readout. @defaultValue 8 */
|
|
34
|
+
offset?: number;
|
|
35
|
+
/** Offset (px) along the anchored edge (only `start` / `end` align). @defaultValue 0 */
|
|
36
|
+
alignOffset?: number;
|
|
37
|
+
/**
|
|
38
|
+
* Glide to each new position instead of jumping. Pass the timing of an anchor that glides itself (a
|
|
39
|
+
* move ghost) so the readout travels with it. Where it first appears is never animated.
|
|
40
|
+
* @defaultValue none — a readout jumps with its gesture
|
|
41
|
+
*/
|
|
42
|
+
glide?: GestureTipGlide;
|
|
43
|
+
/** Where the readout may live (a grid anchor only). @defaultValue 'data' */
|
|
44
|
+
boundary?: GridBoundary;
|
|
45
|
+
/**
|
|
46
|
+
* Whose theme the readout wears. A readout is chrome, so the app's — even over a grid in another mode.
|
|
47
|
+
* @defaultValue 'provider'
|
|
48
|
+
*/
|
|
49
|
+
themeFrom?: 'provider' | 'anchor';
|
|
50
|
+
/**
|
|
51
|
+
* The tip's identity in the tooltip group. A layer rendered once per pane passes one name so its
|
|
52
|
+
* copies count as one tip.
|
|
53
|
+
* @defaultValue this instance
|
|
54
|
+
*/
|
|
55
|
+
name?: string;
|
|
56
|
+
className?: string;
|
|
57
|
+
/** The readout. Empty draws nothing (the group is still held while {@link active}). */
|
|
58
|
+
children?: React.ReactNode;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The readout a gesture shows while it runs — a drag-select's size, a move's destination, a fill's
|
|
62
|
+
* value, a frame's size, a header's size, the row a scrollbar thumb is at. A tooltip of the gesture
|
|
63
|
+
* kind: it opens with the gesture (no dwell), holds the tooltip group so no hover tip opens beside it,
|
|
64
|
+
* closes when the gesture ends, and takes no pointer (the gesture owns it). Drawn in the group's
|
|
65
|
+
* bubble, in the tooltip band and the app's theme; on a grid anchor, `clamp`ed so it stays on screen
|
|
66
|
+
* when the anchor runs off the grid.
|
|
67
|
+
*/
|
|
68
|
+
export declare const GestureTip: React.FC<GestureTipProps>;
|
|
69
|
+
//# sourceMappingURL=GestureTip.d.ts.map
|
|
@@ -0,0 +1,19 @@
|
|
|
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 StickyPortal}, 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. It sits in the popup band, above the
|
|
12
|
+
* grid's other floats (its buttons and labels).
|
|
13
|
+
*
|
|
14
|
+
* The stack's `propsPopper` `placement` and `offsets` are read as the grid placement and offset.
|
|
15
|
+
*/
|
|
16
|
+
export declare const GridFloatPanel: React.FC<FloatPanelProps>;
|
|
17
|
+
/** {@link GridFloatPanel} as a `useFloatStack` `renderFloatPanel`. */
|
|
18
|
+
export declare const renderGridFloatPanel: (props: FloatPanelProps) => React.ReactElement;
|
|
19
|
+
//# sourceMappingURL=GridFloatPanel.d.ts.map
|
|
@@ -62,6 +62,12 @@ export interface LayerProps extends LayerEventProps {
|
|
|
62
62
|
zIndex?: number;
|
|
63
63
|
/** Class for the layer's boundary div (devtools identification). */
|
|
64
64
|
className?: string;
|
|
65
|
+
/**
|
|
66
|
+
* Style for the layer's boundary div — e.g. `display: 'none'` or `opacity` to hide or fade a layer.
|
|
67
|
+
* The boundary's own placement (`position`, `inset`, `pointer-events: none`) comes from the grid;
|
|
68
|
+
* overriding it here breaks the layer's containment.
|
|
69
|
+
*/
|
|
70
|
+
style?: React.CSSProperties;
|
|
65
71
|
/**
|
|
66
72
|
* The layer's content — {@link VirtualDiv}s, `RangeRect`s, floats — hosted inside the layer's
|
|
67
73
|
* boundary div. Children stack by DOM order within the layer (law 1).
|
|
@@ -5,20 +5,21 @@ import { ICellAnchor } from '../selection/ICellAnchor';
|
|
|
5
5
|
import { LayerProps } from './Layer';
|
|
6
6
|
import { StickyState } from './StickyAnchor';
|
|
7
7
|
import { HoverTipProps } from './useHoverIntent';
|
|
8
|
-
import { GridPlacement, GridWhenOff, GridBoundary } from './useGridAnchor';
|
|
8
|
+
import { GridPlacement, GridWhenOff, GridWhenPartial, GridBoundary } from './useGridAnchor';
|
|
9
9
|
/**
|
|
10
|
-
* How
|
|
10
|
+
* How {@link RangeFloatLayer} decides WHICH range is floating.
|
|
11
11
|
*
|
|
12
|
-
* - `'hover'` — the pointer, through the
|
|
12
|
+
* - `'hover'` — the pointer, through the tooltip group's hover intent (its timing, single-open rule and
|
|
13
|
+
* keep-open-on-float); `RangeTooltipLayer` is this, with the group's bubble.
|
|
13
14
|
* - `'selection'` — the active cell of {@link RangeFloatLayerProps.selection}, with no delay: a resting
|
|
14
15
|
* affordance, not a transient tip.
|
|
15
16
|
*
|
|
16
17
|
* 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
|
|
18
|
+
* own). Omit entirely and drive {@link RangeFloatOptions.target} yourself (gesture-driven action
|
|
18
19
|
* popups — paste options, autofill options).
|
|
19
20
|
*/
|
|
20
21
|
export type RangeFloatActivation = 'hover' | 'selection';
|
|
21
|
-
/** A hit from a
|
|
22
|
+
/** A hit from a probe — the range to anchor on plus arbitrary payload. */
|
|
22
23
|
export interface RangeFloatTarget<T = unknown> {
|
|
23
24
|
/** The range the float anchors to (e.g. the cell's own range, a merge, or an enclosing table). */
|
|
24
25
|
range: RangeCoords;
|
|
@@ -29,8 +30,18 @@ export interface RangeFloatTarget<T = unknown> {
|
|
|
29
30
|
key?: string;
|
|
30
31
|
/** Payload passed to the render-prop (the message, the validation, the table, …). */
|
|
31
32
|
data: T;
|
|
33
|
+
/**
|
|
34
|
+
* Where this target's float attaches, for a float whose targets do not all belong on one side.
|
|
35
|
+
* Defaults to the float's {@link RangeFloatOptions.placement}.
|
|
36
|
+
*/
|
|
37
|
+
placement?: GridPlacement;
|
|
38
|
+
/**
|
|
39
|
+
* Offset (px) along the edge for this target, for a float whose offset depends on the anchor (e.g.
|
|
40
|
+
* a fraction of its width). Defaults to the float's {@link RangeFloatOptions.alignOffset}.
|
|
41
|
+
*/
|
|
42
|
+
alignOffset?: number;
|
|
32
43
|
}
|
|
33
|
-
/** The context passed to a
|
|
44
|
+
/** The context passed to a range float's render-prop. */
|
|
34
45
|
export interface RangeFloatRender<T = unknown> {
|
|
35
46
|
/** The anchored range. */
|
|
36
47
|
range: RangeCoords;
|
|
@@ -38,55 +49,52 @@ export interface RangeFloatRender<T = unknown> {
|
|
|
38
49
|
data: T;
|
|
39
50
|
/**
|
|
40
51
|
* Spread onto the floated element. Supplies `pointer-events: auto` (a layer's box never takes the
|
|
41
|
-
* pointer, so content must opt back in) and —
|
|
42
|
-
*
|
|
52
|
+
* pointer, so content must opt back in) and — for a hovered float — the enter/leave handlers that
|
|
53
|
+
* keep it open while the pointer is on it.
|
|
43
54
|
*/
|
|
44
55
|
floatProps: HoverTipProps;
|
|
45
56
|
/** The resolved sticky state (e.g. `state.scrollIntoView()`, `state.slid`). */
|
|
46
57
|
state: StickyState;
|
|
47
58
|
}
|
|
48
59
|
/**
|
|
49
|
-
*
|
|
60
|
+
* How a range float takes part in the UI around it.
|
|
61
|
+
*
|
|
62
|
+
* - `'none'` — takes no pointer at all: a label, a readout, a prompt box.
|
|
63
|
+
* - `'pointer'` — takes the pointer, and its presses, keys, clipboard, context menu and wheel stop at
|
|
64
|
+
* the float: the float is portaled out of the pane, but React events bubble the React TREE, which
|
|
65
|
+
* would carry them to the grid's own handlers. A button, a chevron, a toolbar.
|
|
66
|
+
* - `'focus'` — `'pointer'`, and the float can hold the caret: while focus is inside it stays on its
|
|
67
|
+
* target whatever the pointer does; Escape or a press anywhere outside it (a cell, a menu button, a
|
|
68
|
+
* right-click) closes it, focus returns to the grid, and {@link RangeFloatOptions.onDismiss} is told.
|
|
69
|
+
* "Outside" is judged by the React tree, so a menu the float opens in a portal of its own is inside.
|
|
70
|
+
* A card with a text field.
|
|
50
71
|
*/
|
|
51
|
-
export
|
|
52
|
-
|
|
53
|
-
|
|
72
|
+
export type RangeFloatInteractive = 'none' | 'pointer' | 'focus';
|
|
73
|
+
/**
|
|
74
|
+
* What every range float takes, however it is activated: placement, dismissal, hover timing,
|
|
75
|
+
* interactivity and the render-prop.
|
|
76
|
+
*/
|
|
77
|
+
export interface RangeFloatOptions<T = unknown> {
|
|
54
78
|
/** Style for the floated container. */
|
|
55
79
|
style?: React.CSSProperties;
|
|
56
80
|
/**
|
|
57
|
-
*
|
|
58
|
-
* @defaultValue none (controlled)
|
|
59
|
-
*/
|
|
60
|
-
activateOn?: RangeFloatActivation | readonly RangeFloatActivation[];
|
|
61
|
-
/**
|
|
62
|
-
* Identity for the hover state this layer brokers across its per-pane copies. Defaults to the
|
|
81
|
+
* Identity for the hover state brokered across the float's per-pane copies. Defaults to the host
|
|
63
82
|
* layer's z-slot, which is already unique per grid child — pass one only when a SINGLE grid child
|
|
64
|
-
* hosts more than one
|
|
83
|
+
* hosts more than one range float (they would otherwise share a cell and fight).
|
|
65
84
|
*/
|
|
66
85
|
name?: string;
|
|
67
86
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*/
|
|
72
|
-
probe?: (coords: CellCoords, pane: IGridPane) => RangeFloatTarget<T> | null;
|
|
73
|
-
/**
|
|
74
|
-
* The selection to follow for `activateOn: 'selection'`. An {@link ICellAnchor} rather than a full
|
|
75
|
-
* selection — the layer only ever reads the active cell and subscribes to it.
|
|
76
|
-
*/
|
|
77
|
-
selection?: ICellAnchor;
|
|
78
|
-
/**
|
|
79
|
-
* Controlled target: supply it (including `null`) and the layer floats exactly what you say,
|
|
80
|
-
* ignoring `activateOn` / `probe`. The escape hatch for gesture-driven popups whose lifetime is the
|
|
81
|
-
* action's, not the pointer's.
|
|
87
|
+
* Controlled target: supply it (including `null`) and the float shows exactly what you say, ignoring
|
|
88
|
+
* hover and selection. The escape hatch for gesture-driven popups whose lifetime is the action's,
|
|
89
|
+
* not the pointer's.
|
|
82
90
|
*/
|
|
83
91
|
target?: RangeFloatTarget<T> | null;
|
|
84
92
|
/**
|
|
85
|
-
* Hard close.
|
|
86
|
-
* and a later hover re-opens normally.
|
|
87
|
-
* reads as a **level**: the float stays closed while this holds and returns when it clears
|
|
88
|
-
* anchored cell is in edit mode). Ignored when {@link target} is controlled — the lifetime
|
|
89
|
-
* there, so close it by passing `null`.
|
|
93
|
+
* Hard close. For a hovered float it is **edge-triggered**: the float drops now, bypassing
|
|
94
|
+
* `closeDelay`, and a later hover re-opens normally. For the selection there is no gesture to re-arm
|
|
95
|
+
* it, so it reads as a **level**: the float stays closed while this holds and returns when it clears
|
|
96
|
+
* (e.g. the anchored cell is in edit mode). Ignored when {@link target} is controlled — the lifetime
|
|
97
|
+
* is yours there, so close it by passing `null`.
|
|
90
98
|
*/
|
|
91
99
|
dismiss?: boolean;
|
|
92
100
|
/** Which side of the range the float attaches to. @defaultValue `{ side: 't' }` */
|
|
@@ -95,24 +103,111 @@ export interface RangeFloatLayerProps<T = unknown> extends Omit<LayerProps, 'chi
|
|
|
95
103
|
offset?: number;
|
|
96
104
|
/** Offset (px) along the edge (only `start` / `end` align). @defaultValue 0 */
|
|
97
105
|
alignOffset?: number;
|
|
98
|
-
/** Dwell (ms) before a hovered float shows. @defaultValue 300 */
|
|
106
|
+
/** Dwell (ms) before a hovered float shows. @defaultValue the tooltip group's `enterDelay` (300; 0 while armed) */
|
|
99
107
|
openDelay?: number;
|
|
100
|
-
/** Grace (ms) before a hovered float hides (bridges the gap to the float). @defaultValue
|
|
108
|
+
/** Grace (ms) before a hovered float hides (bridges the gap to the float). @defaultValue the group's `leaveDelay` (400) */
|
|
101
109
|
closeDelay?: number;
|
|
110
|
+
/**
|
|
111
|
+
* A hovered float joins the grid's tooltip group (one tip at a time, closed by any press or key).
|
|
112
|
+
* `false` for a hover-opened float that is not a tooltip — a toolbar — which must survive a tip
|
|
113
|
+
* opening beside it and a press on its own buttons.
|
|
114
|
+
* @defaultValue true
|
|
115
|
+
*/
|
|
116
|
+
group?: boolean;
|
|
117
|
+
/**
|
|
118
|
+
* Keep a hover-opened float up although the pointer has left it — while something it opened (its
|
|
119
|
+
* dropdown) is open and has the pointer. It shows the last hovered target, and closes once released
|
|
120
|
+
* unless the pointer is back on the range or the float.
|
|
121
|
+
* @defaultValue false
|
|
122
|
+
*/
|
|
123
|
+
hold?: boolean;
|
|
102
124
|
/** What happens when the anchor leaves the data area. @defaultValue 'hide' */
|
|
103
125
|
whenOff?: GridWhenOff;
|
|
126
|
+
/** Per-axis policy while the range is partly obstructed. @defaultValue `{ side: 'flip', align: 'slide' }` */
|
|
127
|
+
whenPartial?: GridWhenPartial;
|
|
104
128
|
/** Where the float may live. @defaultValue 'data' */
|
|
105
129
|
boundary?: GridBoundary;
|
|
106
|
-
/** @defaultValue
|
|
107
|
-
zIndex?: number;
|
|
130
|
+
/** The stacking band. @defaultValue `zIndexVar('grid')` */
|
|
131
|
+
zIndex?: number | string;
|
|
132
|
+
/** How the float takes the pointer and the focus. @defaultValue 'pointer' */
|
|
133
|
+
interactive?: RangeFloatInteractive;
|
|
134
|
+
/**
|
|
135
|
+
* A `'focus'` float closed itself — Escape, or a press outside it. A controlled
|
|
136
|
+
* {@link target} should be cleared here.
|
|
137
|
+
*/
|
|
138
|
+
onDismiss?: () => void;
|
|
108
139
|
/** Render the float. **Spread `floatProps`** on the returned element. */
|
|
109
140
|
children: (info: RangeFloatRender<T>) => React.ReactNode;
|
|
110
141
|
}
|
|
111
142
|
/**
|
|
112
|
-
*
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
143
|
+
* Props for {@link VirtualRangeFloat}.
|
|
144
|
+
*/
|
|
145
|
+
export interface VirtualRangeFloatProps<T = unknown> extends RangeFloatOptions<T> {
|
|
146
|
+
/**
|
|
147
|
+
* What the pointer is over, as the HOST layer's own tap found it — `null` for nothing, omit for a
|
|
148
|
+
* float hover does not drive. Report it from the pane the pointer is in; the copies in the other
|
|
149
|
+
* panes need not repeat it (the hover is brokered across them, so the copy that owns the anchor
|
|
150
|
+
* draws).
|
|
151
|
+
*/
|
|
152
|
+
hovered?: RangeFloatTarget<T> | null;
|
|
153
|
+
/**
|
|
154
|
+
* The selection to follow: its active cell, through {@link probe}. An {@link ICellAnchor} rather than
|
|
155
|
+
* a full selection — only the active cell is read and subscribed to.
|
|
156
|
+
*/
|
|
157
|
+
selection?: ICellAnchor;
|
|
158
|
+
/** Ask whether the selection's active cell has something to float. Needed with {@link selection}. */
|
|
159
|
+
probe?: (coords: CellCoords, pane: IGridPane) => RangeFloatTarget<T> | null;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* A **range float** that is not a layer: content anchored to a range that portals out of the pane clip,
|
|
163
|
+
* placed inside a host layer. It owns **anchoring** (a {@link StickyPortal} on the range), the hover
|
|
164
|
+
* **intent** (dwell, grace, keep-open-on-float, `hold`, the tooltip group), the selection follow, and
|
|
165
|
+
* **dismissal**; the host owns its one tap and reports what the pointer is over as {@link
|
|
166
|
+
* VirtualRangeFloatProps.hovered}. So a composite layer (a table's chrome) can float its toolbar
|
|
167
|
+
* without a second layer, and {@link RangeFloatLayer} is this plus a probing tap.
|
|
168
|
+
*
|
|
169
|
+
* ```tsx
|
|
170
|
+
* <Layer onPointerMove={(e) => setHovered(probeAt(e))} onPointerLeave={() => setHovered(null)}>
|
|
171
|
+
* {outlines}
|
|
172
|
+
* <VirtualRangeFloat hovered={hovered} group={false}>
|
|
173
|
+
* {({ data, floatProps }) => <Toolbar {...floatProps} table={data} />}
|
|
174
|
+
* </VirtualRangeFloat>
|
|
175
|
+
* </Layer>
|
|
176
|
+
* ```
|
|
177
|
+
*
|
|
178
|
+
* When hover and selection both drive it, hover is the transient override and selection the resting
|
|
179
|
+
* state: while the pointer holds a target the float shows that one, and falls back to the selection's
|
|
180
|
+
* when the pointer leaves.
|
|
181
|
+
*/
|
|
182
|
+
export declare const VirtualRangeFloat: <T>(props: VirtualRangeFloatProps<T>) => React.ReactElement | null;
|
|
183
|
+
/**
|
|
184
|
+
* Props for {@link RangeFloatLayer}.
|
|
185
|
+
*/
|
|
186
|
+
export interface RangeFloatLayerProps<T = unknown> extends Omit<LayerProps, 'children' | 'zIndex'>, RangeFloatOptions<T> {
|
|
187
|
+
/** Class for the layer. */
|
|
188
|
+
className?: string;
|
|
189
|
+
/**
|
|
190
|
+
* What makes a float appear. Omit to drive {@link RangeFloatOptions.target} yourself.
|
|
191
|
+
* @defaultValue none (controlled)
|
|
192
|
+
*/
|
|
193
|
+
activateOn?: RangeFloatActivation | readonly RangeFloatActivation[];
|
|
194
|
+
/**
|
|
195
|
+
* Ask whether a cell has something to float — the anchor range + payload, or `null` for nothing.
|
|
196
|
+
* Called with the hovered cell (`'hover'`) and with the selection's active cell (`'selection'`), so
|
|
197
|
+
* one probe serves both. Not needed when {@link RangeFloatOptions.target} is controlled.
|
|
198
|
+
*/
|
|
199
|
+
probe?: (coords: CellCoords, pane: IGridPane) => RangeFloatTarget<T> | null;
|
|
200
|
+
/**
|
|
201
|
+
* The selection to follow for `activateOn: 'selection'`. An {@link ICellAnchor} rather than a full
|
|
202
|
+
* selection — the layer only ever reads the active cell and subscribes to it.
|
|
203
|
+
*/
|
|
204
|
+
selection?: ICellAnchor;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* The **range float layer**: a {@link VirtualRangeFloat} as a layer of its own, whose tap probes the
|
|
208
|
+
* hovered cell. It owns the three things every such float needs — **anchoring**, **activation** (what
|
|
209
|
+
* makes it appear) and **dismissal**. What it draws is entirely the consumer's: a tooltip, a button, a
|
|
210
|
+
* toolbar, an action popup.
|
|
116
211
|
*
|
|
117
212
|
* @remarks
|
|
118
213
|
* This is the **float half** of the grid's two mechanisms. A `CellTileDiv` covers everything whose
|
|
@@ -121,7 +216,8 @@ export interface RangeFloatLayerProps<T = unknown> extends Omit<LayerProps, 'chi
|
|
|
121
216
|
* or that must leave the cell box. "Only on the active cell" is the expensive predicate: it would
|
|
122
217
|
* dirty a tile per selection move, which is exactly why it belongs here.
|
|
123
218
|
*
|
|
124
|
-
*
|
|
219
|
+
* A layer that already draws chrome for the same thing (a table's outline and handles) hosts a
|
|
220
|
+
* {@link VirtualRangeFloat} itself instead — layers do not nest.
|
|
125
221
|
*
|
|
126
222
|
* ```tsx
|
|
127
223
|
* <RangeFloatLayer activateOn="hover" probe={probeError}>
|
|
@@ -132,10 +228,6 @@ export interface RangeFloatLayerProps<T = unknown> extends Omit<LayerProps, 'chi
|
|
|
132
228
|
* {({ range, floatProps }) => <Chevron {...floatProps} onPointerDown={() => open(range)} />}
|
|
133
229
|
* </RangeFloatLayer>
|
|
134
230
|
* ```
|
|
135
|
-
*
|
|
136
|
-
* When either can activate it, hover is the transient override and selection is the resting state:
|
|
137
|
-
* while the pointer holds a target the float shows that one, and it falls back to the selection's when
|
|
138
|
-
* the pointer leaves.
|
|
139
231
|
*/
|
|
140
232
|
export declare const RangeFloatLayer: <T>(props: RangeFloatLayerProps<T>) => React.ReactElement;
|
|
141
233
|
//# sourceMappingURL=RangeFloatLayer.d.ts.map
|
|
@@ -23,20 +23,20 @@ export interface RangePromptProps {
|
|
|
23
23
|
onGoto?: (state: StickyState) => void;
|
|
24
24
|
/** Called by the small cancel (×) button. The host unmounts the layer in response. */
|
|
25
25
|
onCancel?: () => void;
|
|
26
|
-
/** @defaultValue
|
|
27
|
-
zIndex?: number;
|
|
26
|
+
/** @defaultValue `zIndexVar('grid')` */
|
|
27
|
+
zIndex?: number | string;
|
|
28
28
|
className?: string;
|
|
29
29
|
style?: React.CSSProperties;
|
|
30
30
|
/** The client prompt content (option buttons, the AI question UI, …). A node or `(state) => node`. */
|
|
31
31
|
children?: React.ReactNode | ((state: StickyState) => React.ReactNode);
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
|
-
* A **persistent prompt pinned to a range** —
|
|
35
|
-
*
|
|
36
|
-
* an AI question about the range) with a small **cancel** (×). When the range
|
|
37
|
-
* clamps to the edge and swaps to a compact **arrow + "Go to range"** pill
|
|
38
|
-
* `state.scrollIntoView()`, or your `onGoto`). Controlled: the host mounts /
|
|
39
|
-
* `onCancel`).
|
|
34
|
+
* A **persistent prompt pinned to a range** — a preset of {@link StickyPortal} (always open, `clamp`ed,
|
|
35
|
+
* with a `renderOffscreen`). While the range is in view it renders the client content (injectable option
|
|
36
|
+
* buttons — e.g. an AI question about the range) on a card with a small **cancel** (×). When the range
|
|
37
|
+
* scrolls **out of view** it clamps to the edge and swaps to a compact **arrow + "Go to range"** pill
|
|
38
|
+
* (which reveals it via `state.scrollIntoView()`, or your `onGoto`). Controlled: the host mounts /
|
|
39
|
+
* unmounts it (cancel calls `onCancel`).
|
|
40
40
|
*/
|
|
41
41
|
export declare const RangePrompt: React.FC<RangePromptProps>;
|
|
42
42
|
//# sourceMappingURL=RangePrompt.d.ts.map
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { CellCoords, RangeCoords } from '@sheetxl/utils';
|
|
3
|
+
import { LayerProps } from './Layer';
|
|
4
|
+
import { StickyState } from './StickyAnchor';
|
|
5
|
+
import { HoverTipProps } from './useHoverIntent';
|
|
6
|
+
import { GridPlacement } from './useGridAnchor';
|
|
7
|
+
/** What a tip's content is rendered from, when {@link RangeTooltipProps.content} is a function. */
|
|
8
|
+
export interface RangeTooltipContentInfo {
|
|
9
|
+
/** The anchored range. */
|
|
10
|
+
range: RangeCoords;
|
|
11
|
+
/** The resolved sticky state (e.g. `state.scrollIntoView()`, `state.placement`). */
|
|
12
|
+
state: StickyState;
|
|
13
|
+
/**
|
|
14
|
+
* Spread onto the content's root to keep the tip open while hovered. Already on the bubble when the
|
|
15
|
+
* tip draws one; only a `bubble: false` tip spreads it itself.
|
|
16
|
+
*/
|
|
17
|
+
tipProps: HoverTipProps;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Props for {@link RangeTooltip}.
|
|
21
|
+
*/
|
|
22
|
+
export interface RangeTooltipProps {
|
|
23
|
+
/** The range the tip hangs on. */
|
|
24
|
+
range: RangeCoords;
|
|
25
|
+
/** The tip: a node, or a function of the anchored range and the float's state. */
|
|
26
|
+
content: React.ReactNode | ((info: RangeTooltipContentInfo) => React.ReactNode);
|
|
27
|
+
/** Which side of the range the tip attaches to. @defaultValue `{ side: 't' }` */
|
|
28
|
+
placement?: GridPlacement;
|
|
29
|
+
/** Gap (px) between the range and the tip. @defaultValue 6 */
|
|
30
|
+
offset?: number;
|
|
31
|
+
/** Offset (px) along the edge (only `start` / `end` align). @defaultValue 0 */
|
|
32
|
+
alignOffset?: number;
|
|
33
|
+
/**
|
|
34
|
+
* The tip stays open while the pointer is on it, so its content can be clicked (a card with
|
|
35
|
+
* buttons). Otherwise it takes no pointer at all. @defaultValue false
|
|
36
|
+
*/
|
|
37
|
+
interactive?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Draw the content in the group's bubble (the host's `renderTooltip`, or the grid's plain one).
|
|
40
|
+
* `false` renders the content bare — the consumer draws its own chrome and spreads `tipProps`.
|
|
41
|
+
* @defaultValue true
|
|
42
|
+
*/
|
|
43
|
+
bubble?: boolean;
|
|
44
|
+
/** Reserved for what the tip is anchored to. A tip on a range takes none. */
|
|
45
|
+
children?: never;
|
|
46
|
+
}
|
|
47
|
+
/** A registered tip. */
|
|
48
|
+
export interface RangeTooltipEntry {
|
|
49
|
+
/** The registration's identity. */
|
|
50
|
+
id: string;
|
|
51
|
+
/** Registration order; the later of two equal ranges wins. */
|
|
52
|
+
order: number;
|
|
53
|
+
props: RangeTooltipProps;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The tips declared under one {@link RangeTooltipProvider}: what {@link RangeTooltip} registers with
|
|
57
|
+
* and {@link RangeTooltipHost} probes.
|
|
58
|
+
*/
|
|
59
|
+
export interface RangeTooltipRegistry {
|
|
60
|
+
/** Registers a tip. The returned function withdraws it. */
|
|
61
|
+
add(id: string, props: RangeTooltipProps): () => void;
|
|
62
|
+
/** Replaces a registered tip's props. */
|
|
63
|
+
set(id: string, props: RangeTooltipProps): void;
|
|
64
|
+
/** The registered tip by id, or `null`. */
|
|
65
|
+
get(id: string): RangeTooltipEntry | null;
|
|
66
|
+
/** How many tips are registered. */
|
|
67
|
+
size(): number;
|
|
68
|
+
/**
|
|
69
|
+
* The tip at a cell: the smallest registered range covering it, and the latest registered among
|
|
70
|
+
* equals. `null` when none covers it.
|
|
71
|
+
*/
|
|
72
|
+
find(coords: CellCoords): RangeTooltipEntry | null;
|
|
73
|
+
/** Called after every change. The returned function unsubscribes. */
|
|
74
|
+
subscribe(listener: () => void): () => void;
|
|
75
|
+
/** A counter that moves on every change — a snapshot for `useSyncExternalStore`. */
|
|
76
|
+
version(): number;
|
|
77
|
+
}
|
|
78
|
+
export declare const createRangeTooltipRegistry: () => RangeTooltipRegistry;
|
|
79
|
+
/** The registry the nearest {@link RangeTooltipProvider} owns, or `null` outside any. */
|
|
80
|
+
export declare const useRangeTooltipRegistry: () => RangeTooltipRegistry | null;
|
|
81
|
+
export interface RangeTooltipProviderProps {
|
|
82
|
+
/**
|
|
83
|
+
* Own a separate registry for this subtree instead of sharing the enclosing one. A provider with no
|
|
84
|
+
* enclosing one always owns a registry.
|
|
85
|
+
*/
|
|
86
|
+
isolate?: boolean;
|
|
87
|
+
children?: React.ReactNode;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Collects the {@link RangeTooltip}s declared under it for the {@link RangeTooltipHost} of the grid
|
|
91
|
+
* inside it. A grid provides one of its own, so a tip among a grid's children needs none; a tip
|
|
92
|
+
* declared elsewhere in the app needs a provider around both it and the grid.
|
|
93
|
+
*/
|
|
94
|
+
export declare const RangeTooltipProvider: React.FC<RangeTooltipProviderProps>;
|
|
95
|
+
/**
|
|
96
|
+
* A **tooltip on a range**, declared where it is wanted: hover any cell of the range and the tip opens
|
|
97
|
+
* beside it, in the tooltip group of the grid (its timing, its one-open rule, its bubble). It draws
|
|
98
|
+
* nothing itself; the grid's {@link RangeTooltipHost} draws every declared tip from one layer.
|
|
99
|
+
*
|
|
100
|
+
* ```tsx
|
|
101
|
+
* <Grid …>
|
|
102
|
+
* <RangeTooltip range={{ rowStart: 3, colStart: 2, rowEnd: 8, colEnd: 5 }} content="Q3 figures" />
|
|
103
|
+
* </Grid>
|
|
104
|
+
* ```
|
|
105
|
+
*
|
|
106
|
+
* @remarks
|
|
107
|
+
* Reach for {@link RangeTooltipLayer} instead when the tips are derived from data (an error on
|
|
108
|
+
* whichever cells have one) rather than declared one by one. Where two declared ranges overlap, the
|
|
109
|
+
* smaller wins, and the later declared among equals. A tip's identity is its element: content may
|
|
110
|
+
* change without the open tip closing. The anchor is the `range`; `children` is reserved for an
|
|
111
|
+
* anchor that is drawn.
|
|
112
|
+
*/
|
|
113
|
+
export declare const RangeTooltip: (props: RangeTooltipProps) => null;
|
|
114
|
+
export interface RangeTooltipHostProps extends Omit<LayerProps, 'children'> {
|
|
115
|
+
className?: string;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* The layer that draws the {@link RangeTooltip}s of the nearest {@link RangeTooltipProvider}: one tap,
|
|
119
|
+
* one probe over the registered ranges, one client of the tooltip group. A grid mounts it at the top of
|
|
120
|
+
* its stack; it draws nothing where no tip is declared.
|
|
121
|
+
*/
|
|
122
|
+
export declare const RangeTooltipHost: React.MemoExoticComponent<(props: RangeTooltipHostProps) => React.JSX.Element>;
|
|
123
|
+
//# sourceMappingURL=RangeTooltip.d.ts.map
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { CellCoords, RangeCoords } from '@sheetxl/utils';
|
|
3
|
+
import { IGridPane } from '../surface';
|
|
4
|
+
import { StickyState } from './StickyAnchor';
|
|
5
|
+
import { HoverTipProps } from './useHoverIntent';
|
|
6
|
+
import { RangeFloatTarget, RangeFloatLayerProps } from './RangeFloatLayer';
|
|
7
|
+
/** The context passed to a {@link RangeTooltipLayerProps} render-prop. */
|
|
8
|
+
export interface RangeTooltipRender<T = unknown> {
|
|
9
|
+
/** The anchored range. */
|
|
10
|
+
range: RangeCoords;
|
|
11
|
+
/** The probe payload. */
|
|
12
|
+
data: T;
|
|
13
|
+
/**
|
|
14
|
+
* Spread onto the tip element to keep it open while hovered (`pointer-events:auto` + enter/leave).
|
|
15
|
+
* Already on the bubble when the layer draws one; only a `bubble: false` tip spreads it itself.
|
|
16
|
+
*/
|
|
17
|
+
tipProps: HoverTipProps;
|
|
18
|
+
/** The resolved sticky state (e.g. `state.scrollIntoView()`). */
|
|
19
|
+
state: StickyState;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Props for {@link RangeTooltipLayer}.
|
|
23
|
+
*/
|
|
24
|
+
export interface RangeTooltipLayerProps<T = unknown> extends Omit<RangeFloatLayerProps<T>, 'activateOn' | 'selection' | 'target' | 'probe' | 'children' | 'zIndex' | 'group' | 'hold' | 'interactive' | 'onDismiss'> {
|
|
25
|
+
/** Probe the hovered cell → a {@link RangeFloatTarget} (range + data), or `null` when nothing should show. */
|
|
26
|
+
probe: (coords: CellCoords, pane: IGridPane) => RangeFloatTarget<T> | null;
|
|
27
|
+
/**
|
|
28
|
+
* The tip stays open while the pointer is on it, so its content can be clicked (a card with
|
|
29
|
+
* buttons). Otherwise it takes no pointer at all. @defaultValue false
|
|
30
|
+
*/
|
|
31
|
+
interactive?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Draw the content in the group's bubble (the host's `renderTooltip`, or the grid's plain one).
|
|
34
|
+
* `false` renders the content bare — the consumer draws its own chrome and spreads `tipProps`.
|
|
35
|
+
* @defaultValue true
|
|
36
|
+
*/
|
|
37
|
+
bubble?: boolean;
|
|
38
|
+
/** Render the tip's content. */
|
|
39
|
+
children: (info: RangeTooltipRender<T>) => React.ReactNode;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The **tooltip kind** of range float: transient, opened by hovering a cell the probe recognizes, one
|
|
43
|
+
* at a time grid-wide. A preset of {@link RangeFloatLayer} (`activateOn: 'hover'`) whose hover intent is
|
|
44
|
+
* the tooltip group's client — so it inherits the group's timing, single-open rule, armed re-open, and
|
|
45
|
+
* closes on any press or key — drawn in the group's bubble, in the tooltip band.
|
|
46
|
+
*
|
|
47
|
+
* @remarks
|
|
48
|
+
* Reach for `RangeFloatLayer` directly when the float is activated by the selection, driven by a
|
|
49
|
+
* gesture, or is something other than a tip. A tip is never focusable: anything that takes the caret
|
|
50
|
+
* is a persistent float.
|
|
51
|
+
*/
|
|
52
|
+
export declare const RangeTooltipLayer: <T>(props: RangeTooltipLayerProps<T>) => React.ReactElement;
|
|
53
|
+
//# sourceMappingURL=RangeTooltipLayer.d.ts.map
|
|
@@ -1,13 +1,13 @@
|
|
|
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, GridAnchorReference, GridPlacement, GridBoundary, GridWhenOff, GridSlide } from './useGridAnchor';
|
|
4
|
+
import { GridAnchor, GridAnchorReference, GridPlacement, GridBoundary, GridWhenOff, GridWhenPartial, 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:
|
|
8
8
|
*
|
|
9
9
|
* - a **render-prop** child self-positions — e.g. a portal that escapes the clip and flows past the
|
|
10
|
-
* pane bounds (this is what {@link
|
|
10
|
+
* pane bounds (this is what {@link StickyPortal} does for you);
|
|
11
11
|
* - a plain **node** ("just a div") is positioned INLINE by StickyAnchor, clipping with the pane.
|
|
12
12
|
*
|
|
13
13
|
* `StickyAnchor` itself is portal-agnostic; it only resolves the anchor and positions inline divs.
|
|
@@ -17,8 +17,10 @@ export interface StickyState {
|
|
|
17
17
|
reference: GridAnchorReference;
|
|
18
18
|
/** Client-space boundary rect (for `flip`/`shift`/`hide` limiters). */
|
|
19
19
|
getBoundaryRect: () => DOMRect;
|
|
20
|
-
/** The placement's anchor pixel (client px). */
|
|
20
|
+
/** The placement's anchor pixel (client px) — a render-time snapshot. */
|
|
21
21
|
anchorPoint: Point;
|
|
22
|
+
/** Live accessor for the anchor pixel (client px); stable identity, reads between renders. */
|
|
23
|
+
getAnchorPoint: () => Point;
|
|
22
24
|
/** Pane-relative range bounds (for an in-grid child) — only meaningful on the owner pane, else null. */
|
|
23
25
|
bounds: Bounds | null;
|
|
24
26
|
/** The pane that owns the anchor pixel (null when clipped off every pane). */
|
|
@@ -35,7 +37,10 @@ export interface StickyState {
|
|
|
35
37
|
* (keep showing) from "off-screen" (show a goto affordance).
|
|
36
38
|
*/
|
|
37
39
|
outOfView: boolean;
|
|
38
|
-
/**
|
|
40
|
+
/**
|
|
41
|
+
* The placement **actually used**: the requested one, or its opposite on an axis that
|
|
42
|
+
* {@link StickyAnchorProps.whenPartial} flipped to the range's other visible edge.
|
|
43
|
+
*/
|
|
39
44
|
placement: GridPlacement;
|
|
40
45
|
/** This instance's pane (null outside a `GridPaneProvider`). */
|
|
41
46
|
pane: IGridPane | null;
|
|
@@ -63,6 +68,11 @@ export interface StickyAnchorProps {
|
|
|
63
68
|
boundary?: GridBoundary;
|
|
64
69
|
/** What happens when the anchor pixel leaves the data area. @defaultValue 'hide' */
|
|
65
70
|
whenOff?: GridWhenOff;
|
|
71
|
+
/**
|
|
72
|
+
* What happens, per axis, while the range is partly obstructed — in view, but the anchored edge is
|
|
73
|
+
* not. @defaultValue `{ side: 'flip', align: 'slide' }`
|
|
74
|
+
*/
|
|
75
|
+
whenPartial?: GridWhenPartial;
|
|
66
76
|
/** Px overlap below which a geometried anchor reads as clipped. @defaultValue 0 */
|
|
67
77
|
minVisible?: number;
|
|
68
78
|
/** The child — a node, or a render function `(state) => node`. Reads state via {@link useSticky} too. */
|
|
@@ -71,7 +81,7 @@ export interface StickyAnchorProps {
|
|
|
71
81
|
/**
|
|
72
82
|
* A **sticky** grid layer: it resolves an {@link GridAnchor} (via {@link useGridAnchor}) to a live
|
|
73
83
|
* anchor point and positions its child there. A plain `<div>` child is placed **inline** (clips with
|
|
74
|
-
* the pane); a **render-prop** child self-positions (e.g. a portal — see {@link
|
|
84
|
+
* the pane); a **render-prop** child self-positions (e.g. a portal — see {@link StickyPortal}). It owns
|
|
75
85
|
* no portal and knows nothing about Floating UI.
|
|
76
86
|
*
|
|
77
87
|
* Rendered per pane like any layer; each instance publishes its own `isOwner`, so only the owner pane
|