@sheetxl/grid-react 0.7.27 → 0.7.28-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.
Files changed (90) hide show
  1. package/README.md +502 -2
  2. package/browser/cjs/index.cjs +3 -12
  3. package/browser/esm/index.mjs +5797 -1867
  4. package/licenses/dependencies.txt +143 -41
  5. package/node/esm/index.mjs +4951 -1861
  6. package/package.json +7 -6
  7. package/types/index.d.ts +2 -1503
  8. package/types/src/cell/CellLayer.d.ts +70 -0
  9. package/types/src/cell/CellRenderer.d.ts +42 -0
  10. package/types/src/cell/DefaultCellRenderer.d.ts +6 -0
  11. package/types/src/cell/GridlineLayer.d.ts +38 -0
  12. package/types/src/cell/Types.d.ts +12 -0
  13. package/types/src/cell/_CellModel.d.ts +82 -0
  14. package/types/src/cell/index.d.ts +6 -0
  15. package/types/src/editor/DefaultEditable.d.ts +121 -0
  16. package/types/src/editor/EditSession.d.ts +182 -0
  17. package/types/src/editor/EditState.d.ts +61 -0
  18. package/types/src/editor/EditorDiv.d.ts +65 -0
  19. package/types/src/editor/EditorInput.d.ts +88 -0
  20. package/types/src/editor/EditorLayer.d.ts +69 -0
  21. package/types/src/editor/EditorPlacement.d.ts +38 -0
  22. package/types/src/editor/index.d.ts +10 -0
  23. package/types/src/editor/useEditorKeymap.d.ts +74 -0
  24. package/types/src/grid/Grid.d.ts +16 -0
  25. package/types/src/grid/IGrid.d.ts +93 -0
  26. package/types/src/grid/index.d.ts +3 -0
  27. package/types/src/header/HeaderDividerAnchor.d.ts +120 -0
  28. package/types/src/header/index.d.ts +3 -0
  29. package/types/src/header/useHeaderSelectionPointer.d.ts +122 -0
  30. package/types/src/index.d.ts +13 -0
  31. package/types/src/layer/HoverTipLayer.d.ts +74 -0
  32. package/types/src/layer/Layer.d.ts +92 -0
  33. package/types/src/layer/LayerTypes.d.ts +47 -0
  34. package/types/src/layer/RangePrompt.d.ts +42 -0
  35. package/types/src/layer/Stage.d.ts +147 -0
  36. package/types/src/layer/StickyAnchor.d.ts +83 -0
  37. package/types/src/layer/StickyFloat.d.ts +65 -0
  38. package/types/src/layer/VirtualDiv.d.ts +59 -0
  39. package/types/src/layer/_Utils.d.ts +37 -0
  40. package/types/src/layer/index.d.ts +11 -0
  41. package/types/src/layer/useGridAnchor.d.ts +157 -0
  42. package/types/src/layer/useHoverIntent.d.ts +49 -0
  43. package/types/src/layer/useLayerResponder.d.ts +29 -0
  44. package/types/src/layer/usePlacement.d.ts +18 -0
  45. package/types/src/layer/useRangeHover.d.ts +35 -0
  46. package/types/src/list/CheckboxList.d.ts +63 -0
  47. package/types/src/list/List.d.ts +55 -0
  48. package/types/src/list/index.d.ts +3 -0
  49. package/types/src/metrics/Types.d.ts +23 -0
  50. package/types/src/metrics/index.d.ts +3 -0
  51. package/types/src/metrics/useGridMetrics.d.ts +67 -0
  52. package/types/src/range/DragHandle.d.ts +129 -0
  53. package/types/src/range/Draggable.d.ts +86 -0
  54. package/types/src/range/FillHandle.d.ts +54 -0
  55. package/types/src/range/RangeRect.d.ts +36 -0
  56. package/types/src/range/RangeResizer.d.ts +68 -0
  57. package/types/src/range/RangeStyle.d.ts +8 -0
  58. package/types/src/range/index.d.ts +13 -0
  59. package/types/src/selection/DefaultSelection.d.ts +59 -0
  60. package/types/src/selection/ICellAnchor.d.ts +21 -0
  61. package/types/src/selection/ISelection.d.ts +65 -0
  62. package/types/src/selection/RangesPickerLayer.d.ts +128 -0
  63. package/types/src/selection/SelectionLayer.d.ts +179 -0
  64. package/types/src/selection/SelectionStyle.d.ts +28 -0
  65. package/types/src/selection/SelectionTouchGrips.d.ts +29 -0
  66. package/types/src/selection/SelectionUtils.d.ts +2 -0
  67. package/types/src/selection/Types.d.ts +67 -0
  68. package/types/src/selection/_SelectionNavigation.d.ts +6 -0
  69. package/types/src/selection/_SelectionUtils.d.ts +7 -0
  70. package/types/src/selection/index.d.ts +12 -0
  71. package/types/src/selection/useDragCells.d.ts +218 -0
  72. package/types/src/selection/useSelectionPointer.d.ts +70 -0
  73. package/types/src/surface/GridPane.d.ts +85 -0
  74. package/types/src/surface/GridPaneProvider.d.ts +37 -0
  75. package/types/src/surface/GridSurface.d.ts +11 -0
  76. package/types/src/surface/IGridPane.d.ts +288 -0
  77. package/types/src/surface/IGridSurface.d.ts +141 -0
  78. package/types/src/surface/SurfaceStateProvider.d.ts +50 -0
  79. package/types/src/surface/_GridUtils.d.ts +37 -0
  80. package/types/src/surface/index.d.ts +7 -0
  81. package/types/src/surface/useGridPane.d.ts +31 -0
  82. package/types/src/surface/useSurfaceState.d.ts +22 -0
  83. package/types/src/svg/LineSVG.d.ts +13 -0
  84. package/types/src/svg/RectangleSVG.d.ts +114 -0
  85. package/types/src/svg/ShapeBounds.d.ts +15 -0
  86. package/types/src/svg/Types.d.ts +37 -0
  87. package/types/src/svg/index.d.ts +9 -0
  88. package/types/src/theme/GridTheme.d.ts +56 -0
  89. package/types/src/theme/index.d.ts +2 -0
  90. package/node/assets/style.css +0 -1
