@sheetxl/grid-react 0.8.0-beta.1 → 0.8.0-beta.11

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.
Files changed (65) hide show
  1. package/README.md +16 -5
  2. package/browser/esm/index.mjs +3504 -2846
  3. package/licenses/dependencies.txt +0 -208
  4. package/node/esm/index.mjs +3861 -2284
  5. package/package.json +8 -12
  6. package/types/src/cell/CellRenderer.d.ts +14 -3
  7. package/types/src/cell/GridlineLayer.d.ts +39 -1
  8. package/types/src/editor/DefaultEditable.d.ts +25 -6
  9. package/types/src/editor/EditSession.d.ts +34 -5
  10. package/types/src/editor/EditState.d.ts +6 -0
  11. package/types/src/editor/EditorDiv.d.ts +3 -2
  12. package/types/src/editor/EditorInput.d.ts +7 -3
  13. package/types/src/editor/EditorLayer.d.ts +9 -4
  14. package/types/src/editor/EditorStartLayer.d.ts +33 -0
  15. package/types/src/editor/index.d.ts +1 -0
  16. package/types/src/editor/useEditorKeymap.d.ts +18 -2
  17. package/types/src/header/GridFreezeAnchor.d.ts +29 -0
  18. package/types/src/header/HeaderDividerAnchor.d.ts +29 -0
  19. package/types/src/header/HeaderFreezeAnchor.d.ts +37 -0
  20. package/types/src/header/_freezeSnap.d.ts +28 -0
  21. package/types/src/header/_useFreezeGrip.d.ts +28 -0
  22. package/types/src/header/index.d.ts +2 -0
  23. package/types/src/header/useHeaderSelectionPointer.d.ts +10 -6
  24. package/types/src/layer/GestureTip.d.ts +69 -0
  25. package/types/src/layer/GridFloatPanel.d.ts +19 -0
  26. package/types/src/layer/Layer.d.ts +6 -0
  27. package/types/src/layer/RangeFloatLayer.d.ts +143 -51
  28. package/types/src/layer/RangePrompt.d.ts +8 -8
  29. package/types/src/layer/RangeTooltip.d.ts +123 -0
  30. package/types/src/layer/RangeTooltipLayer.d.ts +53 -0
  31. package/types/src/layer/StickyAnchor.d.ts +15 -5
  32. package/types/src/layer/StickyPortal.d.ts +73 -0
  33. package/types/src/layer/TooltipProvider.d.ts +101 -0
  34. package/types/src/layer/index.d.ts +7 -4
  35. package/types/src/layer/useGridAnchor.d.ts +45 -4
  36. package/types/src/layer/useHoverIntent.d.ts +35 -8
  37. package/types/src/list/CheckboxList.d.ts +22 -1
  38. package/types/src/list/List.d.ts +11 -2
  39. package/types/src/list/ListSearch.d.ts +52 -0
  40. package/types/src/list/ListSurface.d.ts +25 -5
  41. package/types/src/list/PickList.d.ts +71 -0
  42. package/types/src/list/_measureText.d.ts +14 -0
  43. package/types/src/list/index.d.ts +2 -0
  44. package/types/src/range/DragHandle.d.ts +19 -2
  45. package/types/src/range/Draggable.d.ts +132 -7
  46. package/types/src/range/FillHandle.d.ts +33 -3
  47. package/types/src/range/RangeInsertBar.d.ts +91 -0
  48. package/types/src/range/index.d.ts +2 -0
  49. package/types/src/selection/SelectionLayer.d.ts +128 -15
  50. package/types/src/selection/SelectionStyle.d.ts +33 -0
  51. package/types/src/selection/SelectionTouchGrips.d.ts +0 -4
  52. package/types/src/selection/_SelectionUtils.d.ts +6 -0
  53. package/types/src/selection/useDragCells.d.ts +65 -9
  54. package/types/src/surface/GridPane.d.ts +2 -0
  55. package/types/src/surface/IGridPane.d.ts +15 -2
  56. package/types/src/surface/SurfaceStateProvider.d.ts +1 -1
  57. package/types/src/surface/getPrimaryPane.d.ts +13 -0
  58. package/types/src/surface/index.d.ts +1 -0
  59. package/types/src/surface/useSurfaceState.d.ts +19 -0
  60. package/types/src/svg/_Glide.d.ts +9 -0
  61. package/types/src/theme/GridTheme.d.ts +1 -1
  62. package/browser/cjs/index.cjs +0 -3
  63. package/types/src/layer/HoverTipLayer.d.ts +0 -47
  64. package/types/src/layer/StickyFloat.d.ts +0 -68
  65. package/types/src/layer/useRangeHover.d.ts +0 -36
@@ -1,6 +1,5 @@
1
1
  import { RangeAxis, CellCoords, RangeCoords } from '@sheetxl/utils';
2
- import { IGridPane } from '../surface';
3
- import { ISelection, DragCellsController } from '../selection';
2
+ import { ISelection, DragCellsController, DragCellsPane } from '../selection';
4
3
  /**
5
4
  * Options for {@link useHeaderSelectionPointer} / {@link createHeaderSelectionPointer}.
6
5
  */
