@sheetxl/grid-react 0.7.28-beta.4 → 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.
Files changed (57) hide show
  1. package/README.md +16 -5
  2. package/browser/esm/index.mjs +3421 -2710
  3. package/licenses/dependencies.txt +18 -192
  4. package/node/esm/index.mjs +3878 -2267
  5. package/package.json +8 -12
  6. package/types/src/cell/CellRenderer.d.ts +14 -3
  7. package/types/src/editor/DefaultEditable.d.ts +23 -4
  8. package/types/src/editor/EditSession.d.ts +34 -5
  9. package/types/src/editor/EditState.d.ts +6 -0
  10. package/types/src/editor/EditorInput.d.ts +7 -3
  11. package/types/src/editor/EditorLayer.d.ts +9 -4
  12. package/types/src/editor/EditorStartLayer.d.ts +32 -0
  13. package/types/src/editor/index.d.ts +1 -0
  14. package/types/src/editor/useEditorKeymap.d.ts +18 -2
  15. package/types/src/header/GridFreezeAnchor.d.ts +29 -0
  16. package/types/src/header/HeaderDividerAnchor.d.ts +29 -0
  17. package/types/src/header/HeaderFreezeAnchor.d.ts +37 -0
  18. package/types/src/header/_freezeSnap.d.ts +28 -0
  19. package/types/src/header/_useFreezeGrip.d.ts +28 -0
  20. package/types/src/header/index.d.ts +2 -0
  21. package/types/src/header/useHeaderSelectionPointer.d.ts +10 -6
  22. package/types/src/layer/GestureTip.d.ts +69 -0
  23. package/types/src/layer/GridFloatPanel.d.ts +19 -0
  24. package/types/src/layer/Layer.d.ts +6 -0
  25. package/types/src/layer/RangeFloatLayer.d.ts +233 -0
  26. package/types/src/layer/RangePrompt.d.ts +8 -8
  27. package/types/src/layer/RangeTooltip.d.ts +123 -0
  28. package/types/src/layer/RangeTooltipLayer.d.ts +53 -0
  29. package/types/src/layer/StickyAnchor.d.ts +16 -8
  30. package/types/src/layer/StickyPortal.d.ts +73 -0
  31. package/types/src/layer/TooltipProvider.d.ts +101 -0
  32. package/types/src/layer/index.d.ts +8 -4
  33. package/types/src/layer/useGridAnchor.d.ts +66 -8
  34. package/types/src/layer/useHoverIntent.d.ts +35 -8
  35. package/types/src/list/CheckboxList.d.ts +22 -1
  36. package/types/src/list/List.d.ts +14 -5
  37. package/types/src/list/ListSearch.d.ts +52 -0
  38. package/types/src/list/ListSurface.d.ts +93 -0
  39. package/types/src/list/PickList.d.ts +71 -0
  40. package/types/src/list/_measureText.d.ts +14 -0
  41. package/types/src/list/index.d.ts +3 -0
  42. package/types/src/range/DragHandle.d.ts +19 -2
  43. package/types/src/range/Draggable.d.ts +132 -7
  44. package/types/src/range/FillHandle.d.ts +33 -3
  45. package/types/src/range/RangeInsertBar.d.ts +91 -0
  46. package/types/src/range/index.d.ts +2 -0
  47. package/types/src/selection/SelectionLayer.d.ts +128 -15
  48. package/types/src/selection/SelectionStyle.d.ts +33 -0
  49. package/types/src/selection/SelectionTouchGrips.d.ts +0 -4
  50. package/types/src/selection/_SelectionUtils.d.ts +6 -0
  51. package/types/src/selection/useDragCells.d.ts +65 -9
  52. package/types/src/surface/useSurfaceState.d.ts +19 -0
  53. package/types/src/svg/_Glide.d.ts +9 -0
  54. package/browser/cjs/index.cjs +0 -3
  55. package/types/src/layer/HoverTipLayer.d.ts +0 -74
  56. package/types/src/layer/StickyFloat.d.ts +0 -65
  57. package/types/src/layer/useRangeHover.d.ts +0 -35
