@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,13 +1,13 @@
1
1
  import { default as React } from 'react';
2
2
  import { Bounds, Point, AnchorLocation } from '@sheetxl/utils';
3
3
  import { IGridPane } from '../surface';
4
- import { GridAnchor, GridAnchorReference, GridPlacement, GridBoundary, GridWhenOff, GridSlide } from './useGridAnchor';
4
+ import { GridAnchor, GridAnchorReference, GridPlacement, GridBoundary, GridWhenOff, GridWhenPartial, GridSlide } from './useGridAnchor';
5
5
  /**
6
6
  * The state a {@link StickyAnchor} publishes to its child. Carries the resolved `anchorPoint` (+ owner /
7
7
  * clip / slide state) so the child alone decides how to render:
8
8
  *
9
9
  * - a **render-prop** child self-positions — e.g. a portal that escapes the clip and flows past the
10
- * pane bounds (this is what {@link StickyFloat} does for you);
10
+ * pane bounds (this is what {@link StickyPortal} does for you);
11
11
  * - a plain **node** ("just a div") is positioned INLINE by StickyAnchor, clipping with the pane.
12
12
  *
13
13
  * `StickyAnchor` itself is portal-agnostic; it only resolves the anchor and positions inline divs.
@@ -17,8 +17,10 @@ export interface StickyState {
17
17
  reference: GridAnchorReference;
18
18
  /** Client-space boundary rect (for `flip`/`shift`/`hide` limiters). */
19
19
  getBoundaryRect: () => DOMRect;
20
- /** The placement's anchor pixel (client px). */
20
+ /** The placement's anchor pixel (client px) — a render-time snapshot. */
21
21
  anchorPoint: Point;
22
+ /** Live accessor for the anchor pixel (client px); stable identity, reads between renders. */
23
+ getAnchorPoint: () => Point;
22
24
  /** Pane-relative range bounds (for an in-grid child) — only meaningful on the owner pane, else null. */
23
25
  bounds: Bounds | null;
24
26
  /** The pane that owns the anchor pixel (null when clipped off every pane). */