@@ -55,8 +54,12 @@ export interface HeaderSelectionPointerOptions {
55
54
  onPointerDownInterceptor?: (e: React.PointerEvent, cell: CellCoords) => boolean | void;
56
55
  /** Called once at the start of a pointer gesture (before the selection changes). */
57
56
  onDragStart?: () => void;
58
- /** Called at the end of a pointer gesture. */
59
- onDragEnd?: (e: React.PointerEvent) => void;
57
+ /**
58
+ * Called at the end of a pointer gesture — on release AND on an abort (Escape / OS `pointercancel`),
59
+ * so whatever {@link HeaderSelectionPointerOptions.onDragStart} armed is always disarmed. The event is
60
+ * absent on an abort.
61
+ */
62
+ onDragEnd?: (e?: React.PointerEvent) => void;
60
63
  /** Called on pointer-up, after {@link HeaderSelectionPointerOptions.onDragEnd} (e.g. refocus the grid). */
61
64
  onPointerUp?: (e: React.PointerEvent) => void;
62
65
  }
@@ -106,7 +109,7 @@ export declare const headerRange: (a: CellCoords, b: CellCoords, axis: RangeAxis
106
109
  * keeping the viewport-anchored active cell. `getOptions` is read on every event so live values (entire
107
110
  * range, callbacks) need no controller rebuild.
108
111
  */
109
- export declare const createHeaderSelectionPointer: (selection: ISelection | null, pane: IGridPane, getOptions: () => HeaderSelectionPointerOptions) => DragCellsController;
112
+ export declare const createHeaderSelectionPointer: (selection: ISelection | null, pane: DragCellsPane, getOptions: () => HeaderSelectionPointerOptions) => DragCellsController;
110
113
  /**
111
114
  * The header selection pointer hook: the header-axis counterpart to the body's `useSelectionPointer`.
112
115
  * Reads the pane from context and drives the shared {@link ISelection} model, projecting every gesture
@@ -115,7 +118,8 @@ export declare const createHeaderSelectionPointer: (selection: ISelection | null
115
118
  *
116
119
  * @remarks
117
120
  * Options are read live through a ref, so changing `entireRange` / callbacks does not rebuild the
118
- * handlers — the controller is memoized on `(selection, pane)` only. The engine's auto-scroll timer is
121
+ * handlers — the controller is memoized on `selection` only; the pane is read live too, so a pane rebuilt
122
+ * mid-drag does not end the drag (see `DragCellsPane`). The engine's auto-scroll timer is
119
123
  * stopped on unmount.
120
124
  */
121
125
  export declare const useHeaderSelectionPointer: (selection: ISelection | null, options: HeaderSelectionPointerOptions) => HeaderSelectionPointerResult;
@@ -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 the layer decides WHICH range is floating.
10
+ * How {@link RangeFloatLayer} decides WHICH range is floating.
11
11
  *
12
- * - `'hover'` — the pointer, through the shared hover intent (open / close delays, keep-open-on-float).
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 RangeFloatLayerProps.target} yourself (gesture-driven action
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 {@link RangeFloatLayerProps.probe} — the range to anchor on plus arbitrary payload. */
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 {@link RangeFloatLayerProps} render-prop. */
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 — under `'hover'` — the enter/leave handlers that keep
42
- * the float open while the pointer is on it.
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
- * Props for {@link RangeFloatLayer}.
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 interface RangeFloatLayerProps<T = unknown> extends Omit<LayerProps, 'children'> {
52
- /** Class for the floated container. */
53
- className?: string;
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
- * What makes a float appear. Omit to drive {@link target} yourself.
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 `RangeFloatLayer` (they would otherwise share a cell and fight).
83
+ * hosts more than one range float (they would otherwise share a cell and fight).
65
84
  */
66
85
  name?: string;
67
86
  /**
68
- * Ask whether a cell has something to float — the anchor range + payload, or `null` for nothing.
69
- * Called with the hovered cell (`'hover'`) and with the selection's active cell (`'selection'`), so
70
- * one probe serves both. Not needed when {@link target} is controlled.
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. Under `'hover'` it is **edge-triggered**: the float drops now, bypassing `closeDelay`,
86
- * and a later hover re-opens normally. Under `'selection'` there is no gesture to re-arm it, so it
87
- * reads as a **level**: the float stays closed while this holds and returns when it clears (e.g. the
88
- * anchored cell is in edit mode). Ignored when {@link target} is controlled — the lifetime is yours
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 150 */
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 1250 */
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
- * The **range float layer**: content anchored to a range that portals out of the pane clip. It owns
113
- * the three things every such float needs — **anchoring** (a {@link StickyFloat} on the probed range),
114
- * **activation** (what makes it appear) and **dismissal**. What it draws is entirely the consumer's:
115
- * a tooltip, a button, a toolbar, an action popup.
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
- * Activation is pluggable and the rest of the layer is identical across the choices:
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 1250 */
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** — the "presence" flavor of {@link StickyFloat} (always open,
35
- * not hover). While the range is in view it renders the client content (injectable option buttons — e.g.
36
- * an AI question about the range) with a small **cancel** (×). When the range scrolls **out of view** it
37
- * clamps to the edge and swaps to a compact **arrow + "Go to range"** pill (which reveals it via
38
- * `state.scrollIntoView()`, or your `onGoto`). Controlled: the host mounts / unmounts it (cancel calls
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