@@ -0,0 +1,73 @@
1
+ import { default as React } from 'react';
2
+ import { FloatPopperProps } from '@sheetxl/utils-react';
3
+ import { StickyState } from './StickyAnchor';
4
+ import { GridAnchor, GridPlacement, GridBoundary, GridWhenOff, GridWhenPartial } from './useGridAnchor';
5
+ /** The lifecycle a {@link StickyPortal} reports — {@link FloatPopper}'s. */
6
+ export type StickyPortalLifecycle = Pick<FloatPopperProps, 'onMount' | 'onOpening' | 'onOpen' | 'onClosing' | 'onClose'>;
7
+ /**
8
+ * Props for {@link StickyPortal}.
9
+ */
10
+ export interface StickyPortalProps extends StickyPortalLifecycle {
11
+ /** WHERE to anchor — a grid coordinate (range / cell / bounds / edge / point). */
12
+ anchor: GridAnchor;
13
+ /** Which side + align the float attaches to. @defaultValue `{ side: 't', align: 'center' }` */
14
+ placement?: GridPlacement;
15
+ /** What happens when the anchor leaves the data area. @defaultValue 'hide' */
16
+ whenOff?: GridWhenOff;
17
+ /**
18
+ * What happens, per axis, while the range is partly obstructed — in view, but the anchored edge is
19
+ * not. @defaultValue `{ side: 'flip', align: 'slide' }`
20
+ */
21
+ whenPartial?: GridWhenPartial;
22
+ /**
23
+ * Where the float may LIVE — one rect, resolved by {@link GridBoundary}: it is both the anchor's
24
+ * clip / clamp boundary and the rect `flip` / `shift` collide against. @defaultValue 'data'
25
+ */
26
+ boundary?: GridBoundary;
27
+ /** Px overlap below which a geometried anchor reads as clipped. @defaultValue 0 */
28
+ minVisible?: number;
29
+ /** Gap (px) between the anchor edge and the float. @defaultValue 4 */
30
+ offset?: number;
31
+ /**
32
+ * Offset (px) along the anchor EDGE — only applies to `start` / `end` alignment (a centered float has
33
+ * no edge to slide along). Positive insets the float inward from the corner. @defaultValue 0
34
+ */
35
+ alignOffset?: number;
36
+ /** Controlled visibility (e.g. a hover tooltip). @defaultValue true */
37
+ open?: boolean;
38
+ /** Portal container. @defaultValue the fullscreen-aware root (`useFullscreenPortal`). */
39
+ container?: Element;
40
+ className?: string;
41
+ style?: React.CSSProperties;
42
+ /** The stacking band — a number, or a `zIndexVar` expression. @defaultValue `zIndexVar('grid')` */
43
+ zIndex?: number | string;
44
+ /**
45
+ * Whose theme the float wears: the anchor's (`'anchor'` — a grid label themes with its grid, even where
46
+ * the grid's mode differs from the app's) or the app's (`'provider'` — chrome, such as a gesture
47
+ * readout). @defaultValue 'anchor'
48
+ */
49
+ themeFrom?: 'provider' | 'anchor';
50
+ /**
51
+ * Drawn **instead of** the child while the anchored range has no visible portion (`state.outOfView`) —
52
+ * the presence left behind under `whenOff: 'clamp'`: an edge marker, a "go to range" pill. Without it
53
+ * the child itself is drawn, clamped to the edge.
54
+ */
55
+ renderOffscreen?: (state: StickyState) => React.ReactNode;
56
+ /** The float content — a node, or a render function `(state) => node` (e.g. to react to `slid`). */
57
+ children?: React.ReactNode | ((state: StickyState) => React.ReactNode);
58
+ }
59
+ /**
60
+ * The **portal renderer** of the grid float family: a {@link StickyAnchor} whose child is drawn by
61
+ * {@link FloatPopper} at the resolved anchor, in a **portal** (escaping the pane clip, so it can flow past
62
+ * the pane bounds — e.g. overhang a freeze line). The common case — `<StickyPortal anchor={{ range }}>
63
+ * A1:B4</StickyPortal>` — with no hand-written positioner. For an in-grid (clipping) label, use
64
+ * `<StickyAnchor>` with a plain `<div>` child instead.
65
+ *
66
+ * @remarks
67
+ * The resolver (`StickyAnchor`) decides WHERE — the owner pane, the live client rect, the boundary and the
68
+ * clip / clamp / slide state; the positioner (`FloatPopper`, the same one app menus use) decides how the
69
+ * box fits there. Both kinds of grid float — a persistent `RangeFloat` and a hover `RangeTooltip` — are
70
+ * one of these; what differs is who opens and closes them.
71
+ */
72
+ export declare const StickyPortal: React.FC<StickyPortalProps>;
73
+ //# sourceMappingURL=StickyPortal.d.ts.map
@@ -0,0 +1,101 @@
1
+ import { default as React } from 'react';
2
+ import { GridPlacement } from './useGridAnchor';
3
+ import { HoverTipProps } from './useHoverIntent';
4
+ /**
5
+ * The dwell timing of the tooltip group — MUI's model.
6
+ */
7
+ export interface TooltipTiming {
8
+ /** Dwell (ms) over a target before the first tip shows. @defaultValue 300 */
9
+ enterDelay: number;
10
+ /** Dwell (ms) while the group is **armed** (a tip closed within {@link armedFor}) — the next tip is instant. @defaultValue 0 */
11
+ enterNextDelay: number;
12
+ /** The window (ms) after a close in which the next open is fast — MUI's hysteresis. @defaultValue 800 */
13
+ armedFor: number;
14
+ /** The linger (ms) after leaving before a tip hides — lets the pointer cross onto an interactive tip, and a tip does not vanish the moment the pointer leaves the grid. @defaultValue 400 */
15
+ leaveDelay: number;
16
+ }
17
+ export declare const DEFAULT_TOOLTIP_TIMING: TooltipTiming;
18
+ /** What the host's tooltip bubble is handed. */
19
+ export interface TooltipRenderProps {
20
+ /** The tip's content. */
21
+ children: React.ReactNode;
22
+ /** The edge the tip hangs on — for an arrow. */
23
+ placement: GridPlacement;
24
+ /** Whether the tip stays open while the pointer is on it (and so takes the pointer at all). */
25
+ interactive: boolean;
26
+ /** Spread onto the bubble root: the keep-open handlers and the element registration. */
27
+ tipProps: HoverTipProps;
28
+ className?: string;
29
+ style?: React.CSSProperties;
30
+ }
31
+ /** The bubble around a tip's content — the host's chrome, arrow and theme. */
32
+ export type RenderTooltip = (props: TooltipRenderProps) => React.ReactNode;
33
+ /**
34
+ * A tip registered with its {@link TooltipGroup}. One per `useHoverIntent`; the per-pane copies of a
35
+ * layer share a `key`, so they count as one tip.
36
+ */
37
+ export interface TooltipClient {
38
+ /** Identity: the copies of one tip share it; two tips on the same cell do not. */
39
+ readonly key: string;
40
+ /**
41
+ * A gesture tip holds the group: hover tips may not open while it is up. It is not closed by a press
42
+ * or a key (its gesture's modifiers), and its close does not arm the group.
43
+ */
44
+ readonly gesture: boolean;
45
+ /** The tip's element once mounted — a pointerdown inside it does not close it. */
46
+ getElement(): Element | null;
47
+ /** Close now, no grace (the group took the slot, or the user pressed / typed). */
48
+ forceClose(): void;
49
+ }
50
+ /**
51
+ * The single-open coordinator: at most one tip (by key) is up at a time, the next open is fast for
52
+ * {@link TooltipTiming.armedFor} after a close, a gesture tip preempts hover, and any pointerdown or
53
+ * keydown closes an open hover tip (a gesture tip closes with its gesture). Owned by the top {@link TooltipProvider} (or one that `isolate`s);
54
+ * a built-in default serves a tree with no provider.
55
+ */
56
+ export interface TooltipGroup {
57
+ /** `client` is opening: every client open on another key closes first, with no grace. */
58
+ claim(client: TooltipClient): void;
59
+ /** `client` closed. The group arms when the last client on the open key releases. */
60
+ release(client: TooltipClient): void;
61
+ /** A tip closed less than `armedFor` ms ago. */
62
+ isArmed(armedFor: number): boolean;
63
+ /** A gesture tip is up. */
64
+ isHeld(): boolean;
65
+ /** Close every open tip now. */
66
+ closeAll(): void;
67
+ }
68
+ export declare const createTooltipGroup: () => TooltipGroup;
69
+ /** The ambient tooltip configuration a tip reads. */
70
+ export interface TooltipSurface {
71
+ timing: TooltipTiming;
72
+ /** The host's bubble; `undefined` = the grid's plain default. */
73
+ renderTooltip?: RenderTooltip;
74
+ group: TooltipGroup;
75
+ }
76
+ /**
77
+ * The ambient {@link TooltipSurface}. Works with no provider: MUI timing, the plain bubble and a shared
78
+ * default group.
79
+ */
80
+ export declare const useTooltipSurface: () => TooltipSurface;
81
+ export interface TooltipProviderProps {
82
+ /** Override any of the dwell timings; the rest are inherited. */
83
+ timing?: Partial<TooltipTiming>;
84
+ /** The bubble tips in this subtree open in. Inherited when omitted. */
85
+ renderTooltip?: RenderTooltip;
86
+ /**
87
+ * Own a separate single-open group for this subtree instead of sharing the enclosing one. The top
88
+ * provider (no enclosing one) always owns a group.
89
+ */
90
+ isolate?: boolean;
91
+ children?: React.ReactNode;
92
+ }
93
+ /**
94
+ * Configures the grid's tooltips for a subtree: the dwell timing, the bubble (`renderTooltip`, the way
95
+ * `FloatProvider` takes `renderFloatPanel`) and the single-open group. Nested providers override only
96
+ * what they are given and inherit the rest; a hook outside any provider gets the built-in defaults.
97
+ */
98
+ export declare const TooltipProvider: React.FC<TooltipProviderProps>;
99
+ /** The grid's default bubble — used when no provider supplies `renderTooltip`. */
100
+ export declare const renderDefaultTooltip: RenderTooltip;
101
+ //# sourceMappingURL=TooltipProvider.d.ts.map
@@ -1,11 +1,15 @@
1
1
  export * from './LayerTypes';