@@ -35,7 +37,10 @@ export interface StickyState {
35
37
  * (keep showing) from "off-screen" (show a goto affordance).
36
38
  */
37
39
  outOfView: boolean;
38
- /** The resolved placement. */
40
+ /**
41
+ * The placement **actually used**: the requested one, or its opposite on an axis that
42
+ * {@link StickyAnchorProps.whenPartial} flipped to the range's other visible edge.
43
+ */
39
44
  placement: GridPlacement;
40
45
  /** This instance's pane (null outside a `GridPaneProvider`). */
41
46
  pane: IGridPane | null;
@@ -63,6 +68,11 @@ export interface StickyAnchorProps {
63
68
  boundary?: GridBoundary;
64
69
  /** What happens when the anchor pixel leaves the data area. @defaultValue 'hide' */
65
70
  whenOff?: GridWhenOff;
71
+ /**
72
+ * What happens, per axis, while the range is partly obstructed — in view, but the anchored edge is
73
+ * not. @defaultValue `{ side: 'flip', align: 'slide' }`
74
+ */
75
+ whenPartial?: GridWhenPartial;
66
76
  /** Px overlap below which a geometried anchor reads as clipped. @defaultValue 0 */
67
77
  minVisible?: number;
68
78
  /** The child — a node, or a render function `(state) => node`. Reads state via {@link useSticky} too. */
@@ -71,7 +81,7 @@ export interface StickyAnchorProps {
71
81
  /**
72
82
  * A **sticky** grid layer: it resolves an {@link GridAnchor} (via {@link useGridAnchor}) to a live
73
83
  * anchor point and positions its child there. A plain `<div>` child is placed **inline** (clips with
74
- * the pane); a **render-prop** child self-positions (e.g. a portal — see {@link StickyFloat}). It owns
84
+ * the pane); a **render-prop** child self-positions (e.g. a portal — see {@link StickyPortal}). It owns
75
85
  * no portal and knows nothing about Floating UI.
76
86
  *
77
87
  * Rendered per pane like any layer; each instance publishes its own `isOwner`, so only the owner pane
@@ -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,12 +1,15 @@
1
1
  export * from './LayerTypes';
2
2
  export * from './Layer';
3
3
  export * from './VirtualDiv';
4
- export type { GridAnchor, GridAnchorReference, 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
10
  export * from './RangeFloatLayer';
10
- export * from './HoverTipLayer';
11
+ export * from './RangeTooltipLayer';
12
+ export * from './GestureTip';
11
13
  export * from './RangePrompt';
14
+ export * from './RangeTooltip';
12
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.
@@ -61,14 +82,18 @@ export type GridAnchor = {
61
82
  };
62
83
  /**
63
84
  * The clip / clamp boundary — a **rect fed to the positioning math**, NOT a DOM parent. One prop, one
64
- * meaning: *where may this thing live*. It governs the anchor's clip / clamp AND (via `StickyFloat`)
85
+ * meaning: *where may this thing live*. It governs the anchor's clip / clamp AND (via `StickyPortal`)
65
86
  * where `flip` / `shift` may land the float. This is how "don't slide under the headers" is expressed:
66
87
  * clamp to the data viewport.
67
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.
92
+ *
68
93
  * - `'data'` — the union of the panes' cell areas (headers excluded). Default.
69
94
  * - `'pane'` — just the resolving pane's cell area.
70
95
  * - `'grid'` — currently the same as `'data'` (until a surface/header rect is threaded).
71
- * - `'viewport'` — the browser viewport: the opt-out, for a float that may cover grid chrome.
96
+ * - `'viewport'` — the browser window alone: the opt-out, for a float that may cover grid chrome.
72
97
  * - a {@link Bounds} — an explicit **client-px** rect.
73
98
  */
74
99
  export type GridBoundary = 'data' | 'pane' | 'grid' | 'viewport' | Bounds;
@@ -105,9 +130,15 @@ export interface GridAnchorResolved {
105
130
  /**
106
131
  * The anchor's range has **no visible portion** (fully scrolled off) — independent of `whenOff`. Unlike
107
132
  * {@link clipped} (which `clamp` forces false), this stays true under `clamp`, so a presence can tell
108
- * "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.
109
135
  */
110
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;
111
142
  }
112
143
  /**
113
144
  * The Floating UI **virtual reference** for a grid anchor. Stable identity (so `autoUpdate` subscribes
@@ -134,6 +165,11 @@ export interface UseGridAnchorResult {
134
165
  reference: GridAnchorReference;
135
166
  /** Live accessor for the boundary rect (for `shift`/`flip`/`hide` limiters). */
136
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;
137
173
  /** Render-time snapshot: anchor outside the boundary. Updates each scroll frame (pane re-render). */
138
174
  clipped: boolean;
139
175
  /** Render-time snapshot: which side the anchor is off, when clipped. */
@@ -146,17 +182,21 @@ export interface UseGridAnchorResult {
146
182
  slid: GridSlide | null;
147
183
  /** Render-time snapshot: the range is fully scrolled off (stays true under `clamp`; see resolved). */
148
184
  outOfView: boolean;
185
+ /** Render-time snapshot: the placement actually used (see {@link GridAnchorResolved.placement}). */
186
+ placement: GridPlacement;
149
187
  /** The pane the anchor resolves against (null outside a `GridPaneProvider`). */
150
188
  pane: IGridPane | null;
151
189
  }
152
190
  /** @internal The shared placement default (`StickyAnchor` and the resolver must agree on it). */
153
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>;
154
194
  /**
155
195
  * Resolve a {@link GridAnchor} to a client rect + clip state against a boundary. **Pure** (given a
156
196
  * pane) — no React, no live DOM beyond `getBoundingClientRect`, so it is directly unit-testable with a
157
197
  * fake {@link IGridPane}. Shared by {@link useGridAnchor} (the live closures call this per frame).
158
198
  */
159
- 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;
160
200
  /**
161
201
  * Bridge a {@link GridAnchor} (grid coordinate) to a **live Floating UI virtual reference** plus clip
162
202
  * state. The pane already re-renders every layer on scroll (so the snapshot values update per frame),
@@ -170,5 +210,6 @@ export declare const useGridAnchor: (anchor: GridAnchor, options?: {
170
210
  minVisible?: number;
171
211
  placement?: GridPlacement;
172
212
  whenOff?: GridWhenOff;
213
+ whenPartial?: GridWhenPartial;
173
214
  }) => UseGridAnchorResult;
174
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,6 +37,14 @@ 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
  }
@@ -48,8 +57,8 @@ export interface ListProps extends React.HTMLAttributes<HTMLDivElement> {
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
- * See {@link CheckboxList} for the checkbox-list specialization, and `SheetValueList` in
52
- * `@sheetxl/react` for the sheet-backed one (real cells, so values format like the sheet).
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
@@ -1,4 +1,5 @@
1
1
  import { default as React } from 'react';
2
+ import { Viewport } from '@sheetxl/utils-react';
2
3
  import { CellLayerProps, CellRendererProps } from '../cell';
3
4
  import { LayerEventProps } from '../layer';
4
5
  import { ISelection } from '../selection';
@@ -48,6 +49,26 @@ export interface ListSurfaceProps extends React.HTMLAttributes<HTMLDivElement> {
48
49
  propsLayer?: LayerEventProps;
49
50
  /** Take focus on mount, so the Arrow keys work without a click first. @defaultValue false */
50
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;
51
72
  /** Opaque content cache-bust forwarded to the `CellLayer`. */
52
73
  cacheToken?: unknown;
53
74
  /** Ref for the Element. */
@@ -60,11 +81,10 @@ export interface ListSurfaceProps extends React.HTMLAttributes<HTMLDivElement> {
60
81
  *
61
82
  * @remarks
62
83
  * Not a list *component*: it renders no row content of its own, has no notion of an item, and adds no
63
- * padding — {@link ListSurfaceProps.renderCell} owns the whole row box. It exists because there are
64
- * two kinds of list ({@link List}, whose rows are arbitrary React, and `@sheetxl/react`'s
65
- * `SheetValueList`, whose rows are real sheet cells) and they differ ONLY in that renderer. Everything
66
- * they share — the viewport, the measured single column, the selection styling and its rationale, the
67
- * layer order — is here, once.
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.
68
88
  *
69
89
  * The single column tracks the measured content width, so a row spans the full list; scrolling is
70
90
  * vertical only.