@topgrid/grid-pro-master 0.1.0

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.
@@ -0,0 +1,393 @@
1
+ import { ReactNode, Ref, ReactElement } from 'react';
2
+ import { GridProps, GridHandle } from '@topgrid/grid-core';
3
+ export { ColumnPinGrid, ColumnPinGridProps, TreeGrid, TreeGridProps } from '@topgrid/grid-core';
4
+ import { Cell, Row, ExpandedState } from '@tanstack/react-table';
5
+ import { StorageType } from '@topgrid/grid-core/internal/storage';
6
+
7
+ /**
8
+ * @topgrid/grid-pro-master — Public type definitions for Master-Detail and Context Menu grids.
9
+ *
10
+ * G-001 (MOD-GRID-16): `<MasterDetailGrid>` wrapper enabling Master-Detail row
11
+ * expansion with `renderDetailRow` prop and controlled/uncontrolled expanded state.
12
+ *
13
+ * G-002 (MOD-GRID-16): `<ContextMenuGrid>` wrapper enabling right-click context menu
14
+ * with `contextMenuItems` prop and keyboard shortcut support.
15
+ *
16
+ * @see G-001-spec.md Section 4.1
17
+ * @see G-002-spec.md Section 4
18
+ */
19
+
20
+ /**
21
+ * Master-Detail expansion options.
22
+ *
23
+ * @typeParam TData - Row data type.
24
+ *
25
+ * @example Controlled mode
26
+ * ```tsx
27
+ * <MasterDetailGrid
28
+ * data={rows}
29
+ * columns={columns}
30
+ * renderDetailRow={(row) => <DetailPanel data={row.original} />}
31
+ * masterDetail={{
32
+ * expandedRowKeys: expandedKeys,
33
+ * onExpandChange: setExpandedKeys,
34
+ * }}
35
+ * />
36
+ * ```
37
+ */
38
+ interface MasterDetailOptions<_TData> {
39
+ /**
40
+ * Controlled expanded row key array.
41
+ * When provided, the component is in controlled mode — expanded state is
42
+ * driven externally. Keys correspond to TanStack `row.id` values.
43
+ *
44
+ * When absent, internal `useState<ExpandedState>` manages state (uncontrolled).
45
+ */
46
+ expandedRowKeys?: string[];
47
+ /**
48
+ * Callback fired when expanded rows change.
49
+ * In controlled mode, the parent must update `expandedRowKeys` from this callback.
50
+ *
51
+ * @param expandedKeys - Array of currently expanded `row.id` strings.
52
+ */
53
+ onExpandChange?: (expandedKeys: string[]) => void;
54
+ }
55
+ /**
56
+ * Render function type for the Master-Detail detail row content.
57
+ *
58
+ * @typeParam TData - Row data type.
59
+ *
60
+ * @param row - The TanStack `Row<TData>` object for the expanded master row.
61
+ * @returns ReactNode to render inside the detail row cell.
62
+ *
63
+ * @example
64
+ * ```tsx
65
+ * const renderDetailRow: RenderDetailRow<User> = (row) => (
66
+ * <UserDetailPanel userId={row.original.id} />
67
+ * );
68
+ * ```
69
+ */
70
+ type RenderDetailRow<TData> = (row: Row<TData>) => ReactNode;
71
+ /**
72
+ * Props for `<MasterDetailGrid>`.
73
+ *
74
+ * Extends `GridProps<TData>` with Master-Detail specific props.
75
+ *
76
+ * @typeParam TData - Row data type.
77
+ *
78
+ * @see MasterDetailOptions
79
+ * @see RenderDetailRow
80
+ * @see G-001-spec.md Section 4.2
81
+ */
82
+ interface MasterDetailGridProps<TData> extends GridProps<TData> {
83
+ /**
84
+ * Detail row render function.
85
+ *
86
+ * When provided, each row gains an expand toggle in the first column.
87
+ * Clicking the toggle reveals a full-width detail row rendered by this function.
88
+ *
89
+ * When absent, the grid renders as a standard flat grid without expand toggles.
90
+ */
91
+ renderDetailRow?: RenderDetailRow<TData>;
92
+ /**
93
+ * Master-Detail expansion options (controlled/uncontrolled state).
94
+ *
95
+ * @see MasterDetailOptions
96
+ */
97
+ masterDetail?: MasterDetailOptions<TData>;
98
+ }
99
+ /**
100
+ * A single context menu item definition.
101
+ *
102
+ * @typeParam TData - Row data type.
103
+ *
104
+ * @example
105
+ * ```tsx
106
+ * const items: ContextMenuItem<User>[] = [
107
+ * {
108
+ * label: '수정',
109
+ * shortcut: 'E',
110
+ * onClick: (row, cell, event) => openEditDialog(row),
111
+ * },
112
+ * { separator: true, label: '', onClick: () => {} },
113
+ * {
114
+ * label: '삭제',
115
+ * shortcut: 'Delete',
116
+ * disabled: (row) => row.locked,
117
+ * onClick: (row, cell, event) => deleteRow(row),
118
+ * },
119
+ * ];
120
+ * ```
121
+ *
122
+ * @see G-002-spec.md Section 4.1
123
+ */
124
+ interface ContextMenuItem<TData> {
125
+ /**
126
+ * Display label for the menu item.
127
+ * For separator items, the label is ignored — pass an empty string.
128
+ */
129
+ label: string;
130
+ /**
131
+ * Optional keyboard shortcut hint displayed on the right side of the label.
132
+ * When the wrapper div has focus and this key is pressed while the menu is open,
133
+ * the item's `onClick` is triggered (if not disabled).
134
+ *
135
+ * Value is a single key string matched against `event.key` (case-insensitive).
136
+ *
137
+ * @example `'E'` for the 'e' key, `'Delete'` for the Delete key
138
+ */
139
+ shortcut?: string;
140
+ /**
141
+ * Whether this item is disabled.
142
+ *
143
+ * - `boolean`: static disabled state.
144
+ * - `(row: TData) => boolean`: evaluated at render time against the target row.
145
+ *
146
+ * Disabled items are rendered but not clickable (pointer-events: none equivalent).
147
+ */
148
+ disabled?: boolean | ((row: TData) => boolean);
149
+ /**
150
+ * When `true`, renders a horizontal separator line.
151
+ * All other properties except `label` are ignored for separator items.
152
+ */
153
+ separator?: boolean;
154
+ /**
155
+ * Click handler for this menu item.
156
+ *
157
+ * @param row - The `original` data of the right-clicked row.
158
+ * @param cell - The TanStack `Cell<TData, unknown>` that was right-clicked.
159
+ * @param event - The original `MouseEvent`.
160
+ */
161
+ onClick: (row: TData, cell: Cell<TData, unknown>, event: MouseEvent) => void;
162
+ }
163
+ /**
164
+ * Props for `<ContextMenuGrid>`.
165
+ *
166
+ * Extends `GridProps<TData>` with context menu specific props.
167
+ *
168
+ * @typeParam TData - Row data type.
169
+ *
170
+ * @see ContextMenuItem
171
+ * @see G-002-spec.md Section 4.2
172
+ */
173
+ interface ContextMenuGridProps<TData> extends GridProps<TData> {
174
+ /**
175
+ * Array of context menu items displayed on right-click.
176
+ *
177
+ * When absent (or empty), right-click falls through to the browser default.
178
+ * When provided, `preventDefault()` is called and the custom menu is shown.
179
+ *
180
+ * @see ContextMenuItem
181
+ */
182
+ contextMenuItems?: ContextMenuItem<TData>[];
183
+ }
184
+ /**
185
+ * Row Pinning base type definition (F-16-06).
186
+ *
187
+ * Defines `pinTop` / `pinBottom` row id arrays for future TanStack row pinning UI.
188
+ * **Types-only in this Goal** (D20 / AC-006) — full UI implementation is a separate
189
+ * follow-up Goal. Pass these values to a future `RowPinningGrid` component.
190
+ *
191
+ * @example
192
+ * ```tsx
193
+ * const pinning: RowPinningOptions = {
194
+ * pinTop: ['row-0', 'row-1'],
195
+ * pinBottom: ['row-99'],
196
+ * };
197
+ * ```
198
+ *
199
+ * @see G-003-spec.md Section 2.3 + D6
200
+ * @see MOD-GRID-16-decisions.md D20
201
+ */
202
+ interface RowPinningOptions {
203
+ /**
204
+ * Row ids to pin at the top of the grid.
205
+ * Keys correspond to TanStack `row.id` values.
206
+ *
207
+ * @see AC-006 — UI implementation deferred to a separate Goal.
208
+ */
209
+ pinTop?: string[];
210
+ /**
211
+ * Row ids to pin at the bottom of the grid.
212
+ * Keys correspond to TanStack `row.id` values.
213
+ *
214
+ * @see AC-006 — UI implementation deferred to a separate Goal.
215
+ */
216
+ pinBottom?: string[];
217
+ }
218
+
219
+ /**
220
+ * `<MasterDetailGrid>` — Pro-tier Master-Detail row expansion.
221
+ *
222
+ * Wraps `GridProps<TData>` surface with `renderDetailRow` + `masterDetail` expansion options.
223
+ * Renders its own standalone `useReactTable` table — does NOT import `<Grid>` from
224
+ * `@topgrid/grid-core` at runtime (Option B — MIT↔Pro EULA boundary preservation, D1).
225
+ *
226
+ * Features:
227
+ * - `renderDetailRow` prop: render function for expanded detail row content.
228
+ * - Controlled mode: `masterDetail.expandedRowKeys` + `onExpandChange` callback.
229
+ * - Uncontrolled mode: internal `useState<ExpandedState>`.
230
+ * - Imperative handle: `expandAll()` / `collapseAll()` via `ref`.
231
+ *
232
+ * @see G-001-spec.md Section 4/8/11
233
+ * @see MOD-GRID-16-decisions.md D1/D3/D7/D8
234
+ */
235
+
236
+ /**
237
+ * `<MasterDetailGrid>` Pro-tier component with Master-Detail row expansion.
238
+ *
239
+ * @typeParam TData - Row data type.
240
+ *
241
+ * @example Uncontrolled
242
+ * ```tsx
243
+ * const gridRef = useRef<GridHandle<Order>>(null);
244
+ *
245
+ * <MasterDetailGrid<Order>
246
+ * ref={gridRef}
247
+ * data={orders}
248
+ * columns={columns}
249
+ * renderDetailRow={(row) => <OrderDetail order={row.original} />}
250
+ * />
251
+ *
252
+ * gridRef.current?.expandAll();
253
+ * ```
254
+ *
255
+ * @example Controlled
256
+ * ```tsx
257
+ * const [expanded, setExpanded] = useState<string[]>([]);
258
+ *
259
+ * <MasterDetailGrid<Order>
260
+ * data={orders}
261
+ * columns={columns}
262
+ * renderDetailRow={(row) => <OrderDetail order={row.original} />}
263
+ * masterDetail={{ expandedRowKeys: expanded, onExpandChange: setExpanded }}
264
+ * />
265
+ * ```
266
+ */
267
+ declare const MasterDetailGrid: <TData>(props: MasterDetailGridProps<TData> & {
268
+ ref?: Ref<GridHandle<TData>>;
269
+ }) => ReactElement;
270
+
271
+ /**
272
+ * `<ContextMenuGrid>` — Pro-tier right-click context menu grid.
273
+ *
274
+ * Wraps `GridProps<TData>` surface with `contextMenuItems` prop.
275
+ * Renders its own standalone `useReactTable` table — does NOT import `<Grid>`
276
+ * from `@topgrid/grid-core` at runtime (Option B — MIT↔Pro EULA boundary, D1).
277
+ *
278
+ * Features:
279
+ * - `contextMenuItems` prop: declarative right-click context menu items.
280
+ * - `createPortal` menu rendering into `document.body` (D4).
281
+ * - Keyboard shortcut support via wrapper div `onKeyDown` (D5).
282
+ * - `disabled` evaluation at render time (D7).
283
+ *
284
+ * @see G-002-spec.md Section 4/5/8
285
+ * @see MOD-GRID-16-decisions.md D9–D16
286
+ */
287
+
288
+ /**
289
+ * `<ContextMenuGrid>` Pro-tier component with right-click context menu support.
290
+ *
291
+ * @typeParam TData - Row data type.
292
+ *
293
+ * @example Uncontrolled
294
+ * ```tsx
295
+ * const gridRef = useRef<GridHandle<Order>>(null);
296
+ *
297
+ * const menuItems: ContextMenuItem<Order>[] = [
298
+ * { label: '수정', shortcut: 'E', onClick: (row) => openEdit(row) },
299
+ * { separator: true, label: '', onClick: () => {} },
300
+ * {
301
+ * label: '삭제',
302
+ * shortcut: 'Delete',
303
+ * disabled: (row) => row.status === 'completed',
304
+ * onClick: (row) => deleteOrder(row),
305
+ * },
306
+ * ];
307
+ *
308
+ * <ContextMenuGrid<Order>
309
+ * ref={gridRef}
310
+ * data={orders}
311
+ * columns={columns}
312
+ * contextMenuItems={menuItems}
313
+ * />
314
+ * ```
315
+ */
316
+ declare const ContextMenuGrid: <TData>(props: ContextMenuGridProps<TData> & {
317
+ ref?: Ref<GridHandle<TData>>;
318
+ }) => ReactElement;
319
+
320
+ /**
321
+ * `useExpandedPersistence` — Pro-tier hook that persists TanStack `ExpandedState`
322
+ * to Web Storage (localStorage / sessionStorage) across page refreshes.
323
+ *
324
+ * Option B — independent hook. Does NOT modify `useGridState` in `@topgrid/grid-core` (D17).
325
+ * External composition pattern: wire `[expanded, setExpanded]` return value into
326
+ * `masterDetail.expandedRowKeys` + `onExpandChange` on `<MasterDetailGrid>`.
327
+ *
328
+ * Internal SSR-guard + try/catch + JSON I/O boilerplate is now delegated to
329
+ * `@topgrid/grid-core/internal/storage` (ADR-007 Wave 3). External API, in-memory
330
+ * fallback semantics, and dev-mode warning behaviour unchanged.
331
+ *
332
+ * @see G-003-spec.md Section 2.1 + D3 (D17 in decisions.md)
333
+ * @see MOD-GRID-16-decisions.md D17
334
+ * @see MOD-GRID-REFACTOR-2026-05-17-decisions.md ADR-007
335
+ */
336
+
337
+ /**
338
+ * Options for `useExpandedPersistence`.
339
+ *
340
+ * @example
341
+ * ```tsx
342
+ * const [expanded, setExpanded] = useExpandedPersistence({
343
+ * storageKey: 'orders-grid-expanded',
344
+ * storageType: 'localStorage',
345
+ * });
346
+ * ```
347
+ */
348
+ interface UseExpandedPersistenceOptions {
349
+ /**
350
+ * Web Storage key. Use a unique key per grid instance to avoid collisions
351
+ * when multiple grids are mounted on the same page.
352
+ */
353
+ storageKey: string;
354
+ /**
355
+ * Which Web Storage to use.
356
+ * - `'localStorage'` (default): persists across browser sessions.
357
+ * - `'sessionStorage'`: cleared when the tab is closed (EC-07).
358
+ * @default 'localStorage'
359
+ */
360
+ storageType?: StorageType;
361
+ /**
362
+ * Initial `ExpandedState` used when no stored value is found or storage is unavailable.
363
+ * @default {}
364
+ */
365
+ initialExpanded?: ExpandedState;
366
+ }
367
+ /** Setter signature matching TanStack table `onExpandedChange` updater contract. */
368
+ type ExpandedStateSetter = (updated: ExpandedState | ((prev: ExpandedState) => ExpandedState)) => void;
369
+ /**
370
+ * Pro-tier hook — persists TanStack `ExpandedState` to Web Storage.
371
+ *
372
+ * @remarks
373
+ * Does NOT modify `useGridState` in `@topgrid/grid-core` (Option B, D17).
374
+ * Wire the returned `[expanded, setExpanded]` into `<MasterDetailGrid>`:
375
+ * ```tsx
376
+ * masterDetail={{
377
+ * expandedRowKeys: Object.keys(expanded).filter(k => (expanded as Record<string,boolean>)[k]),
378
+ * onExpandChange: (keys) => {
379
+ * const next: Record<string, boolean> = {};
380
+ * keys.forEach(k => { next[k] = true; });
381
+ * setExpanded(next);
382
+ * },
383
+ * }}
384
+ * ```
385
+ *
386
+ * @param options - Persistence options (storageKey, storageType, initialExpanded).
387
+ * @returns `[expanded, setExpanded]` tuple compatible with TanStack `ExpandedState`.
388
+ *
389
+ * @see G-003-spec.md Section 2.1
390
+ */
391
+ declare function useExpandedPersistence(options: UseExpandedPersistenceOptions): [ExpandedState, ExpandedStateSetter];
392
+
393
+ export { ContextMenuGrid, type ContextMenuGridProps, type ContextMenuItem, MasterDetailGrid, type MasterDetailGridProps, type MasterDetailOptions, type RenderDetailRow, type RowPinningOptions, type UseExpandedPersistenceOptions, useExpandedPersistence };