2
2
  export * from './Layer';
3
3
  export * from './VirtualDiv';
4
- export type { GridAnchor, GridPlacement, GridWhenOff, GridBoundary, GridFloatSide, GridAlign, GridSlide } from './useGridAnchor';
4
+ export type { GridAnchor, GridAnchorReference, GridPlacement, GridWhenOff, GridWhenPartial, GridPartialPolicy, GridBoundary, GridFloatSide, GridAlign, GridSlide } from './useGridAnchor';
5
5
  export * from './StickyAnchor';
6
- export * from './StickyFloat';
6
+ export * from './StickyPortal';
7
+ export * from './GridFloatPanel';
8
+ export * from './TooltipProvider';
7
9
  export * from './useHoverIntent';
8
- export * from './useRangeHover';
9
- export * from './HoverTipLayer';
10
+ export * from './RangeFloatLayer';
11
+ export * from './RangeTooltipLayer';
12
+ export * from './GestureTip';
10
13
  export * from './RangePrompt';
14
+ export * from './RangeTooltip';
11
15
  //# sourceMappingURL=index.d.ts.map
@@ -25,6 +25,27 @@ export interface GridPlacement {
25
25
  * the owner becomes the pane under the clamped pixel and {@link GridAnchorResolved.slid} is set.
26
26
  */
27
27
  export type GridWhenOff = 'hide' | 'clamp';
28
+ /**
29
+ * What a float does on ONE axis while the range is **partly obstructed** — in view, but the edge the
30
+ * float hangs on is not (scrolled under a frozen pane, a header, or the window edge).
31
+ *
32
+ * - `'slide'` — the anchor pixel rides the visible edge, over the obstruction, until the range is
33
+ * fully out ({@link GridAnchorResolved.slid} reports how far).
34
+ * - `'flip'` — the float moves to the **opposite edge of the range** when that edge is in view (the
35
+ * resolved {@link GridAnchorResolved.placement} reports it); slides when neither edge is. Meaningless
36
+ * for a `center` align, which slides.
37
+ * - `'hide'` — the range counts as out of view as soon as the anchored edge is obstructed.
38
+ */
39
+ export type GridPartialPolicy = 'slide' | 'flip' | 'hide';
40
+ /**
41
+ * The {@link GridPartialPolicy} per axis: `side` governs the axis the float sits on (its `side`), `align`
42
+ * the axis it is aligned along.
43
+ * @defaultValue `{ side: 'flip', align: 'slide' }`
44
+ */
45
+ export interface GridWhenPartial {
46
+ side?: GridPartialPolicy;
47
+ align?: GridPartialPolicy;
48
+ }
28
49
  /**
29
50
  * How far the anchor pixel was pushed to stay in frame (the `clamp` fallback). Handed to the sticky
30
51
  * child so it can render differently when slid — an arrow toward the true (off-frame) anchor, etc.
@@ -60,15 +81,22 @@ export type GridAnchor = {
60
81
  point: Point;
61
82
  };
62
83
  /**
63
- * The clip / clamp boundary — a **rect fed to the positioning math**, NOT a DOM parent. This is how
64
- * "don't slide under the headers" is expressed: clamp to the data viewport.
84
+ * The clip / clamp boundary — a **rect fed to the positioning math**, NOT a DOM parent. One prop, one
85
+ * meaning: *where may this thing live*. It governs the anchor's clip / clamp AND (via `StickyPortal`)
86
+ * where `flip` / `shift` may land the float. This is how "don't slide under the headers" is expressed:
87
+ * clamp to the data viewport.
88
+ *
89
+ * Every grid-derived boundary is further cut to the **browser window** (the layout viewport): a float
90
+ * the grid does not obscure can still run off the screen, so the edge is always the grid edge ∩ the
91
+ * window edge. An explicit {@link Bounds} is used verbatim.
65
92
  *
66
93
  * - `'data'` — the union of the panes' cell areas (headers excluded). Default.
67
94
  * - `'pane'` — just the resolving pane's cell area.
68
95
  * - `'grid'` — currently the same as `'data'` (until a surface/header rect is threaded).
96
+ * - `'viewport'` — the browser window alone: the opt-out, for a float that may cover grid chrome.
69
97
  * - a {@link Bounds} — an explicit **client-px** rect.
70
98
  */
71
- export type GridBoundary = 'data' | 'pane' | 'grid' | Bounds;
99
+ export type GridBoundary = 'data' | 'pane' | 'grid' | 'viewport' | Bounds;
72
100
  /** A `DOMRect`-shaped plain object (works in Floating UI and in Node tests without a DOM). */
73
101
  export interface GridAnchorRect {
74
102
  x: number;
@@ -102,9 +130,31 @@ export interface GridAnchorResolved {
102
130
  /**
103
131
  * The anchor's range has **no visible portion** (fully scrolled off) — independent of `whenOff`. Unlike
104
132
  * {@link clipped} (which `clamp` forces false), this stays true under `clamp`, so a presence can tell
105
- * "partially obstructed / clamped" (still show) from "off-screen" (show a goto affordance).
133
+ * "partially obstructed / clamped" (still show) from "off-screen" (show a goto affordance). A
134
+ * `whenPartial: 'hide'` axis also sets it once its edge is obstructed.
106
135
  */
107
136
  outOfView: boolean;
137
+ /**
138
+ * The placement **actually used** — the requested one, or its opposite on an axis a
139
+ * `whenPartial: 'flip'` moved to the range's other edge. What the float positions by.
140
+ */
141
+ placement: GridPlacement;
142
+ }
143
+ /**
144
+ * The Floating UI **virtual reference** for a grid anchor. Stable identity (so `autoUpdate` subscribes
145
+ * once), but both members read **live**.
146
+ */
147
+ export interface GridAnchorReference {
148
+ /** The anchor's client rect, read live on every call (`autoUpdate` calls it between React renders). */
149
+ getBoundingClientRect: () => DOMRect;
150
+ /**
151
+ * The pane element. `autoUpdate` unwraps a virtual reference to *this* element and gates **every**
152
+ * DOM-side trigger on it — ancestor `scroll`, the `observeMove` layout-shift detector, element resize.
153
+ * Without it only the window `resize` listener survives, which is why the float used to need a 60fps
154
+ * `animationFrame` poll. A **getter**: the pane element only exists after mount, and resolving it
155
+ * lazily keeps this object's identity stable.
156
+ */
157
+ readonly contextElement?: Element;
108
158
  }
109
159
  /** The hook result: stable live accessors + render-time snapshot values. */
110
160
  export interface UseGridAnchorResult {
@@ -112,11 +162,14 @@ export interface UseGridAnchorResult {
112
162
  * A Floating UI **virtual reference** with **stable identity** — its `getBoundingClientRect` reads
113
163
  * the anchor **live** on every call (Floating UI's `autoUpdate` invokes it between React renders).
114
164
  */
115
- reference: {
116
- getBoundingClientRect: () => DOMRect;
117
- };
165
+ reference: GridAnchorReference;
118
166
  /** Live accessor for the boundary rect (for `shift`/`flip`/`hide` limiters). */
119
167
  getBoundaryRect: () => DOMRect;
168
+ /**
169
+ * Live accessor for the placement's anchor pixel (client px) — the live counterpart of
170
+ * {@link anchorPoint}, for a child that positions itself on the point between React renders.
171
+ */
172
+ getAnchorPoint: () => Point;
120
173
  /** Render-time snapshot: anchor outside the boundary. Updates each scroll frame (pane re-render). */
121
174
  clipped: boolean;
122
175
  /** Render-time snapshot: which side the anchor is off, when clipped. */
@@ -129,17 +182,21 @@ export interface UseGridAnchorResult {
129
182
  slid: GridSlide | null;
130
183
  /** Render-time snapshot: the range is fully scrolled off (stays true under `clamp`; see resolved). */
131
184
  outOfView: boolean;
185
+ /** Render-time snapshot: the placement actually used (see {@link GridAnchorResolved.placement}). */
186
+ placement: GridPlacement;
132
187
  /** The pane the anchor resolves against (null outside a `GridPaneProvider`). */
133
188
  pane: IGridPane | null;
134
189
  }
135
190
  /** @internal The shared placement default (`StickyAnchor` and the resolver must agree on it). */
136
191
  export declare const DEFAULT_PLACEMENT: GridPlacement;
192
+ /** @internal The shared partial-obstruction default: today's behavior made explicit. */
193
+ export declare const DEFAULT_WHEN_PARTIAL: Required<GridWhenPartial>;
137
194
  /**
138
195
  * Resolve a {@link GridAnchor} to a client rect + clip state against a boundary. **Pure** (given a
139
196
  * pane) — no React, no live DOM beyond `getBoundingClientRect`, so it is directly unit-testable with a
140
197
  * fake {@link IGridPane}. Shared by {@link useGridAnchor} (the live closures call this per frame).
141
198
  */
142
- export declare const resolveGridAnchor: (pane: IGridPane | null, anchor: GridAnchor, boundary?: GridBoundary, minVisible?: number, placement?: GridPlacement, whenOff?: GridWhenOff) => GridAnchorResolved;
199
+ export declare const resolveGridAnchor: (pane: IGridPane | null, anchor: GridAnchor, boundary?: GridBoundary, minVisible?: number, placement?: GridPlacement, whenOff?: GridWhenOff, whenPartial?: GridWhenPartial) => GridAnchorResolved;
143
200
  /**
144
201
  * Bridge a {@link GridAnchor} (grid coordinate) to a **live Floating UI virtual reference** plus clip
145
202
  * state. The pane already re-renders every layer on scroll (so the snapshot values update per frame),
@@ -153,5 +210,6 @@ export declare const useGridAnchor: (anchor: GridAnchor, options?: {
153
210
  minVisible?: number;
154
211
  placement?: GridPlacement;
155
212
  whenOff?: GridWhenOff;
213
+ whenPartial?: GridWhenPartial;
156
214
  }) => UseGridAnchorResult;
157
215
  //# sourceMappingURL=useGridAnchor.d.ts.map
@@ -2,13 +2,39 @@
2
2
  * Options for {@link useHoverIntent}.
3
3
  */
4
4
  export interface UseHoverIntentOptions {
5
- /** Dwell (ms) over a target before opening — kills pass-through flicker. @defaultValue 300 */
5
+ /**
6
+ * Dwell (ms) over a target before opening — kills pass-through flicker.
7
+ * @defaultValue the tooltip group's `enterDelay` (300), or its `enterNextDelay` (0) while armed
8
+ */
6
9
  openDelay?: number;
7
- /** Grace (ms) after leaving before closing — lets the pointer cross the gap to the float. @defaultValue 150 */
10
+ /**
11
+ * Grace (ms) after leaving before closing — lets the pointer cross the gap to the float.
12
+ * @defaultValue the tooltip group's `leaveDelay` (400)
13
+ */
8
14
  closeDelay?: number;
15
+ /**
16
+ * Join the grid's tooltip group: one tip open at a time, a fast re-open while armed, closed by any
17
+ * pointerdown or key, refused while a gesture tip is up. `false` for a hover-opened float that is not
18
+ * a tooltip — a table toolbar, a note's box — which must survive a tip opening beside it.
19
+ * @defaultValue true
20
+ */
21
+ group?: boolean;
22
+ /**
23
+ * The tip's identity in the group. A layer rendered once per pane passes one name so its copies count
24
+ * as ONE tip (they aim and open in lockstep); two layers on the same cell must differ.
25
+ * @defaultValue this hook instance
26
+ */
27
+ name?: string;
28
+ /**
29
+ * A gesture readout: opens at once (no dwell) and holds the group, so no hover tip can open until it
30
+ * closes. @defaultValue false
31
+ */
32
+ gesture?: boolean;
9
33
  }
10
34
  /** Props to spread onto the floated element so hovering IT keeps the float open. */
11
35
  export interface HoverTipProps {
36
+ /** Registers the element with the tooltip group, so a press inside an interactive tip does not close it. */
37
+ ref: React.RefCallback<Element>;
12
38
  onPointerEnter: () => void;
13
39
  onPointerLeave: () => void;
14
40
  style: React.CSSProperties;
@@ -37,13 +63,14 @@ export interface UseHoverIntentResult {
37
63
  close: () => void;
38
64
  }
39
65
  /**
40
- * The reusable **hover-intent state machine** behind a hover tooltip — delays + keep-open-on-tip-hover,
41
- * with NO hit-testing of its own. Feed it a target key via {@link UseHoverIntentResult.setTarget}
42
- * (`null` = nothing) and it debounces open / close; spread {@link UseHoverIntentResult.tipProps} on the
43
- * float so moving onto the float itself keeps it open.
66
+ * The **hover-intent state machine** behind a tip — the per-tip client of the grid's tooltip group
67
+ * ({@link TooltipProvider}): dwell / grace timing, keep-open-on-tip-hover, and the group's rules
68
+ * (single open, armed re-open, gesture preempts hover, closed by a press or a key). It does NO
69
+ * hit-testing: feed it a target key via {@link UseHoverIntentResult.setTarget} (`null` = nothing) and
70
+ * spread {@link UseHoverIntentResult.tipProps} on the float.
44
71
  *
45
- * {@link useRangeHover} wraps this with a pointer responder against a fixed range; a dynamic consumer
46
- * (e.g. an error layer discovering the hovered cell) drives `setTarget` itself.
72
+ * `RangeFloatLayer` drives it from a probe; a dynamic consumer (a layer discovering the hovered note)
73
+ * drives `setTarget` itself.
47
74
  */
48
75
  export declare const useHoverIntent: (options?: UseHoverIntentOptions) => UseHoverIntentResult;
49
76
  //# sourceMappingURL=useHoverIntent.d.ts.map
@@ -1,7 +1,14 @@
1
1
  import { default as React } from 'react';
2
2
  import { ISelection } from '../selection';
3
+ import { ListProps } from './List';
3
4
  export interface CheckboxListAttributes {
4
5
  isCheckboxList: () => true;
6
+ /** The highlighted row, or `-1` when the list is empty. */
7
+ getHighlightIndex: () => number;
8
+ /** Move the highlight `delta` rows (clamped to the list) and bring it into view. */
9
+ moveHighlight: (delta: number) => void;
10
+ /** Toggle the selected rows, as Space does: the anchor's opposite, applied to every one of them. */
11
+ toggleHighlighted: () => void;
5
12
  }
6
13
  export interface ICheckboxListElement extends HTMLDivElement, CheckboxListAttributes {
7
14
  }
@@ -13,6 +20,11 @@ export interface CheckboxListProps extends React.HTMLAttributes<HTMLDivElement>
13
20
  itemCount: number;
14
21
  /** Whether the item at `index` is checked. */
15
22
  isChecked: (index: number) => boolean;
23
+ /**
24
+ * Whether the item at `index` is partly checked: a row standing for several values (a group)
25
+ * with some of them checked. Drawn as the tri-state; the row still toggles to `!isChecked`.
26
+ */
27
+ isIndeterminate?: (index: number) => boolean;
16
28
  /**
17
29
  * Set `indices` to `checked`. Called with a single index on a click, every selected row on a keyboard
18
30
  * toggle (Space/Enter), and every row from `(Select All)`. The caller maps `index` to its own store.
@@ -32,15 +44,24 @@ export interface CheckboxListProps extends React.HTMLAttributes<HTMLDivElement>
32
44
  renderDivider?: () => React.ReactNode;
33
45
  /**
34
46
  * Show a tri-state **(Select All)** header with this label. It operates over *all* rows — which in a
35
- * filtered list are the filtered ones, so it's "Select all (filtered)" automatically.
47
+ * filtered list are the filtered ones, so it's "Select all (filtered)" automatically. It sits
48
+ * above the rows, outside the scroll, so it never leaves the view.
36
49
  */
37
50
  selectAllLabel?: React.ReactNode;
51
+ /** The header's accessible name and tooltip, when its label does not say what it is (a count). */
52
+ selectAllTitle?: string;
53
+ /** The Select All row's own attributes (a surface, a class), over its defaults. */
54
+ propsSelectAll?: React.HTMLAttributes<HTMLDivElement>;
38
55
  /** Uniform row height in px. @defaultValue 24 */
39
56
  itemHeight?: number;
40
57
  /** Selection model (highlight + Arrow nav). Created internally if omitted. */
41
58
  selection?: ISelection;
42
59
  /** Content cache-bust; bump when checked state changes without `isChecked`'s identity changing. */
43
60
  cacheToken?: unknown;
61
+ /** See `ListSurfaceProps.autoFocus`. */
62
+ autoFocus?: boolean;
63
+ /** See `ListSurfaceProps.viewport`. */
64
+ viewport?: ListProps['viewport'];
44
65
  /** Ref for the Element. */
45
66
  ref?: React.Ref<ICheckboxListElement>;
46
67
  }
@@ -1,5 +1,6 @@
1
1
  import { default as React } from 'react';
2
2
  import { ISelection } from '../selection';
3
+ import { ListSurface } from './ListSurface';
3
4
  export interface ListAttributes {
4
5
  isList: () => true;
5
6
  }
@@ -36,20 +37,28 @@ export interface ListProps extends React.HTMLAttributes<HTMLDivElement> {
36
37
  * *rendered* content changed without `renderItem`'s identity changing.
37
38
  */
38
39
  cacheToken?: unknown;
40
+ /** See `ListSurfaceProps.scrollTo`. */
41
+ scrollTo?: {
42
+ row: number;
43
+ } | null;
44
+ /** See `ListSurfaceProps.autoFocus`. */
45
+ autoFocus?: boolean;
46
+ /** See `ListSurfaceProps.viewport`. */
47
+ viewport?: React.ComponentProps<typeof ListSurface>['viewport'];
39
48
  /** Ref for the Element. */
40
49
  ref?: React.Ref<IListElement>;
41
50
  }
42
51
  /**
43
- * A virtualized **list** built on `GridSurface` with the grid's own layers — a `CellLayer` for the
44
- * items and a `SelectionLayer` for the active-row highlight + Arrow keys (the same shape as the editor
45
- * demo: a model passed to layers as props).
52
+ * A virtualized **list** of arbitrary React content, built on {@link ListSurface} — which is the
53
+ * grid's own machinery (a `CellLayer` for the items and a `SelectionLayer` for the active-row
54
+ * highlight + Arrow keys) dressed as a list.
46
55
  *
47
56
  * @remarks
48
57
  * The List's whole state is its {@link ListProps.selection}; it has no per-item callbacks and no notion
49
58
  * of "checked" or "toggle". Pointer selection is the `SelectionLayer`'s job (it hit-tests the pointer),
50
59
  * so the cells are inert, transparent content; the keyboard is the caller's via {@link ListProps.onKeyDown}.
51
- * The active row fills (no Excel anchor hole) and carries an inset ring, since the anchor is the live
52
- * Space/scroll target. See {@link CheckboxList} for the checkbox-list specialization.
60
+ * See {@link CheckboxList} for the checkbox-list specialization and {@link PickList} for the
61
+ * single-choice text list.
53
62
  */
54
63
  export declare const List: React.ForwardRefExoticComponent<Omit<ListProps, "ref"> & React.RefAttributes<IListElement>>;
55
64
  //# sourceMappingURL=List.d.ts.map
@@ -0,0 +1,52 @@
1
+ import { default as React } from 'react';
2
+ /**
3
+ * Props for {@link ListSearch}.
4
+ */
5
+ export interface ListSearchProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange'> {
6
+ /** The search text. */
7
+ value: string;
8
+ /** The search text changed — including to `''` when Escape clears it. */
9
+ onChange: (value: string) => void;
10
+ /** Escape on an empty field: the search has nothing left to clear, so the host closes. */
11
+ onClose?: () => void;
12
+ /**
13
+ * The name of the clear button shown in the field while it holds text (its tooltip and
14
+ * accessible name). Without one the button is unnamed, not absent.
15
+ */
16
+ clearLabel?: string;
17
+ /**
18
+ * In place of the search glyph inside the field: a control over the search itself (a menu of
19
+ * its options, drawn with {@link ListSearchGlyph}). The default is the glyph alone.
20
+ */
21
+ glyph?: React.ReactNode;
22
+ /** Shown before the field, on its line: an action over the rows in view. */
23
+ leading?: React.ReactNode;
24
+ /** Shown after the field, on its line: an action on the typed text (an Add). */
25
+ trailing?: React.ReactNode;
26
+ /** Ref for the input. */
27
+ ref?: React.Ref<HTMLInputElement>;
28
+ }
29
+ /**
30
+ * The rows of `items` whose `text` contains `query`, ignoring case. An empty query keeps every row.
31
+ */
32
+ export declare const filterByText: <T extends {
33
+ text: string;
34
+ }>(items: readonly T[], query: string) => readonly T[];
35
+ /** The search glyph: a magnifier, drawn in the current color. */
36
+ export declare const ListSearchGlyph: (props: {
37
+ className?: string;
38
+ }) => React.ReactElement;
39
+ /**
40
+ * The **search field** shown above a list ({@link PickList}, `CheckboxList`): a plain input that
41
+ * narrows the rows as typed, a search glyph before the text and a clear button after it while
42
+ * there is text. Filtering itself is the host's, with {@link filterByText}.
43
+ *
44
+ * @remarks
45
+ * Escape clears the text first and closes only when there is none left, so a mistyped search is
46
+ * one key from a full list and two from a closed one. The clear button does the first of those
47
+ * without taking the focus, as the next thing typed is usually another search. Every other key
48
+ * is the host's through `onKeyDown`, which is how the arrows and Enter reach the list while the
49
+ * field keeps focus.
50
+ */
51
+ export declare const ListSearch: React.ForwardRefExoticComponent<Omit<ListSearchProps, "ref"> & React.RefAttributes<HTMLInputElement>>;
52
+ //# sourceMappingURL=ListSearch.d.ts.map
@@ -0,0 +1,93 @@
1
+ import { default as React } from 'react';
2
+ import { Viewport } from '@sheetxl/utils-react';
3
+ import { CellLayerProps, CellRendererProps } from '../cell';
4
+ import { LayerEventProps } from '../layer';
5
+ import { ISelection } from '../selection';
6
+ /**
7
+ * Props for {@link ListSurface}.
8
+ */
9
+ export interface ListSurfaceProps extends React.HTMLAttributes<HTMLDivElement> {
10
+ /** Number of rows. */
11
+ itemCount: number;
12
+ /**
13
+ * Render one row, as a grid cell — the `CellLayer` renderer, so the row is handed its bounds, its
14
+ * pane (zoom) and its resolved `value`. The cell is positioned and clipped by the tiling engine.
15
+ */
16
+ renderCell: (props: CellRendererProps) => React.ReactNode;
17
+ /**
18
+ * Resolve the visible rows to render (and their `value`). Omit to render every visible row with no
19
+ * pre-resolved value — `renderCell` then derives its content from the row index.
20
+ */
21
+ getVisibleCells?: CellLayerProps['getVisibleCells'];
22
+ /**
23
+ * Uniform row height in px. Also the list's natural height (`itemCount * itemHeight`) unless
24
+ * `style.height` overrides it. @defaultValue 24
25
+ */
26
+ itemHeight?: number;
27
+ /**
28
+ * Width the **column** should be, in px — the list sizes itself to this PLUS its own chrome (the
29
+ * vertical scrollbar's gutter), so the column actually ends up this wide.
30
+ *
31
+ * @remarks
32
+ * The distinction matters because the natural thing to pass — a measured content width, e.g.
33
+ * `ICellRange.getBestFit().width` — describes the column, not the box. Setting it as the box's
34
+ * `width` instead silently hands the gutter's worth of pixels back, and content sized to fit
35
+ * exactly then does not. Omit to size from `style` and let the column take what is left.
36
+ */
37
+ contentWidth?: number;
38
+ /**
39
+ * The selection model — the active-row highlight + Arrow-key navigation. The surface's *state*.
40
+ * Owned by the caller (so it can read what's selected); a private one is created when omitted.
41
+ */
42
+ selection?: ISelection;
43
+ /**
44
+ * Event taps installed as the list's TOP layer — so they are offered keys and pointers before the
45
+ * built-in Arrow navigation and before the selection's own hit test. Handle Space/Enter here (the
46
+ * grid would otherwise consume them) and `stopPropagation` to override; anything you don't consume
47
+ * falls through to navigation.
48
+ */
49
+ propsLayer?: LayerEventProps;
50
+ /** Take focus on mount, so the Arrow keys work without a click first. @defaultValue false */
51
+ autoFocus?: boolean;
52
+ /**
53
+ * Whether the vertical scrollbar (and its gutter) is drawn. `'auto'` draws it only while the rows
54
+ * overflow the box — a list that fits has nothing to scroll and the gutter would only widen it,
55
+ * and one squeezed by its host (a popup capped to the window) scrolls as a plain list does.
56
+ * @defaultValue 'auto'
57
+ */
58
+ showScrollbar?: boolean | 'auto';
59
+ /**
60
+ * Bring `row` into view. Read by identity: a new object scrolls again, the same object does not, so
61
+ * a caller keeps one per intent (the row highlighted on open, the row a key moved to). The scroll
62
+ * waits for the surface to have a size, so it can be set before the first paint.
63
+ */
64
+ scrollTo?: {
65
+ row: number;
66
+ } | null;
67
+ /**
68
+ * The scroll state, when the caller owns it — a host that sizes the list itself (`setSizes`) or
69
+ * drives its scroll. A private one is created when omitted.
70
+ */
71
+ viewport?: Viewport;
72
+ /** Opaque content cache-bust forwarded to the `CellLayer`. */
73
+ cacheToken?: unknown;
74
+ /** Ref for the Element. */
75
+ ref?: React.Ref<HTMLDivElement>;
76
+ }
77
+ /**
78
+ * The **list chrome**: a virtualized single-column `GridSurface` wearing the grid's own layers — a
79
+ * `CellLayer` for the rows and a `SelectionLayer` for the active-row highlight + Arrow keys — dressed
80
+ * so it reads as a list rather than a grid.
81
+ *
82
+ * @remarks
83
+ * Not a list *component*: it renders no row content of its own, has no notion of an item, and adds no
84
+ * padding — {@link ListSurfaceProps.renderCell} owns the whole row box. It exists because the lists
85
+ * built on it ({@link List}, whose rows are arbitrary React, and {@link PickList}, whose rows are text)
86
+ * differ ONLY in that renderer. Everything they share — the viewport, the measured single column, the
87
+ * selection styling and its rationale, the layer order — is here, once.
88
+ *
89
+ * The single column tracks the measured content width, so a row spans the full list; scrolling is
90
+ * vertical only.
91
+ */
92
+ export declare const ListSurface: React.ForwardRefExoticComponent<Omit<ListSurfaceProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
93
+ //# sourceMappingURL=ListSurface.d.ts.map