@@ -0,0 +1,122 @@
1
+ import { RangeAxis, CellCoords, RangeCoords } from '@sheetxl/utils';
2
+ import { IGridPane } from '../surface';
3
+ import { ISelection, DragCellsController } from '../selection';
4
+ /**
5
+ * Options for {@link useHeaderSelectionPointer} / {@link createHeaderSelectionPointer}.
6
+ */
7
+ export interface HeaderSelectionPointerOptions {
8
+ /** The header's axis. A column header selects entire columns; a row header, entire rows. */
9
+ axis: RangeAxis;
10
+ /**
11
+ * The **body** entire range (full rows × full columns). The header projects every gesture across the
12
+ * opposite axis using this — `pane.getTotalRange()` on a header pane only covers the header strip, so
13
+ * it must be supplied (typically `sheet.getEntireRange().getCoords()`).
14
+ */
15
+ entireRange: RangeCoords;
16
+ /**
17
+ * Allow Ctrl/Cmd-click to append additional header ranges (multi-select). When `false` a modifier
18
+ * click is treated as a plain replace.
19
+ *
20
+ * @defaultValue true
21
+ */
22
+ allowMulti?: boolean;
23
+ /**
24
+ * **Point (reference-picking) mode.** A no-modifier click/drag re-scopes the **active** reference in
25
+ * place (or **appends** a new one when the caret isn't on a reference, i.e. `rangeIndex < 0`),
26
+ * preserving the formula's other references — instead of the default `'clear'` that replaces the whole
27
+ * selection. Used by the header reference picker (`SheetReferenceHeaderLayer`) while editing a formula
28
+ * or a chart's data ranges. The gesture is also `stopPropagation`d so a primary header selection
29
+ * registered below this overlay never also runs its clobbering replace.
30
+ *
31
+ * @defaultValue false
32
+ */
33
+ replaceActive?: boolean;
34
+ /**
35
+ * Keep the current focus on pointer-down instead of letting the click steal it to the `tabIndex` Stage.
36
+ * On for a picker overlay used while editing a formula — a header pick must not blur the editor's
37
+ * textarea (mirrors the body draw picker's `preventDefault`). @defaultValue false
38
+ */
39
+ preserveFocus?: boolean;
40
+ /**
41
+ * Scroll a header cell into view during a drag (including the held-still auto-scroll). Given the header
42
+ * cell's axis coord — `{ colIndex }` for a column header, `{ rowIndex }` for a row header.
43
+ *
44
+ * @remarks
45
+ * **Must** be supplied for auto-scroll to work on a real sheet: a header `GridSurface` has a controlled
46
+ * viewport (it mirrors the body) and cannot scroll itself, so the scroll has to route through the sheet
47
+ * (`sheet.scrollTo`) — exactly like `SelectionLayer`'s `scrollIntoView`. When omitted the header falls
48
+ * back to scrolling its own pane, which is correct only for a standalone header / the unit tests.
49
+ */
50
+ scrollIntoView?: (coords: Partial<CellCoords>) => void;
51
+ /**
52
+ * Intercept pointer-down before any selection change. Return `false` to cancel (e.g. a right-click on
53
+ * an already fully-selected header, so the context menu keeps the existing multi-selection).
54
+ */
55
+ onPointerDownInterceptor?: (e: React.PointerEvent, cell: CellCoords) => boolean | void;
56
+ /** Called once at the start of a pointer gesture (before the selection changes). */
57
+ onDragStart?: () => void;
58
+ /** Called at the end of a pointer gesture. */
59
+ onDragEnd?: (e: React.PointerEvent) => void;
60
+ /** Called on pointer-up, after {@link HeaderSelectionPointerOptions.onDragEnd} (e.g. refocus the grid). */
61
+ onPointerUp?: (e: React.PointerEvent) => void;
62
+ }
63
+ /** Handlers to spread onto a `Layer` tap for header selection. */
64
+ export interface HeaderSelectionPointerResult {
65
+ onPointerDown: (e: React.PointerEvent) => void;
66
+ onPointerMove: (e: React.PointerEvent) => void;
67
+ onPointerUp: (e: React.PointerEvent) => void;
68
+ }
69
+ /**
70
+ * The entire-axis **start** corner for a header `cell`: the header index on the header axis, the body's
71
+ * entire-range start on the opposite axis (so a column header spans from the top row).
72
+ */
73
+ export declare const headerEntireStart: (cell: CellCoords, axis: RangeAxis, entire: RangeCoords) => CellCoords;
74
+ /** The entire-axis **end** corner for a header `cell` (mirror of {@link headerEntireStart}). */
75
+ export declare const headerEntireEnd: (cell: CellCoords, axis: RangeAxis, entire: RangeCoords) => CellCoords;
76
+ /**
77
+ * The **active cell** for a header gesture: the header index on the header axis, anchored to the first
78
+ * visible body row/column on the opposite axis — so the active cell (and the editor that follows it)
79
+ * lands at the top-left of the visible body, not at row/column 0.
80
+ */
81
+ export declare const headerAnchorCell: (cell: CellCoords, axis: RangeAxis, visible: RangeCoords) => CellCoords;
82
+ /**
83
+ * The entire-axis **range** spanning header cells `a`..`b` (only their header-axis index is used; the
84
+ * opposite axis always spans the body's entire range). The selection range is decoupled from the
85
+ * viewport-anchored active cell — which is why the header cannot use `ISelection.modify` (that ties the
86
+ * range to the anchor).
87
+ */
88
+ export declare const headerRange: (a: CellCoords, b: CellCoords, axis: RangeAxis, entire: RangeCoords) => RangeCoords;
89
+ /**
90
+ * The header selection pointer controller — the headless core of {@link useHeaderSelectionPointer},
91
+ * separated so the gesture→model logic is testable with a real {@link ISelection} and a fake pane (no
92
+ * React). Translates header pointer gestures into entire-axis selections written through `ISelection`:
93
+ *
94
+ * - **click / drag** → replace with the entire row/column(s) under the pointer.
95
+ * - **Shift + click/drag** → extend the active range from the first-clicked header.
96
+ * - **Ctrl/Cmd + click/drag** → append a new entire row/column range (when `allowMulti`).
97
+ *
98
+ * In {@link HeaderSelectionPointerOptions.replaceActive} (point) mode the plain click/drag instead
99
+ * re-scopes the ACTIVE reference in place (or appends when the caret isn't on one), the gesture is
100
+ * `stopPropagation`d, and writes go through an index-pinned `commitAt` (the body picker's `commitRange`).
101
+ *
102
+ * The drag *mechanics* (pointer capture, per-cell de-dup, held-still auto-scroll) come from the shared
103
+ * {@link createDragCells} engine; this controller only supplies the header *policy* (the entire-axis seed
104
+ * / drag / end). Unlike the body's `useSelectionPointer` it never calls `modify`/`append`: each gesture
105
+ * computes the full entire-axis range (which is NOT anchored to the active cell) and `setSelection`s it,
106
+ * keeping the viewport-anchored active cell. `getOptions` is read on every event so live values (entire
107
+ * range, callbacks) need no controller rebuild.
108
+ */
109
+ export declare const createHeaderSelectionPointer: (selection: ISelection | null, pane: IGridPane, getOptions: () => HeaderSelectionPointerOptions) => DragCellsController;
110
+ /**
111
+ * The header selection pointer hook: the header-axis counterpart to the body's `useSelectionPointer`.
112
+ * Reads the pane from context and drives the shared {@link ISelection} model, projecting every gesture
113
+ * to entire rows/columns and anchoring the active cell to the visible body. See
114
+ * {@link createHeaderSelectionPointer} for the gesture semantics.
115
+ *
116
+ * @remarks
117
+ * 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
119
+ * stopped on unmount.
120
+ */
121
+ export declare const useHeaderSelectionPointer: (selection: ISelection | null, options: HeaderSelectionPointerOptions) => HeaderSelectionPointerResult;
122
+ //# sourceMappingURL=useHeaderSelectionPointer.d.ts.map
@@ -0,0 +1,13 @@
1
+ export * from './metrics';
2
+ export * from './svg';
3
+ export * from './layer';
4
+ export * from './range';
5
+ export * from './surface';
6
+ export * from './cell';
7
+ export * from './selection';
8
+ export * from './editor';
9
+ export * from './header';
10
+ export * from './grid';
11
+ export * from './list';
12
+ export * from './theme';
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,74 @@
1
+ import { default as React } from 'react';
2
+ import { CellCoords, RangeCoords } from '@sheetxl/utils';
3
+ import { IGridPane } from '../surface';
4
+ import { LayerProps } from './Layer';
5
+ import { StickyState } from './StickyAnchor';
6
+ import { HoverTipProps } from './useHoverIntent';
7
+ import { GridPlacement, GridWhenOff, GridBoundary } from './useGridAnchor';
8
+ /** A hit returned by a {@link HoverTipLayerProps.probe} — the range to anchor on plus arbitrary payload. */
9
+ export interface HoverTarget<T = unknown> {
10
+ /** The range the tip anchors to (e.g. the cell's own range, or an enclosing table). */
11
+ range: RangeCoords;
12
+ /**
13
+ * Stable identity for dedupe — the tip re-opens only when this changes (a `pointermove` storm within
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
+ }
20
+ /** The context passed to a {@link HoverTipLayerProps} render-prop. */
21
+ export interface HoverTipRender<T = unknown> {
22
+ /** The anchored range. */
23
+ range: RangeCoords;
24
+ /** The probe payload. */
25
+ data: T;
26
+ /** Spread onto the tip element to keep it open while hovered (`pointer-events:auto` + enter/leave). */
27
+ tipProps: HoverTipProps;
28
+ /** The resolved sticky state (e.g. `state.scrollIntoView()`). */
29
+ state: StickyState;
30
+ }
31
+ /**
32
+ * Props for {@link HoverTipLayer}.
33
+ */
34
+ export interface HoverTipLayerProps<T = unknown> extends Omit<LayerProps, 'children'> {
35
+ /** Class for the floated tip container. */
36
+ className?: string;
37
+ /** Style for the floated tip container. */
38
+ style?: React.CSSProperties;
39
+ /** Probe the hovered cell → a {@link HoverTarget} (range + data), or `null` when nothing should show. */
40
+ 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
+ /** Render the tip. **Spread `tipProps`** on the returned element so hovering it keeps the tip open. */
64
+ children: (info: HoverTipRender<T>) => React.ReactNode;
65
+ }
66
+ /**
67
+ * The reusable **hover-tooltip layer**: sweeps the pointer over cells (a {@link Layer} tap +
68
+ * `getCellFromPointer`), asks a {@link HoverTipLayerProps.probe} whether the hovered cell has something
69
+ * to show, and — via the shared hover intent ({@link useHoverIntent}) — floats a {@link StickyFloat} tip
70
+ * (with flip / shift). The probe supplies the anchor range + payload; the render-prop draws the tip and
71
+ * keeps it open on hover. This is the shared engine behind `CellErrorLayer`, a table tip, etc.
72
+ */
73
+ export declare const HoverTipLayer: <T>(props: HoverTipLayerProps<T>) => React.ReactElement;
74
+ //# sourceMappingURL=HoverTipLayer.d.ts.map
@@ -0,0 +1,92 @@
1
+ import { IGridPane } from '../surface';
2
+ /**
3
+ * What a {@link Layer} contributes to the subtree it hosts, read with {@link useLayer}.
4
+ */
5
+ export interface LayerHandle {
6
+ /**
7
+ * The layer's **z-slot** — its position in the grid's normalized layer list (react declaration
8
+ * order with explicit-`zIndex` overrides already folded in by `normalizeLayers`), i.e. the
9
+ * "effective z" a dev means by *visual order*, **not** any raw `zIndex` prop. Nested content (a
10
+ * command scope) registers at it so keystroke / command dispatch follows the visual stack. Derived
11
+ * purely from the React list — no DOM, and stable across remounts (it's the LIST position, not
12
+ * when a responder registered).
13
+ */
14
+ zIndex: number;
15
+ /** The enclosing grid pane (null outside a pane — e.g. in a portal). */
16
+ pane: IGridPane | null;
17
+ }
18
+ /**
19
+ * Read the enclosing {@link Layer}'s slot: `{ zIndex, pane }`.
20
+ */
21
+ export declare const useLayer: () => LayerHandle;
22
+ /**
23
+ * The event-tap handler props a {@link Layer} accepts — the layer's own handlers, fired as the
24
+ * **boundary of its z-slot**: when the event's target is inside this layer they fire natively as
25
+ * the outermost step of the subtree bubble; for every other layer's turn the Stage invokes them at
26
+ * this layer's slot in the walk (strict z order — keys and pointers alike). Consume an event with
27
+ * `event.stopPropagation()` (the one-bubble law's single consume signal). The events are real:
28
+ * `event.target` is the actual element under the pointer, and
29
+ * `pane.getCellFromPointer(e.clientX, e.clientY)` resolves the cell.
30
+ */
31
+ export interface LayerEventProps {
32
+ onPointerDown?: (event: React.PointerEvent) => void;
33
+ onPointerMove?: (event: React.PointerEvent) => void;
34
+ onPointerUp?: (event: React.PointerEvent) => void;
35
+ onPointerLeave?: (event: React.PointerEvent) => void;
36
+ onMouseDown?: (event: React.MouseEvent) => void;
37
+ onMouseEnter?: (event: React.MouseEvent) => void;
38
+ onMouseLeave?: (event: React.MouseEvent) => void;
39
+ onMouseMove?: (event: React.MouseEvent) => void;
40
+ onMouseOut?: (event: React.MouseEvent) => void;
41
+ onMouseOver?: (event: React.MouseEvent) => void;
42
+ onMouseUp?: (event: React.MouseEvent) => void;
43
+ onDoubleClick?: (event: React.MouseEvent) => void;
44
+ onKeyDown?: (event: React.KeyboardEvent) => void;
45
+ onKeyPress?: (event: React.KeyboardEvent) => void;
46
+ onKeyUp?: (event: React.KeyboardEvent) => void;
47
+ onFocus?: (event: React.FocusEvent) => void;
48
+ onBlur?: (event: React.FocusEvent) => void;
49
+ onContextMenu?: (event: React.MouseEvent) => void;
50
+ }
51
+ /**
52
+ * Props for {@link Layer}.
53
+ */
54
+ export interface LayerProps extends LayerEventProps {
55
+ /**
56
+ * Explicit stacking override, read by `normalizeLayers` **off the grid-child element** to sort the
57
+ * layer list (higher sorts later = on top; omitted ⇒ declaration order). It is honored ONLY at the
58
+ * grid-children level — the layer's actual dispatch slot always comes from the resulting order
59
+ * index (via {@link LayerOrderContext}), never from this raw number, so paint order and event
60
+ * order can never disagree.
61
+ */
62
+ zIndex?: number;
63
+ /** Class for the layer's boundary div (devtools identification). */
64
+ className?: string;
65
+ /**
66
+ * The layer's content — {@link VirtualDiv}s, `RangeRect`s, floats — hosted inside the layer's
67
+ * boundary div. Children stack by DOM order within the layer (law 1).
68
+ */
69
+ children?: React.ReactNode;
70
+ }
71
+ /**
72
+ * A **Layer**: the containment boundary of one z-slot. It renders a single invisible, view-sized
73
+ * `<div>` (law 2: never paints, never a hit target — `pointer-events:none`; children opt back in)
74
+ * whose DOM presence is what gives every element inside it its **layer membership**: the dispatch
75
+ * resolves an event's layer by ancestry, so anything you host — VirtualDivs, plain elements,
76
+ * third-party widgets — participates in the z-order automatically.
77
+ *
78
+ * - **z-slot** — the layer's position in the grid's stack. It orders painting (DOM order of the
79
+ * sorted list) *and* event dispatch: the whole grid follows ONE rule — layers on top get events
80
+ * first, keys and pointers alike (law 3).
81
+ * - **event tap** — the layer's own handlers (`onPointerMove`, `onKeyDown`, …): the boundary of its
82
+ * slot. When the event's target is inside this layer they fire natively as the outermost step of
83
+ * the layer's own subtree bubble ("standard child eventing" ends at the layer); for every other
84
+ * layer's turn the Stage invokes them at this slot in the walk. Consume with
85
+ * `event.stopPropagation()`.
86
+ *
87
+ * Layers exist only as direct children of a `GridSurface` / `Grid` (law 4: the stack is flat) — a
88
+ * composite feature is a component that renders exactly one Layer at its root. Dev-enforced: a
89
+ * Layer errors when nested inside another Layer.
90
+ */
91
+ export declare const Layer: import('react').MemoExoticComponent<(props: LayerProps) => import("react").JSX.Element>;
92
+ //# sourceMappingURL=Layer.d.ts.map
@@ -0,0 +1,47 @@
1
+ import { RangeCoords, Bounds } from '@sheetxl/utils';
2
+ /**
3
+ * The placement core shared by {@link VirtualDiv} and the shape leaves: WHERE to place — a `range`
4
+ * (resolved via the pane), explicit `bounds`, or `fill` (the whole view) — and how much off-screen
5
+ * slack to keep. Exactly one of `range` | `bounds` | `fill` must be provided.
6
+ */
7
+ export interface VirtualDivPlacement {
8
+ /**
9
+ * The range to place at. Resolved to absolute bounds via the current pane. Provide this OR
10
+ * {@link bounds} OR {@link fill}.
11
+ */
12
+ range?: RangeCoords;
13
+ /**
14
+ * Explicit absolute bounds to place at (already resolved). Provide this OR {@link range} OR
15
+ * {@link fill}.
16
+ */
17
+ bounds?: Bounds;
18
+ /**
19
+ * Size to the view (the pane), never culled. For full-view content: a background wash, a canvas
20
+ * host, a pointer-capture surface, a container that needs real CSS (`overflow`, `opacity`,
21
+ * `filter`, a scroll-carrying transform) applied to a whole group. Provide this OR {@link range}
22
+ * OR {@link bounds}.
23
+ */
24
+ fill?: boolean;
25
+ /**
26
+ * View-pixel slack for the off-screen cull. A negative value extends outside the viewport, keeping
27
+ * a just-off-screen box visible.
28
+ */
29
+ clipInsets?: number;
30
+ }
31
+ /**
32
+ * The layers of a `GridSurface` / `Grid`, bottom → top — an ordinary React node, or an array of
33
+ * them. Each child renders exactly one {@link Layer} at its root (dev-enforced) and reads its pane
34
+ * from context ({@link useGridPane}):
35
+ *
36
+ * @example
37
+ * <GridSurface><MyLayer /></GridSurface>
38
+ *
39
+ * @remarks
40
+ * Structurally this is just `React.ReactNode` (an array of nodes is itself a node); the name only
41
+ * documents intent at the `children` site.
42
+ *
43
+ * For the rare case that needs the pane to build the element itself (rather than reading it from
44
+ * context inside the component), call {@link useGridPane} from a small wrapper component.
45
+ */
46
+ export type LayerNode = React.ReactNode | (React.ReactNode[]);
47
+ //# sourceMappingURL=LayerTypes.d.ts.map
@@ -0,0 +1,42 @@
1
+ import { default as React } from 'react';
2
+ import { RangeCoords } from '@sheetxl/utils';
3
+ import { StickyState } from './StickyAnchor';
4
+ import { GridPlacement } from './useGridAnchor';
5
+ /**
6
+ * Props for {@link RangePrompt}.
7
+ */
8
+ export interface RangePromptProps {
9
+ /** The range the prompt is pinned to. */
10
+ range: RangeCoords;
11
+ /** Where the prompt attaches relative to the range. @defaultValue `{ side: 't', align: 'start' }` */
12
+ placement?: GridPlacement;
13
+ /** Gap (px) perpendicular to the edge. @defaultValue 8 */
14
+ offset?: number;
15
+ /** Offset (px) along the edge (only `start` / `end` align). @defaultValue 0 */
16
+ alignOffset?: number;
17
+ /** Label for the out-of-view goto pill. @defaultValue the range's A1 address (e.g. `E11:H15`) */
18
+ address?: string;
19
+ /**
20
+ * Called by the out-of-view "Go to range" affordance. Defaults to `state.scrollIntoView()` (grid-level
21
+ * reveal); provide to also select at the sheet level (`sheet.getRange(addr).select()`).
22
+ */
23
+ onGoto?: (state: StickyState) => void;
24
+ /** Called by the small cancel (×) button. The host unmounts the layer in response. */
25
+ onCancel?: () => void;
26
+ /** @defaultValue 1250 */
27
+ zIndex?: number;
28
+ className?: string;
29
+ style?: React.CSSProperties;
30
+ /** The client prompt content (option buttons, the AI question UI, …). A node or `(state) => node`. */
31
+ children?: React.ReactNode | ((state: StickyState) => React.ReactNode);
32
+ }
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`).
40
+ */
41
+ export declare const RangePrompt: React.FC<RangePromptProps>;
42
+ //# sourceMappingURL=RangePrompt.d.ts.map
@@ -0,0 +1,147 @@
1
+ import { RemoveListener } from '@sheetxl/utils';
2
+ import { IGridPane } from '../surface';
3
+ /**
4
+ * A handler in the dispatch walk. Receives the React synthetic event and the owning pane.
5
+ * Call `event.stopPropagation()` to consume the event — lower layers and the pane/app then do
6
+ * not see it (the one-bubble law's single consume signal).
7
+ */
8
+ export type StageEventHandler = (event: React.SyntheticEvent, pane: IGridPane) => void;
9
+ /**
10
+ * A {@link Layer} tap's registration with the Stage.
11
+ *
12
+ * @remarks
13
+ * The Stage is the convergence hub: every Layer registers one tap and the Stage offers each event
14
+ * down the walk in slot order (higher first), then registration (render) order, stopping when one
15
+ * consumes.
16
+ */
17
+ export interface StageResponder {
18
+ /**
19
+ * The layer's dispatch **slot** — its derived order index in the grid's normalized layer list
20
+ * (see `LayerOrderContext`). Higher is offered the event first; ties break by registration
21
+ * (render) order REVERSED, so the later-declared layer (which paints on top) is offered first.
22
+ */
23
+ zIndex?: number;
24
+ /**
25
+ * Live accessor for the layer's boundary div. The dispatch resolves an event's **layer
26
+ * membership** by ancestry against these elements (which layer does the target belong to?) — the
27
+ * point of the Layer being a real div. Optional for element-less responders (the pane command
28
+ * terminal, `addReactEventListener` shims), which have no membership to resolve.
29
+ */
30
+ getElement?: () => Element | null;
31
+ /**
32
+ * Returns the current handler for a native event type (`'pointerdown'`, `'keydown'`,
33
+ * …), or `undefined`. Called per-dispatch, so it always sees the latest closures — a
34
+ * responder is registered once (not per render) and handler identity may change freely.
35
+ */
36
+ getHandler: (type: string) => StageEventHandler | undefined;
37
+ }
38
+ /**
39
+ * A geometried box's registration with the Stage (a {@link VirtualDiv}). Unlike a
40
+ * {@link StageResponder} (a Layer's zero-geometry tap), a box owns a real DOM element, so the
41
+ * DOM-driven dispatch can map a hit element to its box, resolve the boxes under the pointer, and
42
+ * skip the native target (whose handlers already fired in the "up your subtree" phase).
43
+ *
44
+ * @remarks
45
+ * Kept in a SEPARATE registry from the tap chain on purpose: there can be very many boxes
46
+ * (e.g. one fill per cell), and the tap chain is sorted on every event — boxes must not
47
+ * inflate that hot path. The dispatch resolves boxes geometrically (the DOM already stacks them),
48
+ * not by iterating this set per event.
49
+ */
50
+ export interface LayerRegistration {
51
+ /**
52
+ * The box's enclosing Layer's dispatch **slot** (from `LayerOrderContext`). Interleaves the box
53
+ * with the Layer taps in the single walk: a box fires between the taps of the layers above and
54
+ * below its own.
55
+ */
56
+ zIndex?: number;
57
+ /** Live accessor for the box's DOM element (null while culled / unmounted). */
58
+ getElement: () => Element | null;
59
+ /**
60
+ * Per-type handler accessor (as {@link StageResponder.getHandler}). The DOM-driven dispatch uses
61
+ * it to invoke a box that is BELOW the native target (so it did not receive the event natively;
62
+ * the hit box fires its own handlers natively — the up phase). Boxes with no handlers omit it.
63
+ */
64
+ getHandler?: (type: string) => StageEventHandler | undefined;
65
+ /**
66
+ * Whether this box currently has any event handlers. Drives the dispatch fast-path: when NO
67
+ * registered box has handlers (the entire normal grid — fills / borders / selection visuals),
68
+ * the geometried pass is skipped entirely, so it adds zero per-event cost.
69
+ */
70
+ hasHandlers?: boolean;
71
+ }
72
+ /**
73
+ * The event types a {@link VirtualDiv}'s registered handlers are invoked for on **other layers'
74
+ * turns** (a box below the hit layer, under the pointer). These are the positional, bubbling
75
+ * events. A box's handlers are ordinary native props — they fire natively when the box is on the
76
+ * event's target chain (its own layer's turn, phase 2); this registry map covers the pass-through
77
+ * case (phase 3). Relational (`enter`/`leave`), focus, and key events are targeted — the DOM's own
78
+ * delivery is already correct, so boxes never receive them positionally (Layer taps do, via the
79
+ * ordered walk).
80
+ */
81
+ export declare const WALKED_EVENT_TYPE_TO_PROP: Record<string, string>;
82
+ /** The walk-dispatched box prop names (values of {@link WALKED_EVENT_TYPE_TO_PROP}). */
83
+ export declare const WALKED_EVENT_PROPS: string[];
84
+ /**
85
+ * The event types the **three-phase dispatch** fully orders (law 3: layers on top hear events
86
+ * first — keys and pointers alike): the positional walked types PLUS keys. For these:
87
+ * - **phase 1** — a native CAPTURE listener on the Stage offers the event to the taps of every
88
+ * layer ABOVE the hit layer (top first), before the native dispatch runs;
89
+ * - **phase 2** — the native dispatch runs the hit layer's own subtree, exactly as React does
90
+ * (inner content, then any boxes on the chain, then the layer's own boundary handlers);
91
+ * - **phase 3** — the Stage's bubble handlers continue the walk strictly BELOW the hit layer
92
+ * (under-pointer boxes + taps, in slot order).
93
+ * `stopPropagation()` anywhere ends the whole bubble. Everything else (enter/leave/focus/blur) is
94
+ * stage-relational: a single unbounded tap walk.
95
+ */
96
+ export declare const ORDERED_EVENT_TYPES: readonly string[];
97
+ export interface IStageAttributes {
98
+ /**
99
+ * Add a listener for a single event type to the stage. Primarily grid-internal plumbing —
100
+ * external callers use {@link IGridPane.addReactEventListener} (which delegates here); layers
101
+ * use {@link Layer} taps instead.
102
+ */
103
+ addReactEventListener(type: string, listener: (event: React.SyntheticEvent) => void, listenerPane?: (event: React.SyntheticEvent, pane: IGridPane) => void): RemoveListener;
104
+ isStage(): true;
105
+ }
106
+ export interface IStageElement extends HTMLDivElement, IStageAttributes {
107
+ }
108
+ /**
109
+ * @internal
110
+ * The responder registry the Stage implementation also provides. Deliberately kept off the public
111
+ * {@link IStageElement} — Layers join the dispatch walk via their tap, which reaches
112
+ * this through {@link IStageElementInternal}.
113
+ */
114
+ export interface IStageResponderHost {
115
+ /** Register a (non-visual, broadcast) responder in the responder chain. Returns a remover. */
116
+ registerResponder(responder: StageResponder): RemoveListener;
117
+ /**
118
+ * Register a geometried layer (a {@link Layer}). Returns a remover. Stored
119
+ * apart from the responder chain (see {@link LayerRegistration}); consumed by the DOM-driven
120
+ * dispatch, not by the per-event responder fan-out.
121
+ */
122
+ registerLayer(layer: LayerRegistration): RemoveListener;
123
+ }
124
+ /** @internal Stage element augmented with the responder registry (used by `Layer` / `useLayerResponder`). */
125
+ export interface IStageElementInternal extends IStageElement, IStageResponderHost {
126
+ }
127
+ /**
128
+ * @internal
129
+ * Resolve a pane's Stage element WITH the responder registry (grid-internal; the registry is
130
+ * deliberately off the public pane API — external callers get {@link IGridPane.addReactEventListener}).
131
+ * The pane's surface element IS its Stage, brand-checked via `isStage` so a non-stage host (e.g. a
132
+ * static-border stub pane) resolves to `null` and the caller skips registration.
133
+ */
134
+ export declare const getStageInternal: (pane: IGridPane | null | undefined) => IStageElementInternal | null;
135
+ export interface StageProps extends React.HTMLAttributes<HTMLDivElement> {
136
+ /**
137
+ * Ref for the HTMLDivElement
138
+ */
139
+ ref?: React.Ref<IStageElement>;
140
+ }
141
+ /**
142
+ * Stage
143
+ *
144
+ * Internally used to distinguish the main grid area.
145
+ */
146
+ export declare const Stage: import('react').NamedExoticComponent<Omit<StageProps, "ref"> & import('react').RefAttributes<IStageElement>>;
147
+ //# sourceMappingURL=Stage.d.ts.map
@@ -0,0 +1,83 @@
1
+ import { default as React } from 'react';
2
+ import { Bounds, Point, AnchorLocation } from '@sheetxl/utils';
3
+ import { IGridPane } from '../surface';
4
+ import { GridAnchor, GridPlacement, GridBoundary, GridWhenOff, GridSlide } from './useGridAnchor';
5
+ /**
6
+ * The state a {@link StickyAnchor} publishes to its child. Carries the resolved `anchorPoint` (+ owner /
7
+ * clip / slide state) so the child alone decides how to render:
8
+ *
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 StickyFloat} does for you);
11
+ * - a plain **node** ("just a div") is positioned INLINE by StickyAnchor, clipping with the pane.
12
+ *
13
+ * `StickyAnchor` itself is portal-agnostic; it only resolves the anchor and positions inline divs.
14
+ */
15
+ export interface StickyState {
16
+ /** Client-space Floating UI virtual reference (stable identity; reads live). */
17
+ reference: {
18
+ getBoundingClientRect: () => DOMRect;
19
+ };
20
+ /** Client-space boundary rect (for `flip`/`shift`/`hide` limiters). */
21
+ getBoundaryRect: () => DOMRect;
22
+ /** The placement's anchor pixel (client px). */
23
+ anchorPoint: Point;
24
+ /** Pane-relative range bounds (for an in-grid child) — only meaningful on the owner pane, else null. */
25
+ bounds: Bounds | null;
26
+ /** The pane that owns the anchor pixel (null when clipped off every pane). */
27
+ owner: AnchorLocation | null;
28
+ /** Whether THIS instance's pane is the owner — the child self-gates on it (render once / correct pane). */
29
+ isOwner: boolean;
30
+ /** Anchor outside the boundary. */
31
+ clipped: boolean;
32
+ /** The clamp slide (distance/direction) when `whenOff: 'clamp'` pushed it in-frame, else null. */
33
+ slid: GridSlide | null;
34
+ /**
35
+ * The anchored range is **fully scrolled off** (no visible portion) — stays true under `whenOff:
36
+ * 'clamp'` (unlike {@link clipped}), so a presence can distinguish "partially obstructed / clamped"
37
+ * (keep showing) from "off-screen" (show a goto affordance).
38
+ */
39
+ outOfView: boolean;
40
+ /** The resolved placement. */
41
+ placement: GridPlacement;
42
+ /** This instance's pane (null outside a `GridPaneProvider`). */
43
+ pane: IGridPane | null;
44
+ /**
45
+ * Scroll the anchor's top-left cell into view — the grid-level "reveal" for a render-prop child (e.g.
46
+ * a clamped Presence label whose click should bring its range back on-screen). No-op for anchors
47
+ * without a cell (`bounds` / `edge` / `point`) or outside a pane. This is reveal only; selection lives
48
+ * a layer up (`sheet.getRange(addr).select()`).
49
+ */
50
+ scrollIntoView: (options?: globalThis.ScrollIntoViewOptions | boolean) => Promise<unknown>;
51
+ }
52
+ /** Read the enclosing {@link StickyAnchor}'s state. Throws outside one. */
53
+ export declare const useSticky: () => StickyState;
54
+ /** Read the enclosing {@link StickyAnchor}'s state, or null outside one. */
55
+ export declare const useStickyOptional: () => StickyState | null;
56
+ /**
57
+ * Props for {@link StickyAnchor}.
58
+ */
59
+ export interface StickyAnchorProps {
60
+ /** WHERE to anchor — a grid coordinate (range / cell / bounds / edge / point). */
61
+ anchor: GridAnchor;
62
+ /** Which side + align of the anchor the float attaches to (picks the single anchor pixel). */
63
+ placement?: GridPlacement;
64
+ /** Clip / clamp boundary (client-space math input, not a DOM parent). @defaultValue 'data' */
65
+ boundary?: GridBoundary;
66
+ /** What happens when the anchor pixel leaves the data area. @defaultValue 'hide' */
67
+ whenOff?: GridWhenOff;
68
+ /** Px overlap below which a geometried anchor reads as clipped. @defaultValue 0 */
69
+ minVisible?: number;
70
+ /** The child — a node, or a render function `(state) => node`. Reads state via {@link useSticky} too. */
71
+ children?: React.ReactNode | ((state: StickyState) => React.ReactNode);
72
+ }
73
+ /**
74
+ * A **sticky** grid layer: it resolves an {@link GridAnchor} (via {@link useGridAnchor}) to a live
75
+ * anchor point and positions its child there. A plain `<div>` child is placed **inline** (clips with
76
+ * the pane); a **render-prop** child self-positions (e.g. a portal — see {@link StickyFloat}). It owns
77
+ * no portal and knows nothing about Floating UI.
78
+ *
79
+ * Rendered per pane like any layer; each instance publishes its own `isOwner`, so only the owner pane
80
+ * renders the child (once).
81
+ */
82
+ export declare const StickyAnchor: React.FC<StickyAnchorProps>;
83
+ //# sourceMappingURL=StickyAnchor.d.ts.map