@iris-ui-kit/react 0.2.3 → 0.3.1

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 (48) hide show
  1. package/dist/admin.cjs +6 -3
  2. package/dist/admin.cjs.map +1 -1
  3. package/dist/admin.js +1 -1
  4. package/dist/async.cjs +16 -7
  5. package/dist/async.cjs.map +1 -1
  6. package/dist/async.d.cts +7 -6
  7. package/dist/async.d.ts +7 -6
  8. package/dist/async.js +1 -1
  9. package/dist/chunk-3772LKJP.js +942 -0
  10. package/dist/chunk-3772LKJP.js.map +1 -0
  11. package/dist/{chunk-TO7YVSAI.js → chunk-3KYNBLRY.js} +18 -9
  12. package/dist/chunk-3KYNBLRY.js.map +1 -0
  13. package/dist/{chunk-AUA5GBT6.js → chunk-4VPCQ3U4.js} +28 -27
  14. package/dist/chunk-4VPCQ3U4.js.map +1 -0
  15. package/dist/{chunk-V3KHE2WB.js → chunk-QKDOW7FG.js} +15 -9
  16. package/dist/chunk-QKDOW7FG.js.map +1 -0
  17. package/dist/{chunk-KRFZ5KL4.js → chunk-TDVRIHE6.js} +8 -5
  18. package/dist/chunk-TDVRIHE6.js.map +1 -0
  19. package/dist/{chunk-QZJXMCRR.js → chunk-VLWZSOTH.js} +2 -2
  20. package/dist/chunk-VLWZSOTH.js.map +1 -0
  21. package/dist/data.cjs.map +1 -1
  22. package/dist/data.d.cts +2 -2
  23. package/dist/data.d.ts +2 -2
  24. package/dist/data.js +1 -1
  25. package/dist/grid.cjs +1007 -0
  26. package/dist/grid.cjs.map +1 -0
  27. package/dist/grid.d.cts +324 -0
  28. package/dist/grid.d.ts +324 -0
  29. package/dist/grid.js +5 -0
  30. package/dist/grid.js.map +1 -0
  31. package/dist/index.cjs +14296 -2652
  32. package/dist/index.cjs.map +1 -1
  33. package/dist/index.d.cts +1993 -251
  34. package/dist/index.d.ts +1993 -251
  35. package/dist/index.js +13031 -2362
  36. package/dist/index.js.map +1 -1
  37. package/dist/modal-utils.cjs +26 -25
  38. package/dist/modal-utils.cjs.map +1 -1
  39. package/dist/modal-utils.js +1 -1
  40. package/dist/skeletons.cjs +13 -7
  41. package/dist/skeletons.cjs.map +1 -1
  42. package/dist/skeletons.js +1 -1
  43. package/package.json +20 -15
  44. package/dist/chunk-AUA5GBT6.js.map +0 -1
  45. package/dist/chunk-KRFZ5KL4.js.map +0 -1
  46. package/dist/chunk-QZJXMCRR.js.map +0 -1
  47. package/dist/chunk-TO7YVSAI.js.map +0 -1
  48. package/dist/chunk-V3KHE2WB.js.map +0 -1
package/dist/index.d.ts CHANGED
@@ -1,12 +1,13 @@
1
1
  import * as _iris_ui_kit_core from '@iris-ui-kit/core';
2
- import { ReadonlyStore, Store, MachineEvent, Machine, MachineState, RealtimeHandlers, RealtimeOptions, RealtimeStatus, DisposableScope, ResilientFetcherOptions, ResilientFetcher, Variant, Size, Placement, SpreadsheetXmlOptions } from '@iris-ui-kit/core';
3
- export { AdminPreferences, AdminPreferencesState, Align, DataSourceConfig, DataSourceController, DataSourceMode, DataSourceMutateOptions, DataSourceQuery, DataSourceState, DataViewColumn, FloatingEvent, FloatingMachine, FloatingState, GroupedViewConfig, GroupedViewState, GroupedViewStore, IrisHsva, PageItem as IrisPageItem, IrisRgba, Machine, MachineConfig, MachineEvent, MachineState, MutateOptions, NavNode, Placement, ResourceController, ResourceControllerConfig, ResourceQuery, ResourceState, RowMutateOptions, Side, Size, StateNode, Store, TabItem, TabsNav, TabsNavConfig, TabsNavState, Transition, Variant, addDays, addMonths, buildMonthMatrix, clamp01, clampDate, composeEventHandlers, createAdminPreferences, createClientDataSource, createClientFetcher, createDataSource, createFloatingMachine, createGroupedView, createMachine, createResourceController, createStore, createTabsNav, endOfMonth, filterNavByAccess, findNavNode, findNavPath, firstLeaf, flattenNav, formatLocalISO, formatMonthYear, generateId, getPageRange, getWeekdayNames, hexToRgba, hsvToRgb, hsvaToRgba, isBranch, isClosable, isOutOfRange, isSameDay, isSameMonth, localStorageAdminPreferencesStorage, mergeProps, nodeAllowsRoles, rgbToHex, rgbToHsv, rgbaToHsva, startOfDay, startOfMonth, visibleNav } from '@iris-ui-kit/core';
2
+ import { ReadonlyStore, Store, MachineEvent, Machine, MachineState, RealtimeHandlers, RealtimeOptions, RealtimeStatus, DisposableScope, ResilientFetcherOptions, ResilientFetcher, Variant, Size, Placement, AuditLogType, SpreadsheetXmlOptions, Virtualizer } from '@iris-ui-kit/core';
3
+ export { AdminPreferences, AdminPreferencesState, Align, DataSourceConfig, DataSourceController, DataSourceMode, DataSourceMutateOptions, DataSourceQuery, DataSourceState, DataViewColumn, FloatingEvent, FloatingMachine, FloatingState, GroupedViewConfig, GroupedViewState, GroupedViewStore, IrisHsva, PageItem as IrisPageItem, IrisRgba, Machine, MachineConfig, MachineEvent, MachineState, MutateOptions, NavNode, Placement, ResourceController, ResourceControllerConfig, ResourceQuery, ResourceState, RowMutateOptions, Side, Size, StateNode, Store, TabItem, TabsNav, TabsNavConfig, TabsNavState, Transition, Variant, addDays, addMonths, buildMonthMatrix, clamp01, clampDate, composeEventHandlers, createAdminPreferences, createClientDataSource, createClientFetcher, createDataSource, createFloatingMachine, createGroupedView, createMachine, createResourceController, createStore, createTabsNav, endOfMonth, filterNavByAccess, findNavNode, findNavPath, firstLeaf, flattenNav, formatLocalISO, formatMonthYear, generateId, getPageRange, getWeekdayNames, hexToRgba, hsvToRgb, hsvaToRgba, isBranch, isClosable, isOutOfRange, isSameDay, isSameMonth, localStorageAdminPreferencesStorage, mergeProps, nodeAllowsRoles, parseCsv, rgbToHex, rgbToHsv, rgbaToHsva, startOfDay, startOfMonth, visibleNav } from '@iris-ui-kit/core';
4
+ export { GridFilterColumn, GridFilterQuery, GridSortColumn, LegacyGridColumnsProps, LegacyGridExpansionProps, LegacyGridFilteringProps, LegacyGridPaginationProps, LegacyGridPaginationProxyConfig, LegacyGridPaginationState, LegacyGridRowsOptions, LegacyGridRowsProps, LegacyGridSelectionProps, LegacyGridSortingProps, UseGridClipboardOptions, UseGridClipboardResult, UseGridColumnsOptions, UseGridColumnsResult, UseGridCoreOptions, UseGridEditingOptions, UseGridEditingResult, UseGridExpansionOptions, UseGridExpansionResult, UseGridFilteringOptions, UseGridFilteringResult, UseGridPaginationOptions, UseGridPaginationResult, UseGridRangeOptions, UseGridRangeResult, UseGridRowsOptions, UseGridRowsResult, UseGridSelectionOptions, UseGridSelectionResult, UseGridSortingOptions, UseGridSortingResult, UseGridVirtualOptions, UseGridVirtualResult, toGridColumnsOptions, toGridExpansionOptions, toGridFilteringOptions, toGridPaginationOptions, toGridRowsOptions, toGridSelectionOptions, toGridSortingOptions, useGridClipboard, useGridColumns, useGridCore, useGridEditing, useGridExpansion, useGridFiltering, useGridPagination, useGridRange, useGridRows, useGridSelection, useGridSorting, useGridVirtual } from './grid.js';
4
5
  export { ThemeProvider, ThemeProviderProps, UseThemeReturn, useColorScheme, useDirection, useTheme, useThemeContext, useThemeOptional } from './theme.js';
5
6
  export { ApplySkinResult, LoadSkinOptions, ResolvedSkin, Skin, SkinBootScriptConfig, SkinCatalog, SkinCatalogConfig, SkinEngine, SkinEngineConfig, SkinError, SkinErrorCode, SkinLookup, SkinManifest, SkinManifestEntry, SkinMode, SkinPatch, SkinRegistry, SkinResolutionError, SkinStorage, SkinTokenOverrides, applySkin, builtinSkins, createSkinCatalog, createSkinEngine, createSkinRegistry, darkSkin, lightSkin, loadSkin, localStorageSkinStorage, memorySkinStorage, renderSkinStyle, resolveSkin, skinBootScript, skinError, skinToCssEntries, validateSkin } from '@iris-ui-kit/skins';
6
7
  export { SkinProvider, SkinProviderProps, UseSkinReturn, useSkin, useSkinContext, useSkinOptional } from './skins.js';
7
8
  import * as react_jsx_runtime from 'react/jsx-runtime';
8
9
  import * as React from 'react';
9
- import { ButtonHTMLAttributes, ReactNode, CSSProperties, MouseEventHandler, MutableRefObject } from 'react';
10
+ import { ButtonHTMLAttributes, ReactNode, CSSProperties, MouseEventHandler } from 'react';
10
11
  import { IrisIconRegistry } from '@iris-ui-kit/icons';
11
12
  export { CreateIconRegistryOptions, IrisIconNode, IrisIconRegistry, IrisIconResolver, IrisIconSet, RenderIconOptions, ThemeIconConfig, createIconRegistry, defaultIconRegistry, defaultIcons, renderIconSvg, resolveIcon, resolveThemedIcon } from '@iris-ui-kit/icons';
12
13
  export { FieldInputProps, FormContext, IrisForm, IrisFormProps, UseFieldArrayReturn, UseFieldReturn, UseFormReturn, useField, useFieldArray, useForm, useFormContext } from './form.js';
@@ -28,6 +29,7 @@ export { IrisProvider, IrisProviderProps, PluginStoreContext, PluginStoreContext
28
29
  export { IrisErrorBoundary, IrisErrorBoundaryFallbackProps, IrisErrorBoundaryProps } from './error-boundary.js';
29
30
  export { ApplyThemeResult, ThemeStore, ThemeStoreConfig, applyTheme, createThemeStore, getCssVar, toCssVarName } from '@iris-ui-kit/theme';
30
31
  export { ALL_TOKEN_NAMES, AnyToken, COLOR_TOKENS, ColorToken, IrisTheme, IrisThemeColors, IrisThemeRadii, IrisThemeSpacing, IrisThemeType, RADII_TOKENS, RadiusToken, SPACING_TOKENS, SpacingToken, darkTheme, lightTheme } from '@iris-ui-kit/tokens';
32
+ import '@iris-ui-kit/core/grid';
31
33
  import '@floating-ui/dom';
32
34
 
33
35
  /**
@@ -2393,92 +2395,6 @@ interface IrisSelectProps<T = unknown> {
2393
2395
  */
2394
2396
  declare function IrisSelect<T = unknown>({ items, value: valueProp, defaultValue, onValueChange, multiple, placeholder, size, disabled, placement, invalid, id, ariaDescribedby, renderTrigger, style, className, virtual, ...rest }: IrisSelectProps<T>): React.ReactElement;
2395
2397
 
2396
- type IrisTableSortDirection = 'asc' | 'desc';
2397
- /** Map of column key → current width in px (after any resizing). */
2398
- type IrisTableColumnWidths = Record<string, number>;
2399
- type IrisTableEditor = 'text' | 'number' | 'select';
2400
- /** Aggregation op for a column's summary/footer cell. */
2401
- type IrisTableAggregateOp = 'sum' | 'avg' | 'min' | 'max' | 'count';
2402
- interface IrisTableVirtualOptions {
2403
- /** Per-row height in px (uniform). */
2404
- itemHeight: number;
2405
- /** Viewport height. Number → px; string → CSS length. */
2406
- height: number | string;
2407
- /** Extra rows rendered above and below the viewport. */
2408
- buffer?: number;
2409
- }
2410
- interface IrisTableSortState {
2411
- key: string;
2412
- direction: IrisTableSortDirection;
2413
- }
2414
- /**
2415
- * One search-form field (vxe-grid formConfig items parity). On submit the
2416
- * field's value merges into the table filters under `key` (client-side path
2417
- * or the proxy query); empty strings are inactive and stripped.
2418
- */
2419
- interface IrisTableFormField {
2420
- /** Filter key — matched against column keys and the query `filters` map. */
2421
- key: string;
2422
- /** Visible field label. */
2423
- label: string;
2424
- /** Control kind. Default `'text'`. */
2425
- type?: 'text' | 'select';
2426
- /** Options when `type: 'select'`. */
2427
- options?: Array<{
2428
- value: string;
2429
- label: string;
2430
- }>;
2431
- placeholder?: string;
2432
- /** Initial value; reset restores it. */
2433
- defaultValue?: string;
2434
- }
2435
- /** Params delivered to `IrisTableProps.proxyConfig.query` (vxe proxyConfig parity). */
2436
- interface IrisTableProxyQueryParams {
2437
- /** 1-based page number. */
2438
- page: number;
2439
- pageSize: number;
2440
- sort: IrisTableSortState | null;
2441
- /**
2442
- * Multi-column sort (vxe sort-config.multiple parity), most-significant
2443
- * first. Present only in multiSort mode — single mode keeps passing `sort`.
2444
- */
2445
- sorts?: IrisTableSortState[];
2446
- filters: Record<string, string>;
2447
- }
2448
- /**
2449
- * Edit-validation presentation (vxe-grid ValidConfig parity).
2450
- */
2451
- interface IrisTableValidConfig {
2452
- /**
2453
- * Render the inline editor error message (`data-iris-table-editor-error`).
2454
- * `false` still runs validation and blocks the commit — only the message
2455
- * element is skipped (`aria-invalid` stays). Default true.
2456
- */
2457
- showMessage?: boolean;
2458
- }
2459
- /** Params delivered to `IrisTableProps.seqMethod` (vxe seqMethod parity). */
2460
- interface IrisTableSeqMethodParams {
2461
- rowIndex: number;
2462
- columnIndex: number;
2463
- }
2464
- /** Coordinates delivered to `IrisTableProps.onCellClick` (vxe cell-click parity). */
2465
- interface IrisTableCellClickParams<Row = Record<string, unknown>> {
2466
- row: Row;
2467
- column: IrisTableColumn<Row>;
2468
- rowIndex: number;
2469
- columnIndex: number;
2470
- }
2471
- /**
2472
- * Coordinates delivered to `IrisTableProps.contextMenu` callbacks (vxe
2473
- * context-menu event params parity): the row/column under the cursor and its
2474
- * grid position.
2475
- */
2476
- interface IrisTableContextMenuParams<Row = Record<string, unknown>> {
2477
- row: Row;
2478
- column: IrisTableColumn<Row>;
2479
- rowIndex: number;
2480
- columnIndex: number;
2481
- }
2482
2398
  interface IrisTableColumn<Row = Record<string, unknown>> {
2483
2399
  key: string;
2484
2400
  title: string;
@@ -2488,6 +2404,18 @@ interface IrisTableColumn<Row = Record<string, unknown>> {
2488
2404
  titleSuffix?: React.ReactNode;
2489
2405
  /** Path inside the row to read the cell value from. Defaults to `key`. */
2490
2406
  dataIndex?: keyof Row | string;
2407
+ /**
2408
+ * Single-line cell formula (batch AO, iris 独有 — vxe has no computed
2409
+ * columns; the closest is a display-only formatter). Evaluated by the core
2410
+ * `evaluateFormula` parser against each row: field refs + `+ - * / %` +
2411
+ * whitelist functions SUM/AVG/MIN/MAX/COUNT (case-insensitive), optional
2412
+ * leading `=`. The COMPUTED value feeds every data consumer — cell render,
2413
+ * sorting, filtering, grouping, summary, range stats, clipboard and CSV
2414
+ * export. Errors / unknown fields → null (empty cell). An `editable`
2415
+ * formula column is DISPLAY-ONLY: inline editing, row mode and batch edit
2416
+ * ignore it. Overrides `dataIndex` / `sortBy`. Leading `=` optional.
2417
+ */
2418
+ formula?: string;
2491
2419
  sortable?: boolean;
2492
2420
  /** Sort by another field (vxe sort-by parity): the comparator reads this
2493
2421
  * field instead of the column's own value. */
@@ -2505,6 +2433,15 @@ interface IrisTableColumn<Row = Record<string, unknown>> {
2505
2433
  * the value is injected with `dangerouslySetInnerHTML`; ensure the content
2506
2434
  * is trusted to avoid XSS. */
2507
2435
  html?: boolean;
2436
+ /** Render the cell value as a link (vxe... no direct parity, batch L): return
2437
+ * `{ href, label?, target? }` or a plain href string; `null`/`undefined` falls
2438
+ * through to the formatter/raw value. The anchor text is `label` when given,
2439
+ * otherwise the formatted (or raw) text; `target: '_blank'` adds `rel="noreferrer"`. */
2440
+ link?: (value: unknown, row: Row) => {
2441
+ href: string;
2442
+ label?: string;
2443
+ target?: string;
2444
+ } | string | null;
2508
2445
  width?: number | string;
2509
2446
  /** Minimum width (px) when resizing. Default 60. */
2510
2447
  minWidth?: number;
@@ -2517,6 +2454,47 @@ interface IrisTableColumn<Row = Record<string, unknown>> {
2517
2454
  editable?: boolean;
2518
2455
  /** Editor kind. Default `'text'`. */
2519
2456
  editor?: IrisTableEditor;
2457
+ /**
2458
+ * Lock this column's cells against editing (batch BE, iris 独有 — vxe has
2459
+ * no cell-lock concept): `true` locks every cell of the column; a
2460
+ * predicate receives the row (and column) and returns whether THAT cell is
2461
+ * locked — a predicate ignoring its column argument is a row-level lock
2462
+ * (both levels share this one field). Locked cells are not editable —
2463
+ * every editing entry point no-ops (dblclick / click trigger / F2 / Tab
2464
+ * nav / row mode / batch edit / paste / fill / range clear / FNR replace /
2465
+ * Delete shortcut) — render with a striped background and
2466
+ * `data-iris-cell-locked="true"`, and stay fully interactive for
2467
+ * selection, copy and export.
2468
+ */
2469
+ locked?: boolean | ((row: Row, column: IrisTableColumn<Row>) => boolean);
2470
+ /**
2471
+ * Cell permission predicate (batch BJ, iris 独有 — vxe has no per-cell
2472
+ * permission concept): return `'readonly'` to make THAT cell read-only
2473
+ * through every editing entry point (dblclick / click trigger / F2 / Tab
2474
+ * nav / row mode / batch edit / paste / fill / range clear / FNR replace /
2475
+ * Delete shortcut); `'editable'` or absent → editable (default). DYNAMIC —
2476
+ * re-evaluated on every render (unlike `locked`, which is a static
2477
+ * declaration): permission follows the current row/column state without a
2478
+ * re-mount. Readonly cells render with a dotted texture and
2479
+ * `data-iris-cell-readonly="true"` (distinct from locked's 45° stripes),
2480
+ * and stay fully interactive for selection, copy and export. When a cell is
2481
+ * both locked and readonly, locked wins visually (stripes + not-allowed).
2482
+ */
2483
+ cellPermission?: (row: Row, column: IrisTableColumn<Row>) => 'readonly' | 'editable';
2484
+ /** Batch AN column preset (iris 独有): fills display defaults from the core
2485
+ * factory — `'money'` (2 decimals + thousands separator, right-aligned,
2486
+ * number editor + numeric editRules), `'progress'` (percent text, right),
2487
+ * `'date'` (String passthrough, left), `'status'` (UPPERCASE text, center).
2488
+ * User fields always win over the preset defaults (defined-fields-only
2489
+ * merge); localized formatting stays the caller's job. */
2490
+ preset?: _iris_ui_kit_core.ColumnPreset;
2491
+ /**
2492
+ * Native datalist suggestions while editing (batch AM, iris 独有): `true`
2493
+ * builds the option list from the DISTINCT cell values of this column over
2494
+ * the current body data (String-coerced, null/'' excluded, sorted, capped at
2495
+ * 50); an explicit array of `string | number` is used verbatim. Text editor
2496
+ * only — the number/select/textarea editors ignore it. */
2497
+ suggest?: boolean | Array<string | number>;
2520
2498
  /**
2521
2499
  * Options for the `'select'` editor (vxe edit-render options parity). A
2522
2500
  * column with `editor: 'select'` renders a native `<select>` while editing;
@@ -2562,6 +2540,302 @@ interface IrisTableColumn<Row = Record<string, unknown>> {
2562
2540
  sorter?: (a: Row, b: Row) => number;
2563
2541
  /** Custom render for cell content. */
2564
2542
  render?: (value: unknown, row: Row, rowIndex: number) => React.ReactNode;
2543
+ /** Format a cell's value for display (vxe formatter parity, batch I). Applied AFTER
2544
+ * `render`/`html` and BEFORE the raw value; sorting, filtering, editing and summary
2545
+ * keep reading the RAW value. The tooltip defaults to the formatted text when it is
2546
+ * a string. With `clipConfig.copyWithFormat` (batch CU, iris 独有) the range copy
2547
+ * (Ctrl/Cmd+C / toolbar 复制) carries this formatted text instead of the raw value. */
2548
+ formatter?: (value: unknown, row: Row) => React.ReactNode;
2549
+ /** Mask this column's value for display (batch AY, iris 独有 — vxe has no
2550
+ * built-in masking): `'sensitive'` applies the core `maskValue` sensitive
2551
+ * rule (email → 11-digit phone → generic); a custom function receives the
2552
+ * RAW cell value and returns the masked string. Applied FIRST in the
2553
+ * display chain — `render`/`html`/`link`/`formatter`/tooltip all see the
2554
+ * masked value (a `formatter` receives the masked STRING); inline editing,
2555
+ * validation, sorting, filtering, summary, range stats and conditional
2556
+ * styles keep reading the RAW value. Export/copy mask by default unless
2557
+ * `exportRaw` is set. */
2558
+ mask?: 'sensitive' | ((value: unknown) => string);
2559
+ /** Export/copy the RAW value instead of the masked one (batch AY): when
2560
+ * true, `exportCsv`/`exportCurrentViewCsv`/`exportSelectionCsv` and the
2561
+ * clipboard TSV skip this column's mask. Display keeps masking. */
2562
+ exportRaw?: boolean;
2563
+ /**
2564
+ * Render this numeric column's cells as a mini trend line (batch BI, iris
2565
+ * 独有 — vxe has no sparkline): each cell shows a 20×8 SVG polyline of the
2566
+ * column's values over `filteredData[0..i]` INCLUSIVE (the current value is
2567
+ * the final point), so sorting/filtering reorder and trim the series.
2568
+ * Only cells whose RAW value is a finite number render an SVG (non-numeric
2569
+ * cells render nothing); series points coerce like `buildChartData`
2570
+ * (null/non-finite → gap). Wins over `render`/`html`/`link`/`formatter`/
2571
+ * raw; mask, editing, copy/export and summary stay untouched. The cell
2572
+ * `title` shows the series ("10, 4, 8") instead of the tooltip.
2573
+ */
2574
+ sparkline?: boolean;
2575
+ /** Show a header filter trigger + checkbox panel (vxe filterConfig parity, batch I).
2576
+ * Filtering OR-matches the raw `String(value)` against the checked set. */
2577
+ filterable?: boolean;
2578
+ /** Checkbox options for the filter panel; a column without options can't filter. */
2579
+ filterOptions?: IrisTableFilterOption[];
2580
+ /**
2581
+ * Group the body by this column's value (vxe group-config parity, batch M):
2582
+ * a group header row per distinct value (first-appearance order,
2583
+ * `data-iris-group-row`) showing the value + count, then that group's rows,
2584
+ * then a per-group summary row (`data-iris-group-summary`, same `summary`
2585
+ * ops as the footer computed over the group's rows) when any column has a
2586
+ * `summary` op. Flat mode only — tree mode ignores grouping (fail-closed);
2587
+ * proxy mode groups per loaded page. Only the first `groupBy` column drives
2588
+ * the plan — unless the table-level `groupBy?: string[]` (batch BS) is set,
2589
+ * which wins and drives nested multi-column grouping instead. Group headers are collapsible (batch BH, iris 独有): the
2590
+ * `data-iris-group-toggle` button collapses the group (rows + per-group
2591
+ * summary hidden, header + count stay) via `groupCollapsed` /
2592
+ * `defaultGroupCollapsed` / `onGroupCollapseChange`.
2593
+ */
2594
+ groupBy?: boolean;
2595
+ /** Hide this column entirely (vxe column visibleMethod parity, batch U): a
2596
+ * predicate evaluated in the display-columns memo (at most once per
2597
+ * render); `false` hides the column even when `columnVisibility` says
2598
+ * visible (the column's own veto wins). Absent / `true` keeps it. Scope
2599
+ * mirrors `columnVisibility`: top-level columns only — a grouped column's
2600
+ * leaf `visibleMethod` is not consulted (same documented simplification). */
2601
+ visibleMethod?: () => boolean;
2602
+ }
2603
+
2604
+ /**
2605
+ * One named view preset (batch AH, iris 独有): a user-saved snapshot of the
2606
+ * table's persistable state pieces — the SAME shape `persistState` loads and
2607
+ * saves, captured by the same collector and applied through the same change
2608
+ * callbacks.
2609
+ */
2610
+ interface IrisTableNamedView {
2611
+ /** View name (also the view's key in the toolbar select). */
2612
+ name: string;
2613
+ /** The state pieces captured when the view was saved. */
2614
+ snapshot: IrisTablePersistedState;
2615
+ }
2616
+ /**
2617
+ * Named view presets (batch AH, iris 独有 — vxe has no equivalent; its
2618
+ * closest is manual state saving). The toolbar renders a compact select
2619
+ * (`data-iris-table-views`) of user-saved snapshots: picking a view replays
2620
+ * its snapshot through the change callbacks (same per-piece gating as
2621
+ * `persistState`; `pageSize` reproduces the mount-restore sequence
2622
+ * `onPageChange(1, size)` + one request); the "+ 保存" item opens an inline
2623
+ * input (`data-iris-views-save`) that snapshots the CURRENT pieces under a
2624
+ * typed name (duplicate names upsert); the × button deletes the active view.
2625
+ * Views load from storage on mount with the same guards as `persistState`
2626
+ * and persist on every change; `activeKey` is controlled-only (never
2627
+ * persisted).
2628
+ */
2629
+ interface IrisTableViewConfig {
2630
+ /** Storage adapter (`getItem`/`setItem`; defaults to `localStorage`).
2631
+ * `false` keeps views in-memory only — no reads, no writes. */
2632
+ storage?: Pick<Storage, 'getItem' | 'setItem'> | false;
2633
+ /** Storage key. Default `'iris-table-views'`. */
2634
+ key?: string;
2635
+ /** Label formatter for a view name (rendered in the toolbar select). */
2636
+ label?: (name: string) => string;
2637
+ /** Controlled active view key; omit for uncontrolled (internal state). */
2638
+ activeKey?: string | null;
2639
+ }
2640
+
2641
+ type IrisTableSortDirection = 'asc' | 'desc';
2642
+ /** Map of column key → current width in px (after any resizing). */
2643
+ type IrisTableColumnWidths = Record<string, number>;
2644
+ /**
2645
+ * Custom column panel options (vxe-grid customConfig parity, batch S): the
2646
+ * toolbar `columnSettings` button opens the full panel — search, drag reorder,
2647
+ * visibility toggles and reset — in place of the plain checkbox menu.
2648
+ */
2649
+ interface IrisTableCustomConfig {
2650
+ /** Reset button label; defaults to the i18n `table.customConfig.reset` key. */
2651
+ resetText?: string;
2652
+ }
2653
+ type IrisTableEditor = 'text' | 'number' | 'select' | 'textarea';
2654
+ /** One checkbox option of a filterable column's filter panel (vxe filter-option parity). */
2655
+ interface IrisTableFilterOption {
2656
+ value: string;
2657
+ label: string;
2658
+ }
2659
+ /**
2660
+ * Per-column checked filter sets (vxe filter-multiple parity): column key →
2661
+ * values OR-matched against the raw `String(value)` of each row. Controlled
2662
+ * through `IrisTableProps.filterValues` / `onFilterValuesChange`.
2663
+ */
2664
+ type IrisTableFilterValues = Record<string, string[]>;
2665
+ /** Aggregation op for a column's summary/footer cell. */
2666
+ type IrisTableAggregateOp = 'sum' | 'avg' | 'min' | 'max' | 'count';
2667
+ /** Horizontal cell alignment (vxe align / header-align / footer-align parity). */
2668
+ type IrisTableAlign = 'left' | 'center' | 'right';
2669
+ interface IrisTableVirtualOptions {
2670
+ /** Per-row height in px (uniform), or a `(index) => px` function for known
2671
+ * variable heights (batch AG — the iris take on vxe `virtualYConfig` 增强
2672
+ * 模式; the fn receives the virtual PLAN index — memoize it). */
2673
+ itemHeight: number | ((index: number) => number);
2674
+ /** Viewport height. Number → px; string → CSS length. */
2675
+ height: number | string;
2676
+ /** Extra rows rendered above and below the viewport. */
2677
+ buffer?: number;
2678
+ }
2679
+ /** State pieces persistable via `persistState` (batch AG, iris 独有). */
2680
+ type IrisTablePersistPiece = 'sort' | 'multiSortState' | 'filters' | 'filterValues' | 'columnVisibility' | 'columnOrder' | 'columnWidths' | 'pageSize' | 'expandedKeys';
2681
+ /** One persisted state snapshot (batch AG): the pieces `persistState` loads
2682
+ * and saves, keyed by piece name — a piece appears only when defined + included. */
2683
+ interface IrisTablePersistedState {
2684
+ sort?: IrisTableSortState | null;
2685
+ multiSortState?: IrisTableSortState[];
2686
+ filters?: Record<string, string>;
2687
+ filterValues?: IrisTableFilterValues;
2688
+ columnVisibility?: Record<string, boolean>;
2689
+ columnOrder?: string[];
2690
+ columnWidths?: IrisTableColumnWidths;
2691
+ pageSize?: number;
2692
+ /** Batch BY: expanded row keys (detail panels + tree carets) captured by
2693
+ * the shared collector when `onExpandedRowsChange` is set and the table
2694
+ * actually expands (renderDetail or tree mode); restored through the
2695
+ * expansion model — `expansion.set` commits and replays
2696
+ * `onExpandedRowsChange(keys)` (expansion has no controlled prop, so the
2697
+ * callback is the parent-owned channel). Row keys are STRINGIFIED at the
2698
+ * model boundary, so the stored array is always strings; the snapshot
2699
+ * accepts raw keys and the restore coerces them. Stale keys (rows not
2700
+ * loaded yet) are fail-inert — the row simply renders expanded when it
2701
+ * arrives. */
2702
+ expandedKeys?: Array<string | number>;
2703
+ /** Batch AJ: natural-language query captured by the named-views collector
2704
+ * when `query` is set; restored FIRST via `onQueryChange` on view apply
2705
+ * (persistState path stays byte-identical; legacy views load unchanged). */
2706
+ query?: string;
2707
+ }
2708
+ /**
2709
+ * `persistState` configuration (batch AG, iris 独有 — vxe has no built-in
2710
+ * state persistence). Persists view state (sort / filters / column layout /
2711
+ * page size) to a storage adapter so a table remounts where the user left it.
2712
+ * The table is CONTROLLED: restore replays through the change callbacks and
2713
+ * saves serialize the current props on every change.
2714
+ */
2715
+ interface IrisTablePersistConfig {
2716
+ /** Storage adapter (`getItem`/`setItem`; defaults to `localStorage`).
2717
+ * `false` fully disables persistence — no reads, no writes. */
2718
+ storage?: Pick<Storage, 'getItem' | 'setItem'> | false;
2719
+ /** Storage key. Default `'iris-table-state'`. */
2720
+ key?: string;
2721
+ /** Pieces to persist. Defaults to ALL pieces. */
2722
+ include?: Array<IrisTablePersistPiece>;
2723
+ }
2724
+ /** Periodic full view-state snapshots (batch DM, iris 独有). Unlike
2725
+ * `persistState`, this config owns a separate timer/key and writes the same
2726
+ * JSON shape exposed by `tableRef.exportStateJson()`. */
2727
+ interface IrisTableAutoSaveStateConfig {
2728
+ /** Positive interval in milliseconds; zero/invalid values disable the timer. */
2729
+ intervalMs?: number;
2730
+ /** Storage adapter; defaults to `localStorage` when available. `false` disables IO. */
2731
+ storage?: Pick<Storage, 'getItem' | 'setItem'> | false;
2732
+ /** Storage key. Defaults to `'iris-table-auto-state'`. */
2733
+ key?: string;
2734
+ }
2735
+ /** One external drop target for rowDragBetween (batch DQ). */
2736
+ interface IrisTableRowDragBetweenTarget<Row extends Record<string, unknown> = Record<string, unknown>> {
2737
+ /** Value read from the target element's `data-iris-drop-zone` attribute. */
2738
+ key: string;
2739
+ /** Called once with the dragged row when it is released over that target. */
2740
+ onDrop: (row: Row) => void;
2741
+ }
2742
+
2743
+ /**
2744
+ * One table tab (batch CT, iris 独有 — vxe has no parity): a named tab in
2745
+ * the `tableTabs` strip rendered ABOVE the toolbar. Clicking the tab applies
2746
+ * each view name in `views` IN ORDER through the SAME `selectView` path the
2747
+ * toolbar select uses — unknown names are skipped fail-inert, and when
2748
+ * several views touch the same state piece the LAST applied view wins (the
2749
+ * toolbar select then mirrors that last view). An empty `views` array
2750
+ * renders an inert tab; without the `views` config the whole strip is inert.
2751
+ */
2752
+ interface IrisTableTab {
2753
+ /** Tab key (identity — the first occurrence wins on duplicates). */
2754
+ key: string;
2755
+ /** Tab label. */
2756
+ label: string;
2757
+ /** Named views applied in order on click; omitted → inert tab. */
2758
+ views?: string[];
2759
+ }
2760
+ interface IrisTableSortState {
2761
+ key: string;
2762
+ direction: IrisTableSortDirection;
2763
+ }
2764
+ /**
2765
+ * One search-form field (vxe-grid formConfig items parity). On submit the
2766
+ * field's value merges into the table filters under `key` (client-side path
2767
+ * or the proxy query); empty strings are inactive and stripped.
2768
+ */
2769
+ interface IrisTableFormField {
2770
+ /** Filter key — matched against column keys and the query `filters` map. */
2771
+ key: string;
2772
+ /** Visible field label. */
2773
+ label: string;
2774
+ /** Control kind. Default `'text'`. */
2775
+ type?: 'text' | 'select';
2776
+ /** Options when `type: 'select'`. */
2777
+ options?: Array<{
2778
+ value: string;
2779
+ label: string;
2780
+ }>;
2781
+ placeholder?: string;
2782
+ /** Initial value; reset restores it. */
2783
+ defaultValue?: string;
2784
+ }
2785
+ /** Params delivered to `IrisTableProps.proxyConfig.query` (vxe proxyConfig parity). */
2786
+ interface IrisTableProxyQueryParams {
2787
+ /** 1-based page number. */
2788
+ page: number;
2789
+ pageSize: number;
2790
+ sort: IrisTableSortState | null;
2791
+ /**
2792
+ * Multi-column sort (vxe sort-config.multiple parity), most-significant
2793
+ * first. Present only in multiSort mode — single mode keeps passing `sort`.
2794
+ */
2795
+ sorts?: IrisTableSortState[];
2796
+ filters: Record<string, string>;
2797
+ }
2798
+ /**
2799
+ * Edit-validation presentation (vxe-grid ValidConfig parity).
2800
+ */
2801
+ interface IrisTableValidConfig {
2802
+ /**
2803
+ * Render the inline editor error message (`data-iris-table-editor-error`).
2804
+ * `false` still runs validation and blocks the commit — only the message
2805
+ * element is skipped (`aria-invalid` stays). Default true.
2806
+ */
2807
+ showMessage?: boolean;
2808
+ }
2809
+ /** Params delivered to `IrisTableProps.seqMethod` (vxe seqMethod parity). */
2810
+ interface IrisTableSeqMethodParams {
2811
+ rowIndex: number;
2812
+ columnIndex: number;
2813
+ }
2814
+ /** Coordinates delivered to `IrisTableProps.onCellClick` (vxe cell-click parity). */
2815
+ interface IrisTableCellClickParams<Row = Record<string, unknown>> {
2816
+ row: Row;
2817
+ column: IrisTableColumn<Row>;
2818
+ rowIndex: number;
2819
+ columnIndex: number;
2820
+ }
2821
+ /**
2822
+ * Coordinates delivered to `IrisTableProps.contextMenu` callbacks (vxe
2823
+ * context-menu event params parity): the row/column under the cursor and its
2824
+ * grid position.
2825
+ */
2826
+ interface IrisTableContextMenuParams<Row = Record<string, unknown>> {
2827
+ row: Row;
2828
+ column: IrisTableColumn<Row>;
2829
+ rowIndex: number;
2830
+ columnIndex: number;
2831
+ }
2832
+
2833
+ /** Params delivered to `IrisTableProps.footerMethod` (vxe footer-method parity). */
2834
+ interface IrisTableFooterMethodParams<Row = Record<string, unknown>> {
2835
+ /** Leaf columns of the table (grouped headers flattened). */
2836
+ columns: IrisTableColumn<Row>[];
2837
+ /** Full body rows (sorted + filtered). */
2838
+ data: Row[];
2565
2839
  }
2566
2840
  interface IrisTableCellEditEvent<Row = Record<string, unknown>> {
2567
2841
  row: Row;
@@ -2570,6 +2844,33 @@ interface IrisTableCellEditEvent<Row = Record<string, unknown>> {
2570
2844
  newValue: unknown;
2571
2845
  rowIndex: number;
2572
2846
  }
2847
+ /** Params delivered to `IrisTableProps.onEditStart` (vxe edit-activated parity, batch V). */
2848
+ interface IrisTableEditStartParams<Row = Record<string, unknown>> {
2849
+ row: Row;
2850
+ column: IrisTableColumn<Row>;
2851
+ rowIndex: number;
2852
+ }
2853
+ /**
2854
+ * Params delivered to `IrisTableProps.onEditClosed` (vxe edit-closed parity,
2855
+ * batch V). Cell mode only — row-edit sessions commit per column through
2856
+ * their own stores and are not reported (documented simplification); an
2857
+ * async-validating commit that lands after `commitEdit` returned is also not
2858
+ * reported (the sync path fires with the committed value).
2859
+ */
2860
+ interface IrisTableEditClosedParams<Row = Record<string, unknown>> {
2861
+ row: Row;
2862
+ column: IrisTableColumn<Row>;
2863
+ rowIndex: number;
2864
+ /** The committed value; undefined when the edit was cancelled. */
2865
+ value?: unknown;
2866
+ /** true when the edit was cancelled (Escape) instead of committed. */
2867
+ cancelled: boolean;
2868
+ }
2869
+ /** Scroll coordinates delivered to `IrisTableProps.onScroll` (vxe scroll parity, batch V). */
2870
+ interface IrisTableScrollParams {
2871
+ scrollTop: number;
2872
+ scrollLeft: number;
2873
+ }
2573
2874
  type IrisTableRenderDetail<Row = Record<string, unknown>> = (row: Row, rowIndex: number) => React.ReactNode;
2574
2875
  type IrisTableRowExpandable<Row = Record<string, unknown>> = (row: Row, rowIndex: number) => boolean;
2575
2876
  /**
@@ -2581,10 +2882,11 @@ type IrisTableRowExpandable<Row = Record<string, unknown>> = (row: Row, rowIndex
2581
2882
  interface IrisTableTooltipConfig<Row = Record<string, unknown>> {
2582
2883
  /**
2583
2884
  * Render a tooltip on every body cell. Default true when `tooltipConfig` is
2584
- * set. Truncation-based gating (vxe `showAll: false`) is not implemented
2585
- * cells always carry the `title` (documented simplification: detecting a
2586
- * truncated cell cheaply isn't possible without layout measurement).
2587
- * `false` is accepted for API parity and behaves identically this batch.
2885
+ * set. With `false`, the native `title` is emitted only when the cell's
2886
+ * single-line content is measured wider than its rendered box; the table
2887
+ * rechecks after root resize. SSR/jsdom (where layout dimensions are zero)
2888
+ * fail open and keep the title. `true` keeps the title on every non-empty
2889
+ * cell.
2588
2890
  */
2589
2891
  showAll?: boolean;
2590
2892
  /**
@@ -2593,86 +2895,994 @@ interface IrisTableTooltipConfig<Row = Record<string, unknown>> {
2593
2895
  */
2594
2896
  content?: (row: Row, column: IrisTableColumn<Row>) => string;
2595
2897
  }
2898
+ /**
2899
+ * One header-merge entry (vxe-grid mergeHeaderCells parity, batch P). The
2900
+ * coordinate space is the FLAT header's leaf-column index: `row` 0 only —
2901
+ * entries with `row` > 0 are ignored (the flat header is a single row), and
2902
+ * grouped headers are NOT merged (documented simplification).
2903
+ */
2904
+ interface IrisTableMergeCell {
2905
+ /** Header row index — only 0 is supported (flat header). */
2906
+ row: number;
2907
+ /** Leaf-column index of the merged cell's origin. */
2908
+ col: number;
2909
+ /** Columns spanned (gridColumnEnd); the covered cells render null. */
2910
+ colspan?: number;
2911
+ /** Rows spanned (gridRowEnd); inert on the single flat header row. */
2912
+ rowspan?: number;
2913
+ }
2914
+ /**
2915
+ * Span result shared by `spanMethod` and `footerSpanMethod` (vxe
2916
+ * span-method / footer-span-method parity): both dimensions default to 1;
2917
+ * values > 1 make the cell span adjacent cells, which then render null.
2918
+ * Footer note: `rowspan` is inert in the footer stack (each footer row is
2919
+ * its own grid container — see `footerSpanMethod`).
2920
+ */
2921
+ interface IrisTableSpan {
2922
+ rowspan?: number;
2923
+ colspan?: number;
2924
+ }
2925
+ /** Params delivered to `IrisTableProps.footerSpanMethod` (vxe footer-span-method parity, batch P). */
2926
+ interface IrisTableFooterSpanParams<Row = Record<string, unknown>> {
2927
+ /** 0-based row index over the rendered footer stack (footerMethod rows →
2928
+ * summary row → footerData rows, whichever render). */
2929
+ rowIndex: number;
2930
+ columnIndex: number;
2931
+ /** Leaf columns of the table (grouped headers flattened). */
2932
+ columns: IrisTableColumn<Row>[];
2933
+ /** Full body rows (sorted + filtered). */
2934
+ data: Row[];
2935
+ }
2936
+ /** Footer cell merge callback (vxe footer-span-method parity, batch P). */
2937
+ type IrisTableFooterSpanMethod<Row = Record<string, unknown>> = (params: IrisTableFooterSpanParams<Row>) => IrisTableSpan | null;
2938
+ /** vxe-grid scrollbarConfig parity (batch Q): `theme: 'thin'` → 6px webkit + Firefox `scrollbar-width: thin` via `data-iris-scrollbar-thin`. */
2939
+ type IrisTableScrollbarConfig = {
2940
+ theme?: 'default' | 'thin';
2941
+ };
2942
+ /** vxe-grid editDirtyConfig parity (batch Q): a committed cell whose value
2943
+ * differs from its pre-edit original renders a primary dot
2944
+ * (`data-iris-cell-dirty`); committing the original value clears it.
2945
+ * `indicator: false` suppresses the dot (tracking stays); `className: true`
2946
+ * also adds an `iris-table-cell-dirty` class for custom styling. */
2947
+ type IrisTableEditDirtyConfig = {
2948
+ indicator?: boolean;
2949
+ className?: boolean;
2950
+ };
2951
+ /**
2952
+ * One conditional-formatting rule (batch AX, iris 独有 — vxe has no built-in
2953
+ * conditional-formatting engine). Passed via `IrisTableProps.conditionalStyles`:
2954
+ * a rule matches a body cell when its optional `column` filter (omitted →
2955
+ * every column) equals the cell's column key AND `when(row, value)` returns
2956
+ * true — `value` is the RAW cell value (`dataIndex ?? key` resolved, formula
2957
+ * columns computed via `getCellValue`). Matching rules merge in array order
2958
+ * after `cellStyle`; later rules win on conflicting style keys.
2959
+ */
2960
+ interface IrisTableConditionalStyle<Row = Record<string, unknown>> {
2961
+ /** Column key the rule applies to; omitted → every column. */
2962
+ column?: string;
2963
+ /** Match predicate: `row` is the full row object, `value` the raw cell value. */
2964
+ when: (row: Row, value: unknown) => boolean;
2965
+ /** Inline styles merged onto the body cell when the rule matches. */
2966
+ style: React.CSSProperties;
2967
+ }
2968
+ /**
2969
+ * One footer-merge entry (vxe-grid mergeFooterItems parity, batch R). The
2970
+ * coordinate space matches `footerSpanMethod`: `row` is the 0-based index
2971
+ * over the rendered footer stack (footerMethod rows → summary row →
2972
+ * footerData rows, whichever render) and `col` the leaf-column index — both
2973
+ * start at 0. The function (`footerSpanMethod`) wins when both are provided.
2974
+ */
2975
+ interface IrisTableMergeFooterItem {
2976
+ /** 0-based footer-stack row index (footerMethod rows → summary row → footerData rows). */
2977
+ row: number;
2978
+ /** Leaf-column index of the merged cell's origin. */
2979
+ col: number;
2980
+ /** Columns spanned (gridColumnEnd); the covered cells of the same row render null. */
2981
+ colspan?: number;
2982
+ /** Rows spanned — INERT (each footer row is its own grid container, so
2983
+ * `gridRowEnd` cannot cross rows): covered cells of later rows keep their
2984
+ * own data, like `footerSpanMethod`'s rowspan. */
2985
+ rowspan?: number;
2986
+ }
2987
+
2988
+ /**
2989
+ * Unified event stream palette (batch DW, iris 独有 — vxe has no single event
2990
+ * bus): the `type` names one of the closed event families; `detail` carries
2991
+ * the SAME params the matching dedicated callback receives (reference-
2992
+ * identical `row`/`column`). Events fire AFTER the dedicated callback — the
2993
+ * bus is a bridge, not a behavior. Controllable proxy `sort` updates (a
2994
+ * parent-driven `sort`/`multiSortState` prop change — not a user click) fire
2995
+ * no event. The expansion family mirrors the shared `onExpandedRowsChange`
2996
+ * channel: EVERY model commit fires `expanded-rows-change` — user toggles,
2997
+ * `expandAll` seeding, and `persistState`/view `expandedKeys` restores all
2998
+ * replay through the expansion model's `onChange` (a restore still needs
2999
+ * `onExpandedRowsChange` + an expandable table — the same gate as the
3000
+ * dedicated callback).
3001
+ */
3002
+ type IrisTableEvent<Row = Record<string, unknown>> = {
3003
+ type: 'cell-click';
3004
+ detail: IrisTableCellClickParams<Row>;
3005
+ } | {
3006
+ type: 'cell-dblclick';
3007
+ detail: IrisTableCellClickParams<Row>;
3008
+ } | {
3009
+ type: 'row-click';
3010
+ detail: {
3011
+ row: Row;
3012
+ rowIndex: number;
3013
+ };
3014
+ } | {
3015
+ type: 'row-dblclick';
3016
+ detail: {
3017
+ row: Row;
3018
+ rowIndex: number;
3019
+ };
3020
+ } | {
3021
+ type: 'sort-change';
3022
+ detail: {
3023
+ sort: IrisTableSortState | null;
3024
+ };
3025
+ } | {
3026
+ type: 'multi-sort-change';
3027
+ detail: {
3028
+ sorts: IrisTableSortState[];
3029
+ };
3030
+ } | {
3031
+ type: 'filter-change';
3032
+ detail: {
3033
+ filters: Record<string, string>;
3034
+ };
3035
+ } | {
3036
+ type: 'filter-value-change';
3037
+ detail: {
3038
+ filterValues: IrisTableFilterValues;
3039
+ };
3040
+ } | {
3041
+ type: 'edit-start';
3042
+ detail: IrisTableEditStartParams<Row>;
3043
+ } | {
3044
+ type: 'edit-commit';
3045
+ detail: IrisTableEditClosedParams<Row>;
3046
+ } | {
3047
+ type: 'edit-cancel';
3048
+ detail: IrisTableEditClosedParams<Row>;
3049
+ } | {
3050
+ type: 'expand-change';
3051
+ detail: {
3052
+ row: Row;
3053
+ expanded: boolean;
3054
+ };
3055
+ } | {
3056
+ type: 'tree-expand-change';
3057
+ detail: {
3058
+ row: Row;
3059
+ expanded: boolean;
3060
+ };
3061
+ } | {
3062
+ type: 'expanded-rows-change';
3063
+ detail: {
3064
+ expandedKeys: string[];
3065
+ };
3066
+ };
2596
3067
 
3068
+ interface IrisTableHandle<Row extends Record<string, unknown> = Record<string, unknown>> {
3069
+ /** Insert a row at `index` (default: end). A missing `rowKeyField` value gets an auto id. */
3070
+ insertRow: (row: Row, index?: number) => void;
3071
+ /** Clone the row with `key` (iris 独有): all field values shallow-copied onto a fresh auto id, inserted right after the source (or at `index`); missing key is a silent no-op. */
3072
+ cloneRow: (key: string | number, index?: number) => void;
3073
+ /** Remove the row with `key`; its selection is pruned. */
3074
+ removeRow: (key: string | number) => void;
3075
+ /** Batch-remove several rows by key (vxe removeRows parity): missing keys are silent no-ops, selection is pruned, one onDataChange fires. */
3076
+ removeRows: (keys: Array<string | number>) => void;
3077
+ /** Patch the row with `key` ({ ...row, ...patch }). */
3078
+ updateRow: (key: string | number, patch: Partial<Row>) => void;
3079
+ /** Re-fetch the current page (proxy mode). */
3080
+ refetch: () => void;
3081
+ /** Replace the live row list (vxe loadData parity, batch V): fires onDataChange; in proxy mode the proxy state total stays unchanged until the next query (the core remote source has no setData — documented). */
3082
+ loadData: (rows: Row[]) => void;
3083
+ /** Re-fetch the current page (vxe reloadData parity, batch V — alias of refetch). */
3084
+ reloadData: () => void;
3085
+ /** Merge params into the proxy query and fire the request (vxe commitProxy parity, batch V). */
3086
+ commitProxy: (overrides: Partial<IrisTableProxyQueryParams>) => void;
3087
+ /** Proxy state snapshot (vxe getProxyInfo parity, batch V): page/pageSize/total; null without a proxy. */
3088
+ getProxyInfo: () => {
3089
+ page: number;
3090
+ pageSize: number;
3091
+ total: number;
3092
+ } | null;
3093
+ /** Snapshot (copy) of the current live row list (vxe getTableData parity). */
3094
+ getData: () => Row[];
3095
+ /** Snapshot (copy) of the currently filtered + sorted rows (vxe getFilteredData parity, batch W): the filteredData memo value — the loaded page after local filters/sort (proxy mode: page after the prop `filters` merge), remoteFilter passes rows through unchanged. The handle object is re-created every render, so this always closes over the latest memo. */
3096
+ getFilteredData: () => Row[];
3097
+ /** Serialize the CURRENT filtered view as CSV (batch W): `exportCsv(getFilteredData(), displayColumns)` — hidden columns excluded (displayColumns drops columnVisibility/visibleMethod hides), formula injection neutralized; returns a plain string without BOM (caller downloads via `downloadCsv`). */
3098
+ exportCurrentViewCsv: () => string;
3099
+ /** Serialize the SELECTED rows as CSV (batch AP, iris 独有): selected rows
3100
+ * in bodyData order (filtered + sorted + tree-flattened) → the same
3101
+ * `exportCsv` shape as `exportCurrentViewCsv` (formula columns materialized
3102
+ * on shadow rows, hidden columns excluded); empty selection → `''` (caller
3103
+ * detects via `getSelection()`). */
3104
+ exportSelectionCsv: () => string;
3105
+ /** Serialize rows whose keys are explicitly supplied, preserving current
3106
+ * body/view order and the same formula/mask/hidden-column pipeline. */
3107
+ exportRowsCsv: (keys: Array<string | number>) => string;
3108
+ /** Multi-segment CSV export (batch DI, iris 独有): ONE file — the current
3109
+ * table block (`# current` + `exportCurrentViewCsv()` byte-for-byte) followed
3110
+ * by one `# <key>` + ref block per `exportNames` entry IN ORDER; segments
3111
+ * joined by a blank line (`\n\n`), no trailing newline. Each ref block is
3112
+ * serialized by its OWN keys (first row's keys as header) — NOT this table's
3113
+ * columns; empty ref rows → just the segment header; a `''` key skips that
3114
+ * segment (even its header). Empty/absent `exportNames` → the bare
3115
+ * current-table CSV (byte-identical to `exportCurrentViewCsv()`, zero
3116
+ * regression). Caller downloads via `downloadCsv`. */
3117
+ exportMultiCsv: () => string;
3118
+ /** Current selection keys (vxe getCheckboxRecords parity). */
3119
+ getSelection: () => Array<string | number>;
3120
+ /** Clear every selected row (vxe clearCheckboxRow parity). */
3121
+ clearSelection: () => void;
3122
+ /** Select every checkMethod-eligible row of the current page (vxe
3123
+ * setAllCheckboxRow(true) parity — `checkMethod` rows are skipped). */
3124
+ selectAll: () => void;
3125
+ /** Toggle a single row's selection by key (vxe toggleCheckboxRow parity —
3126
+ * a direct toggle that bypasses `checkMethod`). */
3127
+ toggleRowSelection: (key: string | number) => void;
3128
+ /** Scroll the row with `key` into view (vxe scrollToRow parity); no-op when the row is not rendered. */
3129
+ scrollToRow: (key: string | number) => void;
3130
+ /** Scroll the row with `key` into view AND flash a transient row highlight (`data-iris-row-target`, cleared after 2s — batch CZ, iris 独有: vxe has no locate flash); a later goToRow replaces the previous target; unknown/unrendered key → no-op (scrollToRow precedent); fires no events and needs no `onCurrentRowChange`. */
3131
+ goToRow: (key: string | number) => void;
3132
+ /** Toggle a row's expand state (vxe toggleRowExpand parity): tree mode toggles the caret, detail mode the panel; no-op for plain tables. */
3133
+ toggleRowExpand: (key: string | number) => void;
3134
+ /** Clear the active sort (vxe clearSort parity) — single and multi channels. */
3135
+ clearSort: () => void;
3136
+ /** Clear every filter channel (vxe clearFilter parity): text filters + checked sets. */
3137
+ clearFilter: () => void;
3138
+ /** Set the current (highlighted) row (vxe setCurrentRow parity); no-op without onCurrentRowChange (or an unknown key). */
3139
+ setCurrentRow: (key: string | number) => void;
3140
+ /** Set the current (highlighted) column (vxe setCurrentColumn parity); no-op without onCurrentColumnChange (or an unknown key). */
3141
+ setCurrentColumn: (key: string) => void;
3142
+ /** Audit trail snapshot (batch AT, iris 独有): newest-first entries (seq/at/type/rowKey/column/old→new) — an empty array when `auditLog` is off or nothing was committed yet. */
3143
+ getAuditLog: () => ReadonlyArray<IrisTableAuditEntry>;
3144
+ /** Wipe every audit entry (batch AT, iris 独有): the seq counter never resets — audit integrity. No-op without `auditLog`. */
3145
+ clearAuditLog: () => void;
3146
+ /** Version-history snapshot (batch BA, iris 独有): newest-first LIGHTWEIGHT entries (index/at/type — deliberately WITHOUT rows, so the snapshot stays cheap; `restoreVersion` fetches the rows from the controller) — an empty array when `versionHistory` is off or nothing was committed yet. */
3147
+ getVersions: () => ReadonlyArray<IrisTableVersionEntry>;
3148
+ /** Restore the rows captured before the commit with `index` (batch BA, iris 独有): applies them through the normal write-back channel (`commitRowList`, type `'undo'` — auditable and undoable) WITHOUT pushing a new version; no-op for an unknown index (trimmed/cleared) or without `versionHistory`. */
3149
+ restoreVersion: (index: number) => void;
3150
+ /** Export the rows captured BEFORE the commit with `index` as CSV (batch BF, iris 独有): the same `exportCsv` shape as `exportCurrentViewCsv` (formula columns materialized on shadow rows, masks applied, hidden columns excluded) — the PRE-change snapshot, NOT the live view; an unknown index (trimmed/cleared) or no `versionHistory` → `''` (caller detects via `getVersions()`). */
3151
+ exportVersionCsv: (index: number) => string;
3152
+ /** Export the compare-view DIFF rows as CSV (batch BV, iris 独有): current-view rows marked `removed`/`changed` in VIEW order + `compareWith`-only `added` rows in SNAPSHOT order, each prefixed with a marker column (`__iris_diff`, header = i18n `table.compare.diff`); changed cells export a `maskedOld → maskedNew` composite (mask before composition; `exportRaw` keeps both sides bare; formula columns do not self-composite) — same serializer shape as `exportCurrentViewCsv` (formula materialized, masks applied, hidden columns excluded); no `compareWith`/`rowKey` → `''`, identical snapshots → header only. */
3153
+ exportComparisonCsv: () => string;
3154
+ /** Export the audit trail as CSV (batch CO, iris 独有): spec-literal 6 columns `time,type,rowKey,column,old,new` — `time` = `formatClock(new Date(at))` (HH:MM:SS local — byte-identical to the audit panel's time cell, display/export consistency), the rest verbatim (undefined → '', typed numbers bare, strings RFC-4180-quoted + OWASP formula-neutralized via core `toCsv` — audit content is untrusted data); newest-first (ring order — the same view as `getAuditLog`); `auditLog` off → `''`, on but empty ring → header only (two states, caller distinguishes via `getAuditLog()`). */
3155
+ exportTimelineCsv: () => string;
3156
+ /** Export the annotated cells as CSV (batch DU, iris 独有 — vxe has no note
3157
+ * concept, so no export parity): spec-literal 3 columns
3158
+ * `rowKey,column,annotation`, one line per noted body cell in bodyData
3159
+ * order; notes resolve through the SAME cellNoteState path as the cell
3160
+ * render (dynamic `cellNote` wins over the static `annotations` map),
3161
+ * hidden columns excluded via the view-columns list; values flow through
3162
+ * core `toCsv` (RFC-4180 quoting + OWASP formula neutralization —
3163
+ * annotation text is untrusted data). Fail-closed: `exportAnnotations`
3164
+ * off → `''`; on but no notes on the current body → `''` (spec-literal
3165
+ * 无批注返回空 — the two states are indistinguishable, mirroring
3166
+ * `exportSelectionCsv`). */
3167
+ exportAnnotationsCsv: () => string;
3168
+ /** Export the CURRENT view state as JSON (batch BZ, iris 独有): all 9 spec
3169
+ * blocks — sort / filters / filterValues / columnVisibility / columnOrder /
3170
+ * columnWidths / pageSize / expandedKeys / query — captured by the SAME
3171
+ * collector as `persistState` (multiSortState deliberately excluded — not
3172
+ * in the spec; `importStateJson` accepts supersets). A piece appears only
3173
+ * when restorable (owning callback present; `pageSize` only with a proxy;
3174
+ * `expandedKeys` only when expandable AND restorable; `query` only when
3175
+ * set) — a bare table exports `'{}'`. Round-trips byte-identically through
3176
+ * `importStateJson`. */
3177
+ exportStateJson: () => string;
3178
+ /** Apply a previously exported state JSON (batch BZ, iris 独有): parses and
3179
+ * replays every present piece through the owning change callbacks (the same
3180
+ * per-piece gating as a view apply — `query` restores FIRST via
3181
+ * `onQueryChange`, `pageSize` reproduces `onPageChange(1, size)` + exactly
3182
+ * one request, `expandedKeys` replaces the whole set via the expansion
3183
+ * model). Invalid JSON or a non-object value → `false` with NOTHING applied;
3184
+ * valid JSON applies piece-by-piece lazily and returns `true` (ineligible
3185
+ * pieces — missing callback / wrong type — are skipped). */
3186
+ importStateJson: (json: string) => boolean;
3187
+ /** Compare two exported-state JSONs (batch DE, iris 独有): field-level diff text (`+` added / `-` removed / `~ changed old → new`), deterministic by sorted keys + structural deep-equal (order-independent); identical → `''`; invalid JSON → `! compareStates: invalid JSON` (never throws). Pairs with `exportStateJson`/`importStateJson` — `a` = before, `b` = after. */
3188
+ compareStates: (a: string, b: string) => string;
3189
+ /** Column access stats (batch EB, iris 独有 — vxe has no counter): a
3190
+ * snapshot of the per-column session counters — `{ key, clicks, edits,
3191
+ * total }` sorted total DESC, key ASC tiebreak; `[]` when `columnStats` is
3192
+ * off or nothing was counted yet (fail-closed). Session-local (no
3193
+ * persistence, no clear channel); the handle re-created every render
3194
+ * closes over the latest ref-mirrored map (getFilteredData precedent). */
3195
+ getColumnStats: () => ReadonlyArray<IrisTableColumnStat>;
3196
+ }
3197
+ /**
3198
+ * Audit-trail entry shape (batch AT, iris 独有) — mirrors the core
3199
+ * `AuditLogEntry` contract (the handle returns a snapshot of the controller
3200
+ * ring). Row-level structural changes (insert/remove) carry only `rowKey`.
3201
+ */
3202
+ interface IrisTableAuditEntry {
3203
+ /** Monotonic sequence number (never resets on clear — audit integrity). */
3204
+ seq: number;
3205
+ /** Epoch ms when the entry was pushed. */
3206
+ at: number;
3207
+ /** Commit kind: any core {@link AuditLogType} (edit/insert/remove/paste/batch/fill/undo/redo/merge). */
3208
+ type: AuditLogType;
3209
+ /** Key of the first changed row (undefined when none could be resolved). */
3210
+ rowKey?: string | number;
3211
+ /** Column key of the first changed cell (undefined for row-level ops). */
3212
+ column?: string;
3213
+ /** Value before the change. */
3214
+ oldValue?: unknown;
3215
+ /** Value after the change. */
3216
+ newValue?: unknown;
3217
+ }
3218
+ /**
3219
+ * Version-history entry shape (batch BA, iris 独有) — a LIGHTWEIGHT mirror of
3220
+ * the core `VersionHistoryEntry` WITHOUT the rows (the handle snapshot stays
3221
+ * cheap; `restoreVersion(index)` fetches the rows from the controller).
3222
+ */
3223
+ interface IrisTableVersionEntry {
3224
+ /** Monotonic version index (never resets on clear). */
3225
+ index: number;
3226
+ /** Epoch ms when the version was pushed. */
3227
+ at: number;
3228
+ /** Commit-kind hint: any core {@link AuditLogType} (edit/insert/remove/paste/batch/fill/undo/redo/merge). */
3229
+ type: AuditLogType;
3230
+ }
3231
+ /**
3232
+ * Collaborative-presence cursor entry (batch BD, iris 独有 — vxe has no
3233
+ * cursor sharing): one remote participant's cursor on a selected cell. Pure
3234
+ * display — the table renders the entry verbatim and owns no collaboration
3235
+ * state or logic. `cellKey` uses the canonical `${rowKeyVal}::${colKey}`
3236
+ * delimiter (the same as `cellId` and the `annotations` map keys).
3237
+ */
3238
+ interface IrisTablePresenceEntry {
3239
+ /** Stable participant id (also surfaced as `data-iris-presence-id`). */
3240
+ id: string;
3241
+ /** Participant display name — the text of the cell's corner label. */
3242
+ name: string;
3243
+ /** Cursor color, used verbatim: the cell outline + the label background. */
3244
+ color: string;
3245
+ /** Target cell: `${rowKeyVal}::${colKey}` (same delimiter as `cellId`). */
3246
+ cellKey: string;
3247
+ }
2597
3248
  /**
2598
- * vxe-grid proxyConfig parity the server-side data proxy (query slice).
2599
- * When set, `data` is ignored: rows come from `query` (paged), and the table
2600
- * renders a pager below the body. Edit write-back keeps working — committed
2601
- * edits update the live rows locally until the next refetch replaces them.
3249
+ * Column access-stats entry (batch EB, iris 独有 vxe has no counter): one
3250
+ * leaf column's session counters. DELIBERATELY session-local (no core
3251
+ * controller, no persistence, no clear channel) the parent reads the
3252
+ * snapshot and owns any downstream use. `total = clicks + edits` is the sort
3253
+ * key (descending; ties resolve key ASC for a deterministic order).
2602
3254
  */
2603
- interface IrisTableProxyConfig<Row extends Record<string, unknown>> {
3255
+ interface IrisTableColumnStat {
3256
+ /** Leaf column key (the same key as the column def / `data-iris-table-header`). */
3257
+ key: string;
3258
+ /** Cell clicks on this column — every cell click counts ONCE (row-edit, cell-range and click-trigger paths included). */
3259
+ clicks: number;
3260
+ /** Inline-edit opens on this column — cell-mode `beginEdit` plus each row-mode session created. */
3261
+ edits: number;
3262
+ /** `clicks + edits` — the handle/panel sort key. */
3263
+ total: number;
3264
+ }
3265
+
3266
+ interface IrisTableAdvancedProps<Row extends Record<string, unknown> = Record<string, unknown>> {
3267
+ nlSummary?: boolean;
2604
3268
  /**
2605
- * Fetch one page. 1-based `page`; `sort`/`filters` are the ACTIVE state,
2606
- * passed through when `remoteSort`/`remoteFilter` are enabled.
3269
+ * Mini chart preview (batch AR, iris 独有): when true, the toolbar gains a
3270
+ * chart trigger (`data-iris-chart-trigger`) opening a floating panel
3271
+ * (`data-iris-chart-panel`) that charts the CURRENT filtered rows: a
3272
+ * numeric-column select (columns where `typeof getCellValue(row, col) ===
3273
+ * 'number'` for some row, or `col.summary === 'sum'`) plus a bar/line kind
3274
+ * toggle. The SVG (viewBox 0 0 300 120) is built from the core
3275
+ * `buildChartData` material over the first 20 values (a muted "共 N 行"
3276
+ * note when truncated) — structured JSX only, no SVG strings. Token colors
3277
+ * only; Esc / outside / scroll close it. Requires a toolbar render (the
3278
+ * gate admits `chartPreview` like `undo`).
3279
+ */
3280
+ chartPreview?: boolean;
3281
+ /**
3282
+ * Auto-refresh (batch AS, iris 独有 — vxe has no interval refresh): when
3283
+ * set, the table re-queries the proxy every `intervalMs` ms while in proxy
3284
+ * mode (non-proxy `data` tables are inert — there is nothing to refetch).
3285
+ * Each tick calls the SAME refetch the built-in ↻ button uses — the
3286
+ * standard refetch path, so `loading` flips true for the duration of the
3287
+ * request (the core source has no silent-refresh option; documented
3288
+ * behavior, not suppressed). `intervalMs` ≤ 0 disables the timer
3289
+ * (fail-closed). The interval restarts whenever `intervalMs` changes
3290
+ * (keyed on the scalar, so an inline object doesn't reset the timer every
3291
+ * render) and is cleared on unmount / proxy removal. Additive — default
3292
+ * off.
3293
+ */
3294
+ autoRefresh?: {
3295
+ intervalMs: number;
3296
+ };
3297
+ /**
3298
+ * Freshness stamp (batch AS, iris 独有 — vxe shows no data-arrival time):
3299
+ * when true, the toolbar renders `Updated at HH:MM:SS`
3300
+ * (`data-iris-freshness`, i18n `table.freshness`, 24h local `formatClock`)
3301
+ * re-stamped on EVERY live-data change — initial arrival, refetch, edit
3302
+ * commit, row ops / paste / batch / range clear, undo/redo (everything
3303
+ * that funnels through `setLiveData`). Hidden until the first row exists
3304
+ * (`liveData.length === 0`). Requires a toolbar render. Additive — default
3305
+ * off.
3306
+ */
3307
+ freshness?: boolean;
3308
+ /**
3309
+ * Validation summary (batch BR, iris 独有 — vxe shows no editRules outcome
3310
+ * counts): when true, the toolbar renders a muted commit-outcome ledger
3311
+ * (`data-iris-validation-summary`, i18n `table.validationSummary`, en
3312
+ * `Passed {ok} · Failed {fail}` / zh `通过 {ok} · 失败 {fail}`) for columns
3313
+ * with declarative `editRules`: ok = a commit that passed editRules and
3314
+ * landed (cell and row edit modes), fail = a commit attempt rejected by
3315
+ * editRules. Typing-time validation, legacy `validate` columns, paste/fill/
3316
+ * FNR/batch bypasses and Escape cancels never count. Hidden until at least
3317
+ * one outcome is counted; re-enabling the switch resets the ledger.
3318
+ * Requires a toolbar render (the gate admits `validationSummary` like
3319
+ * `freshness`). Additive — default off.
3320
+ */
3321
+ validationSummary?: boolean;
3322
+ /**
3323
+ * Audit log (batch AT, iris 独有 — vxe has no audit trail): when true, every
3324
+ * mutation commit appends ONE entry to a bounded (200) ring — inline/row
3325
+ * edits, insert/remove row ops, paste, fill, batch edit, undo/redo replay
3326
+ * (type hint per site; rowKey + first-changed-cell context from a light
3327
+ * diff of the row lists, documented simplification). The toolbar gains an
3328
+ * audit trigger (`data-iris-audit-trigger`) opening a floating panel
3329
+ * (`data-iris-audit-panel`, like the chart/stats panels — Esc / outside /
3330
+ * scroll close) listing newest-first entries (seq + `formatClock` time +
3331
+ * type + rowKey + column + muted old→new). `tableRef.getAuditLog()` /
3332
+ * `clearAuditLog()` expose the trail programmatically (the seq never
3333
+ * resets on clear — audit integrity). Requires a toolbar render (the gate
3334
+ * admits `auditLog` like `undo`). Additive — default off.
3335
+ */
3336
+ auditLog?: boolean;
3337
+ /**
3338
+ * Performance panel (batch BL, iris 独有 — vxe has no perf stats): when
3339
+ * true, every render commit samples `nowMs()` (render-top mark →
3340
+ * dependency-less `useLayoutEffect` run) into a core `createPerfStats`
3341
+ * latest-snapshot controller (`@iris-ui-kit/core/perf-stats` — own
3342
+ * subpath). Duration = render + layout phase, excludes paint
3343
+ * (documented). The toolbar gains a ⚡ trigger (`data-iris-perf-trigger`)
3344
+ * opening a floating panel (`data-iris-perf-panel`, like the audit panel
3345
+ * — Esc / outside / scroll close) showing the last render duration,
3346
+ * row count, leaf-column count and the audit-trail depth — live: the
3347
+ * panel subscribes to BOTH controllers, so `tableRef.clearAuditLog()`
3348
+ * refreshes the changes count in place; `auditLog` off → muted `—`. The
3349
+ * push notifies only the panel (separate portal root) — the table never
3350
+ * re-renders from its own measurement. Requires a toolbar render (the
3351
+ * gate admits `perfStats` like `auditLog`). Off = zero cost. Additive —
3352
+ * default off.
3353
+ */
3354
+ perfStats?: boolean;
3355
+ /**
3356
+ * Version history (batch BA, iris 独有 — vxe has no time-travel): when set,
3357
+ * every row-list commit (`commitRowList` — row ops, paste, fill, range
3358
+ * clear, batch edit, undo/redo replay) pushes the PRE-change rows into a
3359
+ * bounded ring (core `createVersionHistory`, default max 20; `max: 0`
3360
+ * unlimited; `max` read once at mount). The toolbar gains a history trigger
3361
+ * (`data-iris-history-trigger`) opening a floating panel
3362
+ * (`data-iris-history-panel`, like the audit panel — Esc / outside / scroll
3363
+ * close) listing versions newest-first (#index + `formatClock` time + commit
3364
+ * type); clicking an entry restores those rows through the normal write-back
3365
+ * channel (`commitRowList(rows, 'undo')` — auditable and undoable) WITHOUT
3366
+ * pushing a new version. Inline cell/row edits (the `commitValue` funnel)
3367
+ * don't create versions (documented — restore replaces the whole row list,
3368
+ * so row-level commits are the coherent unit). `tableRef.getVersions()`
3369
+ * (lightweight — no rows) / `restoreVersion(index)` expose the ring
3370
+ * programmatically. Requires a toolbar render (the gate admits
3371
+ * `versionHistory` like `undo`). Additive — default off.
3372
+ */
3373
+ versionHistory?: {
3374
+ max?: number;
3375
+ };
3376
+ /**
3377
+ * Compare view (batch AU, iris 独有 — vxe has no compare capability): a
3378
+ * snapshot the live rows are diffed against by `rowKey`. Every live row
3379
+ * absent from the snapshot renders `data-iris-row-removed`, every live row
3380
+ * present in both with ≥1 differing cell renders `data-iris-row-changed`
3381
+ * with `data-iris-cell-changed` on the changed cells and a title tooltip
3382
+ * `旧值: X → 新值: Y` (old = live value, new = snapshot value) that
3383
+ * overrides the tooltipConfig title (compare wins, documented); snapshot-
3384
+ * only rows are `added` in the core diff but have no rendered slot — the
3385
+ * compare view renders the live dataset (documented). Core `diffRows` is
3386
+ * framework-free; the memo is null without `compareWith` or `rowKey` —
3387
+ * additive, default off.
3388
+ */
3389
+ compareWith?: Row[];
3390
+ /**
3391
+ * One-click compare merge (batch ED, iris 独有 — vxe has no compare/merge
3392
+ * capability): when true (with `compareWith` + `rowKey`, and a toolbar
3393
+ * render — the gate admits `mergeCompare` like `undo`), the toolbar gains
3394
+ * a text-label button (`data-iris-table-compare-merge`, i18n
3395
+ * `table.mergeCompare`, en `Merge compare` / zh `合并差异`) that applies
3396
+ * EVERY added/changed difference to the CURRENT data — changed rows get
3397
+ * their differing cells replaced in place by the snapshot values (shallow
3398
+ * copy of the live row — a live-only key absent from the snapshot is reset
3399
+ * to `undefined`, so the merged row matches the snapshot exactly and a
3400
+ * second click is a no-op), added rows are
3401
+ * appended in snapshot order (shallow copy — snapshot elements are never
3402
+ * aliased into liveData) — through the normal write-back channel
3403
+ * `commitRowList(rows, 'merge')`, so the merge is audited (a single
3404
+ * `merge` entry), undoable and versioned like any row-list commit.
3405
+ * `removed` rows are untouched (spec: changed/added only). Disabled while
3406
+ * there is nothing to apply (identical snapshot / removed-only diff); the
3407
+ * handler early-returns the same way (double-safety, idempotent).
3408
+ * Additive — default off.
3409
+ */
3410
+ mergeCompare?: boolean;
3411
+ /**
3412
+ * Cell auto-link (batch CA, iris 独有 — vxe has no URL/email auto-
3413
+ * detection): when true, text cells run their display chain
3414
+ * (mask → formatter ?? raw) through core `detectAutoLink`; a whole-text
3415
+ * URL/email match renders an `<a data-iris-auto-link>` (_blank +
3416
+ * noreferrer) instead of plain text. Non-matching text falls through to
3417
+ * the formatter/raw branch unchanged; an explicit `col.link` column still
3418
+ * wins (evaluated before autoLink). Additive — default off.
3419
+ */
3420
+ autoLink?: boolean;
3421
+ /**
3422
+ * Recent filters (batch CB, iris 独有 — vxe has no "recent filters"
3423
+ * concept): when true, every filter-panel confirm (non-empty checked
3424
+ * set) records `{ key, values, ts }` into a core `createRecentFilters`
3425
+ * ring (newest-first, 10 entries, MRU — re-confirming the same set
3426
+ * bumps it to the top). The filter panel shows the recent entries
3427
+ * above the options; clicking one applies it immediately (across
3428
+ * columns) and closes. Additive — default off.
3429
+ */
3430
+ recentFilters?: boolean;
3431
+ /**
3432
+ * Edit-history sidebar (batch DB, iris 独有 — vxe has no edit history): a
3433
+ * right-side drawer panel (portal, `position: fixed`, 360px, NO backdrop —
3434
+ * non-modal) opened from the toolbar trigger (`data-iris-edit-sidebar-trigger`,
3435
+ * ⏳ right after the version-history trigger). It merges the batch-AT audit
3436
+ * ring and the batch-BA version ring into ONE timeline view, newest-first
3437
+ * (`at` desc; a same-ms tie lists the audit entry ABOVE its version — the
3438
+ * deterministic record-order arbitration). Version entries are clickable:
3439
+ * pressing one restores those rows through the normal write-back channel
3440
+ * (`commitRowList(rows, 'undo')` — auditable and undoable) WITHOUT pushing a
3441
+ * new version, exactly like the version-history panel, and closes. Audit
3442
+ * entries render seq + `formatClock` time + type + rowKey + column + muted
3443
+ * old→new. Fail-closed matrix: a recording layer whose prop is OFF
3444
+ * contributes NOTHING — the record layers are never implicitly enabled, so
3445
+ * with only `versionHistory` the panel lists versions alone, with only
3446
+ * `auditLog` audit entries alone, and with neither the empty state. The
3447
+ * panel subscribes to BOTH controllers (`useSyncExternalStore` each) so a
3448
+ * commit while it is open refreshes the timeline in place. Closes on Esc /
3449
+ * outside pointer-down / any scroll; the trigger is exempt (a press on it
3450
+ * toggles instead of close-then-reopen). Requires a toolbar render (the
3451
+ * gate admits `editSidebar` like `versionHistory`). Additive — default off.
3452
+ */
3453
+ editSidebar?: boolean;
3454
+ /**
3455
+ * Imperative handle (vxe-grid edit insert/remove/setRow parity + iris-only
3456
+ * additions): row ops, proxy/view/selection methods, and (batch BZ) the
3457
+ * full view-state JSON export/import — `exportStateJson()` /
3458
+ * `importStateJson(json)` (sort / filters / filterValues /
3459
+ * columnVisibility / columnOrder / columnWidths / pageSize / expandedKeys /
3460
+ * query — the same collector as `persistState`).
3461
+ */
3462
+ tableRef?: React.MutableRefObject<IrisTableHandle<Row> | null>;
3463
+ /** Fired after any internal row operation / edit write-back, with the new row list. */
3464
+ onDataChange?: (rows: Row[]) => void;
3465
+ /** Veto rows from selection (vxe-grid checkboxConfig.checkMethod parity). */
3466
+ checkMethod?: (row: Row, rowIndex: number) => boolean;
3467
+ /** Pager options (vxe-grid pagerConfig parity). */
3468
+ pagerConfig?: IrisTablePagerConfig;
3469
+ /** Fixed height (vxe-grid height parity, batch N): makes the root a vertical
3470
+ * scroll container with a sticky header row. Number → px; string → CSS length. */
3471
+ height?: number | string;
3472
+ /** Minimum height of the fixed-height container (with `height`/`maxHeight`). */
3473
+ minHeight?: number | string;
3474
+ /** Maximum height of the fixed-height container (with `height`/`minHeight`). */
3475
+ maxHeight?: number | string;
3476
+ /** Thin scrollbars (vxe-grid scrollbarConfig parity, batch Q): when
3477
+ * `theme: 'thin'`, the root and its virtual-scroll descendant get 6px
3478
+ * webkit scrollbars plus Firefox `scrollbar-width: thin` via
3479
+ * `data-iris-scrollbar-thin`. Default: browser scrollbars. */
3480
+ scrollbarConfig?: {
3481
+ theme?: 'default' | 'thin';
3482
+ };
3483
+ /** Batch DP (iris 独有): add token-driven custom thumb styling to the native
3484
+ * scrollbar while retaining native scrolling and accessibility. */
3485
+ scrollbarThumb?: boolean;
3486
+ /**
3487
+ * Back-to-top (batch EA, iris 独有 — vxe has no floating back-to-top): when
3488
+ * true, a 40×40 round ↑ button floats at the scroll viewport's bottom-right
3489
+ * once the table's effective scroller scrolls past 200px (the fixed-height
3490
+ * root, vxe-grid `height` parity, or the virtual-scroll viewport — the
3491
+ * viewport wins when both exist, the same resolution the paging keys use).
3492
+ * Clicking it scrolls back to the top (`scrollTo({ top: 0, behavior })` with
3493
+ * a `scrollTop = 0` fallback; reduced-motion users get `'auto'`). The
3494
+ * anchor is a sticky zero-height endcap (absolute-in-anchor corner button,
3495
+ * z 3 above the sticky header / pinned columns) — zero layout footprint,
3496
+ * no dead scroll tail — and the button disappears once the scroller returns
3497
+ * above the threshold. Non-scrollable tables never show it (fail-closed);
3498
+ * printable tables suppress it. Additive — default off.
3499
+ */
3500
+ scrollToTop?: boolean;
3501
+ /** Batch DN (iris 独有): show count/average statistics for numeric columns
3502
+ * inside their leaf headers, separate from footer/column totals. */
3503
+ headerStats?: boolean;
3504
+ /** Dirty-cell tracking (vxe-grid editDirtyConfig parity, batch Q): a cell
3505
+ * whose committed value differs from its pre-edit original renders a
3506
+ * primary dot (`data-iris-cell-dirty`, cell gets `position: relative`);
3507
+ * committing the original value clears it. `indicator: false` suppresses
3508
+ * the dot (tracking stays); `className: true` also adds an
3509
+ * `iris-table-cell-dirty` class for custom styling. */
3510
+ editDirtyConfig?: {
3511
+ indicator?: boolean;
3512
+ className?: boolean;
3513
+ };
3514
+ /** Fill the parent (vxe-grid auto-resize parity, batch Q): a
3515
+ * ResizeObserver measures the root and, when no explicit `height` is set,
3516
+ * renders `height: 100%` so the table fills AND tracks its parent (the
3517
+ * fixed-height scroll machinery engages after the first positive
3518
+ * measure). When `height` IS set the measured size is kept internally and
3519
+ * the explicit height wins (no visible change). Without ResizeObserver
3520
+ * (jsdom/SSR) the scroll engagement is a no-op. Default false. */
3521
+ autoResize?: boolean;
3522
+ /**
3523
+ * Re-measure on content changes (vxe-grid syncResize parity, batch R):
3524
+ * when true, `autoResize` is off and NO explicit `height` is set, an
3525
+ * effect keyed on data / loading / error / footerData / size / bordered
3526
+ * runs the SAME root measure autoResize uses (plus on
3527
+ * `visibilitychange`), so the fixed-height machinery tracks
3528
+ * content-driven size changes without a ResizeObserver. Same application
3529
+ * rules as `autoResize`: with `height` set the explicit height wins and
3530
+ * the effect does nothing. Default false. */
3531
+ syncResize?: boolean;
3532
+ /**
3533
+ * Narrow-width responsive mode (iris 独有 — vxe has no responsive column
3534
+ * behavior): a prop-gated ResizeObserver measures the root; when the
3535
+ * container measures below 480px (strictly — 480 exactly is full width),
3536
+ * the lowest-priority top-level columns are greedily hidden until the
3537
+ * natural width fits (pinned columns survive, at least one column stays),
3538
+ * and — only when columns STILL overflow after collapsing — a horizontal
3539
+ * scroll hint bar (`data-iris-scroll-hint`) + root overflowX auto appear
3540
+ * so no data is unreachable. At/above 480px, without ResizeObserver
3541
+ * (jsdom/SSR) or with the prop off, the render is byte-identical. Default
3542
+ * false. */
3543
+ responsive?: boolean;
3544
+ /**
3545
+ * Seed the live row list with a COPY of `data` (vxe-grid keepSource
3546
+ * parity, batch R): `liveData` initializes to `[...data]` instead of the
3547
+ * `data` reference, so mutating the original array after mount cannot
3548
+ * change the table. The table is immutable either way — it never mutates
3549
+ * the rows it receives; `keepSource` just decouples the initial seed.
3550
+ * Later controlled re-feeds (new `data` reference) keep the hand-off. */
3551
+ keepSource?: boolean;
3552
+ /**
3553
+ * Root stacking (vxe-grid zIndex parity, batch R): sets `z-index` on the
3554
+ * root with `position: relative` (CSS z-index is inert on static
3555
+ * elements). Rendered before `style` — a caller-provided style can still
3556
+ * override. */
3557
+ zIndex?: number;
3558
+ /** Highlight rows on hover (vxe highlight-hover-row parity, batch N). Default true. */
3559
+ highlightHoverRow?: boolean;
3560
+ /** Header overflow (vxe showHeaderOverflow parity, batch W): when false, header cells switch to `whiteSpace: 'normal'` + `overflow: 'visible'` (text wraps instead of the ellipsis). Default true. */
3561
+ showHeaderOverflow?: boolean;
3562
+ /** Footer overflow (vxe showFooterOverflow parity, batch W): when false, summary / footerMethod / footerData cells switch to `whiteSpace: 'normal'` + `overflow: 'visible'` (text wraps instead of the ellipsis). Default true. */
3563
+ showFooterOverflow?: boolean;
3564
+ /** Background watermark text (iris 独有 — vxe has no watermark concept): when set, a rotated tiled watermark layer (wrapper `data-iris-watermark` → overlay `data-iris-watermark-overlay` → tiles `data-iris-watermark-tile`, same DOM shape as the standalone IrisWatermark primitive) overlays the table's static rows / footer / pager — below the sticky header, pinned columns and floating panels. The wrapper is a sticky first child of the root (the scroll container), so in fixed-height mode it pins to the scroll viewport and stays put while rows scroll beneath. Pure display: `aria-hidden` + `pointer-events: none` + `user-select: none`, token-driven (`--iris-muted` / `--iris-space-xl` / `--iris-font-size-lg`). Empty string hides the layer. */
3565
+ watermark?: string;
3566
+ style?: React.CSSProperties;
3567
+ className?: string;
3568
+ }
3569
+
3570
+ interface IrisTableEditingProps<Row extends Record<string, unknown> = Record<string, unknown>> {
3571
+ /**
3572
+ * Column drag-sort (vxe-grid columnDragConfig parity). Reorders leaf
3573
+ * columns on drop; parent owns columns (pass the reordered array back).
3574
+ * Batch CH (iris 独有 — vxe has no drag-out pin): when `columnPinMenu` is
3575
+ * ALSO on, dragging a column header past the table's LEFT edge pins it
3576
+ * left on release (drag-out pin) instead of reordering — a second gesture
3577
+ * into the pin menu's state channel (same `onColumnPinnedChange` contract,
3578
+ * both controlled/uncontrolled modes, never a reorder). Plain `columnDrag`
3579
+ * without `columnPinMenu` keeps the vxe reorder-only behavior.
3580
+ * Batch DK (iris 独有): a pinned intra-zone reorder ALSO fires
3581
+ * `onColumnOrderChange` with the new top-level key list (flat leaf tables
3582
+ * only; grouped leaves stay `onReorder`-only) so a header frozen-zone
3583
+ * reorder is durable for controlled parents through the same channel the
3584
+ * settings panel uses.
3585
+ */
3586
+ columnDrag?: {
3587
+ /** Called with the reordered column array after a drop. */
3588
+ onReorder: (columns: IrisTableColumn<Row>[]) => void;
3589
+ };
3590
+ /** Render a leading sequence-number column (vxe-grid seqConfig parity). */
3591
+ seq?: boolean;
3592
+ /**
3593
+ * Excel-style row/column references (batch AO, iris 独有 — vxe seqConfig
3594
+ * shows numbers only, no column letters): muted A/B/C… letter badges
3595
+ * (`data-iris-cell-ref`) after every LEAF header title (A = first leaf;
3596
+ * seq/selection/detail/drag columns are skipped, grouped leaves follow
3597
+ * source order) plus a leading row-number column 1, 2, 3…
3598
+ * (`data-iris-row-ref`). When `seq` is on the seq column IS the row
3599
+ * number — no duplicate column. Additive — default off.
3600
+ */
3601
+ showCellRefs?: boolean;
3602
+ /**
3603
+ * Cell merge (vxe-grid spanMethod parity): return `{ rowspan, colspan }`
3604
+ * for a cell at (rowIndex, columnIndex); both default 1. Values > 1 make
3605
+ * the cell span adjacent cells (the spanned cells are skipped).
3606
+ */
3607
+ spanMethod?: (params: {
3608
+ rowIndex: number;
3609
+ columnIndex: number;
3610
+ }) => {
3611
+ rowspan?: number;
3612
+ colspan?: number;
3613
+ } | null | undefined;
3614
+ /**
3615
+ * Header merge (vxe-grid mergeHeaderCells parity, batch P): merge entries
3616
+ * keyed by leaf-column index of the FLAT header row (`row` 0 only — rows
3617
+ * > 0 are ignored). A merge cell renders with `gridColumnEnd: span
3618
+ * colspan` / `gridRowEnd: span rowspan`; the covered cells render null.
3619
+ * Grouped headers and `columnVirtualization` are not merged (documented
3620
+ * simplification).
3621
+ */
3622
+ mergeHeaderCells?: IrisTableMergeCell[];
3623
+ /**
3624
+ * Footer merge (vxe-grid mergeFooterItems parity, batch R): declarative
3625
+ * span entries in the SAME coordinate space as `footerSpanMethod` — `row`
3626
+ * is the 0-based index over the rendered footer stack (footerMethod rows →
3627
+ * summary row → footerData rows, whichever render) and `col` the
3628
+ * leaf-column index; both start at 0. A merge cell renders `gridColumnEnd:
3629
+ * span colspan`; the covered cells of the same row render null. `rowspan`
3630
+ * is inert (each footer row is its own grid container — covered cells of
3631
+ * later rows keep their own data; mirrors `footerSpanMethod`'s rowspan).
3632
+ * The function wins: when `footerSpanMethod` is provided,
3633
+ * `mergeFooterItems` is ignored. Entries outside the rendered stack are
3634
+ * no-ops.
3635
+ */
3636
+ mergeFooterItems?: IrisTableMergeFooterItem[];
3637
+ /**
3638
+ * Row key fallback (vxe-grid deprecated string `rowId` parity, re-typed as
3639
+ * a function, batch R): when a row lacks the `rowKey` field, this callback
3640
+ * supplies the row's key — used by selection, expansion, dirty tracking,
3641
+ * editing and tree flattening. `rowKey` wins over `rowId`; without either,
3642
+ * the row index is used at index-bearing call sites (unchanged). The
3643
+ * imperative handle's row ops, clipboard paste and find&replace write-backs
3644
+ * still address rows by the `rowKey` field only (keyless rows are skipped
3645
+ * there). */
3646
+ rowId?: (row: Row, rowIndex: number) => string | number;
3647
+ /** Row drag-sort configuration (composed over core createSortable). */
3648
+ rowDrag?: {
3649
+ /** Reorder callback — receives the reordered row array (parent owns data). */
3650
+ onReorder: (rows: Row[]) => void;
3651
+ };
3652
+ /** Batch DQ (iris 独有): drop a dragged row on an external element whose `data-iris-drop-zone` value matches `key`; the parent owns the zone DOM. */
3653
+ rowDragBetween?: IrisTableRowDragBetweenTarget<Row>[];
3654
+ /** Inline-edit configuration (vxe-grid editConfig parity). */
3655
+ editConfig?: {
3656
+ /** What opens the editor. Default `'dblclick'`. */
3657
+ trigger?: 'click' | 'dblclick' | 'manual';
3658
+ /** Show a required asterisk next to headers of columns with rules. */
3659
+ showAsterisk?: boolean;
3660
+ /** Drop the draft when opening another cell without committing. */
3661
+ autoClear?: boolean;
3662
+ /** Edit mode (vxe editConfig.mode parity, batch K): `'cell'` (default) edits one cell at a time; `'row'` opens every editable column of the clicked row together — Enter/blur commits THAT column, Escape cancels the whole row, clicking another row commits the current row's open editors first. */
3663
+ mode?: 'cell' | 'row';
3664
+ };
3665
+ /** Edit-validation presentation (vxe-grid ValidConfig parity). */
3666
+ validConfig?: IrisTableValidConfig;
3667
+ onCellEdit?: (event: IrisTableCellEditEvent<Row>) => void;
3668
+ /** Edit start (vxe edit-activated parity, batch V): fired when an inline editor opens (cell double-click; cell mode only). */
3669
+ onEditStart?: (params: IrisTableEditStartParams<Row>) => void;
3670
+ /** Edit close (vxe edit-closed parity, batch V): fired when an edit session ends — `cancelled: false` carries the committed value, `cancelled: true` when Escape discarded it. Cell mode only (see `TableTypes.IrisTableEditClosedParams`). */
3671
+ onEditClosed?: (params: IrisTableEditClosedParams<Row>) => void;
3672
+ /** Batch BQ (iris 独有): auto-save committed inline edits — after a successful commit, fire `onAutosave` with the post-commit row list (parent persistence hook; orthogonal to `onDataChange`, which inline edits never trigger). `editAutosave` is the feature switch — `onAutosave` alone is inert (keymap precedent). No-op commits (same value), cancelled (Escape) and validation-failed edits never fire; row edit mode fires per committed column. */
3673
+ editAutosave?: boolean;
3674
+ /** Batch BQ (iris 独有): parent persistence hook fired by `editAutosave` with the post-commit row list. */
3675
+ onAutosave?: (rows: Row[]) => void;
3676
+ /** Batch CC (iris 独有): textarea editors auto-grow their height with content — 1 row to start, up to a 6-row cap, then scroll inside the editor (measured via scrollHeight on input, no re-render loop). Off by default (fail-closed; batch I's rows=3 stays). */
3677
+ editAutoHeight?: boolean;
3678
+ /** Batch CG (iris 独有 — vxe has no equivalent; Excel-style status-bar parity):
3679
+ * a live character count in the editing cell's bottom-right corner (cell AND
3680
+ * row edit modes, recomputed per keystroke from the session draft) plus a
3681
+ * cell-count/sum badge at the selected range's bottom-right cell when
3682
+ * `cellRange` has a live selection (a pure reduction over the rangeStats
3683
+ * material — count = Σ column non-null counts, sum = Σ numeric column sums,
3684
+ * `null` = no numeric data — rounded via the same `aggregateAccuracy` gate as
3685
+ * the summary row). Additive; default off (fail-closed).
3686
+ */
3687
+ charCount?: boolean;
3688
+ /** Batch CQ (iris 独有 — vxe has no equivalent): show a live preview of the
3689
+ * formatter-applied result below the editing cell — recomputed per keystroke
3690
+ * from the session draft through the SAME display chain as the committed cell
3691
+ * (mask → formatter, with the commit path's draft coercion for number/select
3692
+ * editors), rendered as a muted small line (`data-iris-edit-preview`). Only
3693
+ * columns with a `formatter` render a preview. Additive; default off
3694
+ * (fail-closed).
3695
+ */
3696
+ editPreview?: boolean;
3697
+ /** Batch DH (iris 独有 — vxe has no equivalent; data-consistency assist):
3698
+ * while an inline (cell-mode) editor is open, every other cell in the SAME
3699
+ * column whose committed value exactly matches the current draft renders a
3700
+ * light highlight (`data-iris-input-hint` + a `--iris-input-hint` token
3701
+ * background) — a glanceable "these rows already share this value" cue
3702
+ * while typing. Matching is RAW (`String(raw) === String(draft)`, same
3703
+ * draft caliber as the editor/commit path — not the masked/formatted
3704
+ * display). The editing cell itself is exempt. An empty draft is
3705
+ * fail-closed (never floods the whole column). Computed live per keystroke
3706
+ * via the existing cell-edit store — zero new state. Row-edit mode is a
3707
+ * documented fiat: each column's draft lives in its own session, so row
3708
+ * mode does not participate. Additive; default off (fail-closed).
3709
+ */
3710
+ pattern?: boolean;
3711
+ /** Batch DL (iris 独有): alias for the pattern-edit consistency hint. While
3712
+ * an inline draft is open, matching committed values in the same column get
3713
+ * `data-iris-input-hint`; kept as a separate switch for the batch contract. */
3714
+ patternFill?: boolean;
3715
+ /** Batch EB (iris 独有 — vxe has no column access stats): count per-column
3716
+ * cell clicks and inline-edit opens (SESSION-local internal counting — no
3717
+ * core controller, no persistence, no clear channel). Every cell click
3718
+ * counts ONCE through exactly one path — row-edit mode counts the clicked
3719
+ * row's columns (a click + one edit per editable column opened), cell-range
3720
+ * clicks count the clicked column, click-trigger edits count as BOTH a
3721
+ * click and an edit; paste/fill, header clicks and keyboard-opened editors
3722
+ * never add clicks. `handle.getColumnStats()` returns the `{ key, clicks,
3723
+ * edits, total }` snapshot (total desc, key asc tiebreak; `[]` when off or
3724
+ * idle) and the toolbar `▦` trigger opens the top-5 panel. The counting
3725
+ * bumps are plain functional setState — the opt-in re-render cost is
3726
+ * documented (off = zero cost, no bumps, no re-renders). Additive; default
3727
+ * off (fail-closed). */
3728
+ columnStats?: boolean;
3729
+ /** Batch CR (iris 独有 — vxe has no equivalent; Excel status-bar parity):
3730
+ * show a full-width horizontal strip directly below the toolbar
3731
+ * (`data-iris-column-totals`) with the column totals for every
3732
+ * `summary === 'sum'` column — aggregated over the CURRENT body rows with
3733
+ * the exact summary-row value pipeline (`aggregate` + the
3734
+ * `aggregateAccuracy` rounding gate + `renderSummary` fallback), one grid
3735
+ * cell per leaf column (`data-iris-column-totals-cell`) so tracks stay
3736
+ * aligned; non-sum columns render empty placeholders. The strip shows even
3737
+ * with an empty body (`0`). Additive; default off (fail-closed).
3738
+ */
3739
+ columnTotals?: boolean;
3740
+ /** Batch CS (iris 独有 — vxe has no equivalent; vxe keeps the pixel offset, never re-anchors).
3741
+ * In virtual mode, an expansion commit re-locates the first visible row
3742
+ * (the content anchor, with its partial offset) in the NEW plan and
3743
+ * writes `newIndex × slotHeight + relativeTop` — the rows under the
3744
+ * cursor stay put across tree/detail expand AND collapse. Uniform slot
3745
+ * heights only (`rowHeight`/`virtualScroll.itemHeight` functions are
3746
+ * pixel-only — the variable-height offset tree is child-internal);
3747
+ * non-virtual tables are inert (documented fiat); full-set restores
3748
+ * (`expandAll` / `persistState` replay) fall back to the virtualizer's
3749
+ * re-clamp; a single-key commit stays exact. Additive; default off
3750
+ * (fail-closed).
3751
+ */
3752
+ expandScrollPreserve?: boolean;
3753
+ /** Batch CJ (iris 独有 — vxe has no shortcut help): show a `?` toolbar
3754
+ * trigger that opens a floating panel listing every built-in keyboard
3755
+ * shortcut with its EFFECTIVE key — the same normalized map every handler
3756
+ * matches against, so `keymap` remaps reflect live and a listed key always
3757
+ * actually works. Read-only reference (no rebind UI). Additive; default
3758
+ * off (fail-closed).
3759
+ */
3760
+ shortcutHints?: boolean;
3761
+ /** Header select-all toggle (additive — not in vxe's emits, batch V): fired with the PRE-toggle header state and the current selection keys. */
3762
+ onSelectAllChange?: (state: boolean | 'indeterminate', selection: Array<string | number>) => void;
3763
+ /** Root scroll (vxe scroll parity, batch V): `{ scrollTop, scrollLeft }` of the root container; fires in column-virtualization mode and via a native listener otherwise (only meaningful with `height`, else overflow is hidden). */
3764
+ onScroll?: (params: IrisTableScrollParams) => void;
3765
+ /** Render an expandable detail panel beneath a row. */
3766
+ renderDetail?: IrisTableRenderDetail<Row>;
3767
+ /** Which rows can expand a detail panel. */
3768
+ rowExpandable?: IrisTableRowExpandable<Row>;
3769
+ /** Initially-expanded row keys (uncontrolled). Shared by detail rows + tree rows. */
3770
+ defaultExpandedRowKeys?: Array<string | number>;
3771
+ /** Expand every tree row that has children on mount (vxe expand-config
3772
+ * expandAll parity). One-shot: seeds the expansion model with all tree keys
3773
+ * on the first data arrival (proxy pages load async). Default false. */
3774
+ expandAll?: boolean;
3775
+ /** Notified with the expanded row keys whenever they change (batch BY: also the restore channel for `persistState`'s `expandedKeys` piece — the model commit replays this callback). */
3776
+ onExpandedRowsChange?: (keys: Array<string | number>) => void;
3777
+ /** Detail expand toggle (vxe toggle-row-expand parity): `expanded` is the NEW state after the toggle. */
3778
+ onExpandChange?: (row: Row, expanded: boolean) => void;
3779
+ /** Tree expand toggle (vxe toggle-tree-expand parity): `expanded` is the NEW state after the toggle. */
3780
+ onTreeExpandChange?: (row: Row, expanded: boolean) => void;
3781
+ /** Read a row's child rows to render the table as a tree. */
3782
+ getSubRows?: (row: Row) => Row[] | undefined;
3783
+ /** Lazy tree (vxe lazyLoad parity): a row with no `getSubRows` children still renders a caret; the first expand calls this and `load` resolves the children (expanding the row). */
3784
+ lazyLoad?: (row: Row, load: (children: Row[]) => void) => void;
3785
+ /** Batch CL (iris 独有 — vxe has no expand animation):
3786
+ * animate detail-panel and tree-row expansion with a max-height + opacity
3787
+ * enter transition (token-driven — `--iris-table-expand-max` cap and
3788
+ * `--iris-duration-md` duration, both with fallbacks;
3789
+ * `prefers-reduced-motion: reduce` turns the animation off entirely).
3790
+ * Pure CSS entrance — zero state/effect; root tree rows (depth 0) stay
3791
+ * static. Inert in virtual mode (lazy slots would replay the animation on
3792
+ * scroll-mount). Additive; default off (fail-closed).
3793
+ */
3794
+ expandAnimation?: boolean;
3795
+ /**
3796
+ * Enable WAI-ARIA grid keyboard navigation (single-tabstop roving cell
3797
+ * focus). Arrow keys move one cell; Home/End jump to the row's first/last
3798
+ * cell; PageUp/PageDown jump 10 rows (clamped; virtual tables also scroll
3799
+ * the viewport ±10 × row height); Tab/Shift+Tab move row-major to the
3800
+ * next/prev cell (clamped at the bounds — no wrap, focus never leaves the
3801
+ * table); Enter is an alias of ArrowDown (F2 stays the edit-start key).
3802
+ * While an inline editor is open the editor's own keys win — Tab commits
3803
+ * and moves to the next editable column (batch J), unchanged.
2607
3804
  */
2608
- query: (params: IrisTableProxyQueryParams) => Promise<{
2609
- rows: Row[];
2610
- total: number;
2611
- }>;
2612
- /** Auto-load the first page on mount (vxe autoLoad parity). Default true. */
2613
- autoLoad?: boolean;
2614
- /** Sort changes re-query the server instead of sorting client-side (vxe proxyConfig.sort). Default false. */
2615
- remoteSort?: boolean;
2616
- /** Filter changes re-query the server instead of filtering client-side (vxe proxyConfig.filter). Default false. */
2617
- remoteFilter?: boolean;
2618
- /** Rows per page. Default 10. */
2619
- pageSize?: number;
2620
- /** Initial page (1-based). Default 1. */
2621
- defaultPage?: number;
2622
- /** Fired when the page changes. */
2623
- onPageChange?: (page: number, pageSize: number) => void;
2624
- }
2625
- /**
2626
- * Search-form configuration (vxe-grid formConfig parity). Renders a field row
2627
- * above the toolbar (or the table root). Submit merges the values into the
2628
- * table filters: client-side via the existing `filteredData` path, or into the
2629
- * proxy query (`setParams({ filters, page: 1 })`) when `proxyConfig` is set.
2630
- */
2631
- interface IrisTableFormConfig {
2632
- fields: IrisTableFormField[];
2633
- /** Label of the submit button. Defaults to the i18n `table.formSubmit` key. */
2634
- submitText?: string;
2635
- /** Label of the reset button. Defaults to the i18n `table.formReset` key. */
2636
- resetText?: string;
2637
- /** Fired on submit with every field's value (empty strings stripped). */
2638
- onSearch?: (values: Record<string, string>) => void;
2639
- /** Fired on reset with the reset values (defaults re-applied). */
2640
- onReset?: (values: Record<string, string>) => void;
2641
- }
2642
- /**
2643
- * Imperative row operations (vxe-grid insert/remove/setRow parity, simplified
2644
- * to key addressing). Assigned to `tableRef.current` on mount; every op
2645
- * applies a core pure helper to the live row list, commits through the same
2646
- * write-back channel as cell edits, and fires `onDataChange` with the new
2647
- * list. Not-found keys are silent no-ops (the core helpers return the
2648
- * original reference).
2649
- */
2650
- interface IrisTableHandle<Row extends Record<string, unknown> = Record<string, unknown>> {
2651
- /** Insert a row at `index` (default: end). A missing `rowKeyField` value gets an auto id. */
2652
- insertRow: (row: Row, index?: number) => void;
2653
- /** Remove the row with `key`; its selection is pruned. */
2654
- removeRow: (key: string | number) => void;
2655
- /** Patch the row with `key` ({ ...row, ...patch }). */
2656
- updateRow: (key: string | number, patch: Partial<Row>) => void;
2657
- /** Re-fetch the current page (proxy mode). */
2658
- refetch: () => void;
2659
- /** Clear every selected row (vxe clearCheckboxRow parity). */
2660
- clearSelection: () => void;
2661
- /** Select every checkMethod-eligible row of the current page (vxe
2662
- * setAllCheckboxRow(true) parity `checkMethod` rows are skipped). */
2663
- selectAll: () => void;
2664
- /** Toggle a single row's selection by key (vxe toggleCheckboxRow parity
2665
- * a direct toggle that bypasses `checkMethod`). */
2666
- toggleRowSelection: (key: string | number) => void;
2667
- }
2668
- /** Pager configuration (vxe-grid pagerConfig parity). */
2669
- interface IrisTablePagerConfig {
2670
- /** Rows-per-page options rendered as a size selector next to the pager. A
2671
- * change re-queries with the new size and resets the page to 1. */
2672
- pageSizes?: number[];
2673
- }
2674
- /** Public input surface for the React table adapter. */
2675
- interface IrisTableProps<Row extends Record<string, unknown> = Record<string, unknown>> {
3805
+ keyboardNavigation?: boolean;
3806
+ /** Batch AN shortcuts (iris 独有 — vxe keyboardConfig has no edit/clear
3807
+ * keys): F2 begins editing the focused cell's column (when editable),
3808
+ * Delete/Backspace clears it to `''` — one batched `commitRowList`
3809
+ * (undo-covered via the undo funnel). Requires `keyboardNavigation`'s
3810
+ * focused-cell state (single-tabstop roving cell focus); without it the
3811
+ * shortcuts are inert. While an inline editor is open the editor's own
3812
+ * keys win. Additive — default off. */
3813
+ tableShortcuts?: boolean;
3814
+ /** Batch DR (iris 独有): edit keys for the focused editable cell. F2 is
3815
+ * always included when this prop is present; Enter and Space extend it. */
3816
+ editKeys?: Array<'F2' | 'Enter' | 'Space'>;
3817
+ /** Batch BG (iris 独有 — vxe keyboardConfig has no rebinding): rebind the
3818
+ * built-in shortcut keys. ONE key spec string per action
3819
+ * (`Modifier+Key`, case-insensitive; `Ctrl`/`Cmd`/`Meta` share one
3820
+ * ctrl-or-meta flag `Ctrl+C` matches Ctrl OR Cmd). Actions:
3821
+ * `edit` (default F2) / `clear` (Delete, Backspace) need `tableShortcuts`;
3822
+ * `undo` (Ctrl+Z) / `redo` (Ctrl+Y, Ctrl+Shift+Z) need `undo`;
3823
+ * `copy` (Ctrl+C) / `paste` (Ctrl+V) need `clipConfig`;
3824
+ * `fill` (Ctrl+D one-step drag-down) needs `rangeFill` + a live range;
3825
+ * `query` (Ctrl+K focuses the query input) needs the controlled `query`.
3826
+ * An override REPLACES that action's bindings wholesale (aliases included);
3827
+ * invalid specs (`''` / `'Meta'` / `'Ctrl+'` …) are dropped fail-closed —
3828
+ * the action keeps its default. Modifiers match exactly: `Ctrl+Shift+Z`
3829
+ * redoes, `Alt+Ctrl+Z` is inert. Additive — default off (defaults unchanged). */
3830
+ keymap?: Partial<Record<_iris_ui_kit_core.IrisTableKeyAction, string>>;
3831
+ /** Batch DJ (iris 独有 — vxe keyboardConfig has no focus gate): shortcut
3832
+ * scope for the table's WINDOW keydown listeners (undo/redo, clip
3833
+ * copy/paste, fnr Ctrl+F + Escape, batch-edit Escape). `hotkeyScope`
3834
+ * (default `true`) gates the shortcuts to fire only while the focus is
3835
+ * INSIDE the table (`rootRef.contains(e.target)` the focused element,
3836
+ * read live from the keydown target, no extra focus/blur state). Set it to
3837
+ * `false` for the permissive compatibility mode where the same bindings
3838
+ * fire regardless of where the focus is. `outerScope` (default `false`)
3839
+ * forces the GLOBAL scope (fire from anywhere) and wins over
3840
+ * `hotkeyScope`. Fail-closed by default: fnr/batch-edit tighten from
3841
+ * anywhere in-table; undo/clip keep their existing in-table behavior. */
3842
+ hotkeyScope?: boolean;
3843
+ /** Force GLOBAL shortcut scope (fire from anywhere, ignoring
3844
+ * `hotkeyScope`). Default `false`. */
3845
+ outerScope?: boolean;
3846
+ /** Batch BS (iris 独有 — vxe group-config has no multi-column grouping): table-level NESTED multi-column grouping. Array elements are leaf column `key`s; their order defines the nesting levels (`['dept','status']` → `dept` level 0 → `status` level 1). Every level renders its own collapsible group header (indented by depth, `data-iris-group-depth`); a parent group's count is the subtree row total; the per-group summary row (`summary` ops) appears only on the innermost level. Composite group keys join the level values with `::` (`data-iris-group-key`), so `groupCollapsed`/`defaultGroupCollapsed` address nested groups directly (`'Engineering::Active'`) and a collapsed parent hides its whole subtree. When set, the array WINS over any column-level `groupBy: true` flag; absent/empty/unknown-only → the single-column batch M/BH path runs byte-identical (the array's level-0 fallback). Unknown keys are dropped, duplicates keep the first occurrence. Inert in tree mode (fail-closed, like column grouping). */
3847
+ groupBy?: string[];
3848
+ /** Batch BH (iris 独有 vxe group-config has no collapse): controlled set of
3849
+ * collapsed group keys. Keys are `String(cell value)` of the `groupBy` column —
3850
+ * the same identity `data-iris-group-key` carries. When set, the rendered body
3851
+ * only changes after the parent writes the prop back (no optimistic flip).
3852
+ * Inert without `groupBy` / in tree mode. */
3853
+ groupCollapsed?: Array<string | number>;
3854
+ /** Default collapsed group keys (uncontrolled mode). */
3855
+ defaultGroupCollapsed?: Array<string | number>;
3856
+ /** Fired on every group-header toggle with the next collapsed keys, in BOTH
3857
+ * controlled and uncontrolled modes (lift-ready). */
3858
+ onGroupCollapseChange?: (next: Array<string | number>) => void;
3859
+ /** Enable virtual scrolling for the body. */
3860
+ virtualScroll?: IrisTableVirtualOptions;
3861
+ /** Per-row height (batch BN, iris 独有 — vxe row-height is a fixed config value). Number → uniform height (overrides the default AND `virtualScroll.itemHeight` in virtual mode); `(index) => number` → per-row heights in virtual mode the fn feeds the variable-height virtualizer (virtual PLAN index, prefix-sum offsets, like `virtualScroll.itemHeight`), otherwise each body row gets its inline height (bodyData index). `rowStyle` stays the per-row escape hatch (it wins). */
3862
+ rowHeight?: number | ((index: number) => number);
3863
+ /** Batch EC (iris 独有 — vxe autoHeight fills rows to the VIEWPORT instead; there is no content-wrap display row): when NO fixed row height is set — `rowHeight` and `virtualScroll.itemHeight` both absent — DATA rows grow to their content. The one-line clamp (nowrap + ellipsis) is released for data-row cells via a CSS root marker (`data-iris-adaptive-height`) and each data row's height is pinned to its MEASURED rendered height (a dependency-free layout effect reads `offsetHeight` after every commit, diffs once, same-value bail — no re-render loops; window resize + a ResizeObserver re-measure; data/edit/font/density changes self-heal through the per-commit effect), so a textarea/paragraph cell renders fully instead of being clipped at one line. Header/summary/footer/state rows stay nowrap; virtual tables and tables with a fixed `rowHeight` are inert (uniform slots). Rows that measure `≤ 0` (jsdom/SSR/hidden) keep natural height — never a 0px collapse. `rowStyle` stays the per-row escape hatch (it wins). Additive; default off (fail-closed — the nowrap base renders byte-identical). */
3864
+ adaptiveRowHeight?: boolean;
3865
+ /** Persist view state across remounts (batch AG, iris 独有 — vxe has no built-in persistence). Loads sort / multiSortState / filters / filterValues / columnVisibility / columnOrder / columnWidths / pageSize / expandedKeys on mount (replayed through the matching change callbacks) and saves the CURRENT props on every change (the table is controlled). pageSize is only meaningful with proxyConfig.onPageChange (restored via onPageChange(1, restored) before the first query); expandedKeys (batch BY) needs onExpandedRowsChange + an expandable table (renderDetail or tree) — restored through the expansion model, which replays the callback (full-set replace); storage: false fully disables persistence (no reads, no writes); default key 'iris-table-state'. */
3866
+ persistState?: IrisTablePersistConfig;
3867
+ /** Batch DM (iris 独有): periodically persist the complete exported view
3868
+ * state to a separate storage key and restore it once on mount. */
3869
+ autoSaveState?: IrisTableAutoSaveStateConfig;
3870
+ /** Batch DV (iris 独有 — vxe has no URL-state concept): deep-linkable view
3871
+ * state when `true`, the table mirrors sort / sorts (multiSort mode) /
3872
+ * filters / filterValues / page+pageSize (proxy only) into ONE `_table`
3873
+ * query param (`history.replaceState`, other params preserved; empty state
3874
+ * removes it) and restores from the URL on mount (URL wins over
3875
+ * `persistState` on conflicts) and on `hashchange`/`popstate` (share-link
3876
+ * support). Each piece follows the SAME per-piece callback gates as
3877
+ * `persistState` (onSortChange / onMultiSortChange / onFiltersChange /
3878
+ * onFilterValuesChange / proxy onPageChange) — an uncontrolled piece is
3879
+ * inert in both directions. Decode is whole-state fail-closed: a corrupt /
3880
+ * wrong-version payload is ignored entirely, never partially restored.
3881
+ * Default off. */
3882
+ urlState?: boolean;
3883
+ }
3884
+
3885
+ interface IrisTableLayoutProps<Row extends Record<string, unknown> = Record<string, unknown>> {
2676
3886
  columns: IrisTableColumn<Row>[];
2677
3887
  /** Table data. Optional when `proxyConfig` is set (server-side source). */
2678
3888
  data?: Row[];
@@ -2697,6 +3907,18 @@ interface IrisTableProps<Row extends Record<string, unknown> = Record<string, un
2697
3907
  striped?: boolean;
2698
3908
  /** Size preset (vxe-grid size parity): medium / small / mini. */
2699
3909
  size?: 'medium' | 'small' | 'mini';
3910
+ /**
3911
+ * Row-density preset (iris 独有 — vxe has no density concept): three tiers
3912
+ * of row/cell padding stacked on top of `size` (both write
3913
+ * `--iris-cell-pad-y`; density wins on ties). Default comfortable.
3914
+ */
3915
+ density?: IrisTableDensity;
3916
+ /**
3917
+ * Toolbar density-toggle button (iris 独有 — vxe has no density toggle):
3918
+ * cycles comfortable → compact → cozy → comfortable; while shown, the
3919
+ * button state wins over the `density` prop.
3920
+ */
3921
+ densityToggle?: boolean;
2700
3922
  /** First sequence number (vxe seq-config.startIndex parity). Default 1. */
2701
3923
  seqStartIndex?: number;
2702
3924
  /** Custom sequence renderer (vxe seq-config.seqMethod parity). */
@@ -2711,6 +3933,8 @@ interface IrisTableProps<Row extends Record<string, unknown> = Record<string, un
2711
3933
  currentColumnKey?: string;
2712
3934
  /** Fired when the current column changes (header click). */
2713
3935
  onCurrentColumnChange?: (key: string) => void;
3936
+ /** Header cell click (vxe header-click parity). Fired after the sort toggle on sortable headers. */
3937
+ onHeaderClick?: (column: IrisTableColumn<Row>) => void;
2714
3938
  /** Veto a current-column change: return false to keep the previous column. */
2715
3939
  beforeCurrentColumnChange?: (key: string) => boolean | void;
2716
3940
  /** Hide the header row(s) (vxe show-header parity). Default true. */
@@ -2720,6 +3944,51 @@ interface IrisTableProps<Row extends Record<string, unknown> = Record<string, un
2720
3944
  * row, one grid row per entry; structure matches `data`.
2721
3945
  */
2722
3946
  footerData?: Row[];
3947
+ /** Custom footer rows (vxe footer-method parity, batch N): one grid row per returned entry, cell value = `entry[col.key]`, same styling as the summary row; `footerData` renders below. `columns` = leaf columns, `data` = full filtered rows. */
3948
+ footerMethod?: (params: IrisTableFooterMethodParams<Row>) => Row[];
3949
+ /** Footer cell merge (vxe footer-span-method parity, batch P): `colspan` > 1 spans adjacent cells (covered cells skipped, same occupy pattern as `spanMethod`); `rowspan` inert (each footer row is its own grid container). Applies over the footer stack in order: footerMethod rows → summary row → footerData rows; `rowIndex` is 0-based over that stack, `columns` = leaf columns, `data` = full filtered body rows. Group summary rows are not part of the stack. */
3950
+ footerSpanMethod?: IrisTableFooterSpanMethod<Row>;
3951
+ /** Header cell alignment (vxe header-align parity): `headerAlign` wins over
3952
+ * the column's `align`, then 'left'. Applies to flat + grouped headers. */
3953
+ headerAlign?: IrisTableAlign;
3954
+ /** Footer/summary cell alignment (vxe footer-align parity): `footerAlign`
3955
+ * wins over the column's `align`. Applies to summary, footer-method, footer-data. */
3956
+ footerAlign?: IrisTableAlign;
3957
+ /**
3958
+ * Auto-detect column types (batch CX, iris 独有 — vxe requires the caller
3959
+ * to declare `sortType` per column; no auto inference): on FIRST data
3960
+ * arrival, each leaf column's value kind (`string`/`number`/`date`/
3961
+ * `boolean`) is inferred by the core `detectColumnType` from its first 50
3962
+ * non-nullish values (all-samples-agree; mixed columns and numeric/boolean
3963
+ * STRINGS fall back to `string`). Detected columns receive the matching
3964
+ * default alignment + `sortType` — `number` → right-aligned + `'number'`
3965
+ * sort, everything else → left + `'string'` — filling ONLY the fields the
3966
+ * caller left `undefined` (explicit `align`/`sortType` always win; preset
3967
+ * defaults survive). One-shot per mount (later data re-feeds never
3968
+ * re-detect); SSR-safe (effect-driven, the fill lands post-hydration).
3969
+ * Default false — byte-identical with the pre-prop render path.
3970
+ */
3971
+ autoDetectTypes?: boolean;
3972
+ /** Batch CM (iris 独有 — vxe has no summary sticky parity): `'sticky'` pins
3973
+ * the GLOBAL summary row (op row or footerMethod rows — the two renders
3974
+ * that occupy the same footer slot) to the viewport's bottom edge inside
3975
+ * the fixed-height scroll container (`position: sticky; bottom: 0`;
3976
+ * gated by `[data-iris-table-fixed-height]`, same z-index 1 as pinned
3977
+ * columns). Two explicit fiats: per-group summary rows never stick (groups
3978
+ * would fight over the bottom edge) and footerData rows never stick
3979
+ * (contractually rendered below the summary). Pure CSS additive; default
3980
+ * `'default'` — fail-closed, no sticky attr. */
3981
+ summaryRowStyle?: 'default' | 'sticky';
3982
+ /**
3983
+ * Decimal places for summary/footer aggregate values (vxe
3984
+ * aggregateAccuracyConfig parity, batch P): a finite numeric op result is
3985
+ * rounded via `Number(value.toFixed(n))` at the single summary point
3986
+ * (global + per-group summaries), before `renderSummary` — custom renderers
3987
+ * see the rounded value. Non-finite results are left untouched. Values
3988
+ * outside 0–100 (inclusive) are ignored — no rounding (`toFixed`
3989
+ * RangeError guard). Default: no rounding.
3990
+ */
3991
+ aggregateAccuracy?: number;
2723
3992
  /** Per-row class hook (vxe row-class-name parity). */
2724
3993
  rowClassName?: (row: Row, rowIndex: number) => string;
2725
3994
  /** Per-cell class hook (vxe cell-class-name parity). */
@@ -2729,25 +3998,141 @@ interface IrisTableProps<Row extends Record<string, unknown> = Record<string, un
2729
3998
  /** Per-footer-cell class hook (vxe footer-cell-class-name parity). */
2730
3999
  footerCellClassName?: (column: IrisTableColumn<Row>, rowIndex: number) => string;
2731
4000
  /** Per-row inline style hook (vxe row-style parity). */
2732
- rowStyle?: (row: Row, rowIndex: number) => CSSProperties;
4001
+ rowStyle?: (row: Row, rowIndex: number) => React.CSSProperties;
2733
4002
  /** Per-cell inline style hook (vxe cell-style parity). */
2734
- cellStyle?: (row: Row, column: IrisTableColumn<Row>, rowIndex: number) => CSSProperties;
4003
+ cellStyle?: (row: Row, column: IrisTableColumn<Row>, rowIndex: number) => React.CSSProperties;
4004
+ /** Conditional cell styles (batch AX, iris 独有): an ordered rule list merged onto matching body cells AFTER `cellStyle` — later matching rules win on conflicting keys. A rule matches when its `column` filter (omitted → every column) equals the cell's column key AND `when(row, value)` is true; `value` is the RAW cell value (dataIndex ?? key resolved, formula columns computed). Rules evaluate inline per visible cell (cost = visibleCells × rules; virtual scroll bounds it — memoize the array in the caller). */
4005
+ conditionalStyles?: IrisTableConditionalStyle<Row>[];
4006
+ /** External table data for cross-table formula refs (batch BC, iris 独有): `=other!col` reads `formulaTables['other'][0]['col']` (the FIRST row of the named table). Missing tables arg / unknown table / EMPTY table / unknown field → the whole formula null (fail-closed); a known nullish field coerces (Excel parity). Immutable contract: pass a NEW object when referenced tables change. */
4007
+ formulaTables?: Record<string, Row[]>;
4008
+ /** Extra row sets appended to `handle.exportMultiCsv()` (batch DI, iris 独有 — vxe has no multi-file export): each entry names a referenced table whose BARE rows (`Row[]`, no column definitions — they're not IrisTable column configs) are serialized by their OWN enumerable keys (first row's keys are the header), NOT by this table's columns. `key` is both the `# <key>` segment header and (documented) the section name; `ref` is called lazily at export time (handle call, not render) so it can read the live source rows of that table. Empty/absent `exportNames` → `exportMultiCsv()` falls back to the bare current-table CSV, byte-identical to `exportCurrentViewCsv()`. An entry with an empty `key` is skipped entirely; an empty ref row set emits just the segment header. Immutable contract: pass a NEW array when the set changes. */
4009
+ exportNames?: Array<{
4010
+ key: string;
4011
+ ref: () => Row[];
4012
+ }>;
2735
4013
  /** Per-header-cell inline style hook (vxe header-cell-style parity). */
2736
- headerCellStyle?: (column: IrisTableColumn<Row>) => CSSProperties;
4014
+ headerCellStyle?: (column: IrisTableColumn<Row>) => React.CSSProperties;
2737
4015
  /** Per-footer-cell inline style hook (vxe footer-cell-style parity). */
2738
- footerCellStyle?: (column: IrisTableColumn<Row>, rowIndex: number) => CSSProperties;
4016
+ footerCellStyle?: (column: IrisTableColumn<Row>, rowIndex: number) => React.CSSProperties;
4017
+ /**
4018
+ * Unified event stream (batch DW, iris 独有 — vxe has no single event bus):
4019
+ * cell/row click, sort, filter, edit and expand events merged into ONE
4020
+ * subscription. The bus fires AFTER the matching dedicated callback (if
4021
+ * wired) — a bridge, not a behavior, so gate parity holds by construction
4022
+ * (no `onCellClick`/`rowMode` → no cell-click event). `type` is one of the
4023
+ * closed `IrisTableEvent` palette; `detail` carries the SAME params the
4024
+ * dedicated callback receives (reference-identical `detail.row`/`column`).
4025
+ * Controllable proxy `sort` updates (a parent-driven `sort`/`multiSortState`
4026
+ * prop change — not a user click) fire no event. The expansion family
4027
+ * mirrors the shared `onExpandedRowsChange` channel: EVERY model commit
4028
+ * fires `expanded-rows-change` — user toggles, `expandAll` seeding, and
4029
+ * `persistState`/view `expandedKeys` restores all replay through the
4030
+ * expansion model's `onChange` (a restore still needs `onExpandedRowsChange`
4031
+ * + an expandable table — the same gate as the dedicated callback).
4032
+ */
4033
+ onTableEvent?: (event: {
4034
+ type: string;
4035
+ detail: unknown;
4036
+ }) => void;
2739
4037
  /** Cell click (vxe cell-click parity). Fired after internal handlers. */
2740
4038
  onCellClick?: (params: IrisTableCellClickParams<Row>) => void;
4039
+ /** Cell double-click (vxe cell-dblclick parity). Fired AFTER the inline edit starts on editable columns; non-editable columns fire it too. */
4040
+ onCellDblClick?: (params: IrisTableCellClickParams<Row>) => void;
2741
4041
  bordered?: boolean;
4042
+ /**
4043
+ * Rounded root corners (vxe-grid round parity, batch P): the root gets
4044
+ * `border-radius: var(--iris-radius-lg, 10px)` when `bordered && round`;
4045
+ * otherwise the default md radius applies.
4046
+ */
4047
+ round?: boolean;
4048
+ /**
4049
+ * Cell padding override (vxe-grid deprecated `padding` parity, batch P):
4050
+ * sets `--iris-cell-pad` on the root; every cell padding reads
4051
+ * `var(--iris-cell-pad, var(--iris-cell-pad-y, 8px) 12px)`, so the size
4052
+ * presets (small/mini) still win through `--iris-cell-pad-y`.
4053
+ */
4054
+ padding?: string;
2742
4055
  /** Enable column resizing (drag the header's trailing edge or focus + arrow keys). */
2743
4056
  resizableColumns?: boolean;
4057
+ /** Batch DS (iris 独有): show the live pixel width while a resize drag is active. */
4058
+ widthHint?: boolean;
4059
+ /**
4060
+ * Auto-fit column widths on double-click (iris 独有, batch DG — vxe has no
4061
+ * auto-resize): when true (WITH `resizableColumns`, so the handle exists),
4062
+ * double-clicking a column boundary measures the widest rendered content
4063
+ * (header + body cells, `scrollWidth` already includes both-side padding)
4064
+ * and writes the clamped width via `onColumnWidthsChange` (the same duck
4065
+ * channel as drag/keyboard). Falls back fail-closed: no handle without
4066
+ * `resizableColumns`; virtual scrolling measures only the rendered window
4067
+ * (vxe autoResize behavior). Additive — default off.
4068
+ */
4069
+ autoResizeColumns?: boolean;
2744
4070
  /** Controlled per-column pixel widths, keyed by column `key`. */
2745
4071
  columnWidths?: IrisTableColumnWidths;
2746
4072
  defaultColumnWidths?: IrisTableColumnWidths;
2747
4073
  onColumnWidthsChange?: (next: IrisTableColumnWidths) => void;
4074
+ /**
4075
+ * Toolbar reset-widths button (iris 独有, batch BO): clicking it calls
4076
+ * `onColumnWidthsChange({})` — the empty map means zero overrides, so every
4077
+ * column falls back to its declared width. Like `zoomConfig`, this prop
4078
+ * alone does not create the toolbar.
4079
+ */
4080
+ columnWidthsReset?: boolean;
4081
+ /**
4082
+ * Column header pin menu (batch BX, iris 独有 — vxe has no built-in
4083
+ * header pin menu): when true, right-clicking a column HEADER opens a
4084
+ * built-in menu — 固定左 (key `__iris-pin-left`) when the column is not
4085
+ * pinned, 取消固定 (key `__iris-unpin`) when it is pinned left OR right
4086
+ * (the item flips with the column's CURRENT pin state, single and mutually
4087
+ * exclusive — spec has no pin-right action). The menu is fully independent
4088
+ * of `contextMenu` (which only opens on body cells and never on headers):
4089
+ * `columnPinMenu` works with NO `contextMenu` configured, and the two are
4090
+ * separate floating instances — opening one closes the other. Every action
4091
+ * fires `onColumnPinnedChange` in BOTH controlled and uncontrolled modes
4092
+ * (`onColumnWidthsChange` dual-channel precedent, no optimistic flip when
4093
+ * controlled); without `pinnedColumns` the table holds the pin state
4094
+ * internally and the static `col.pinned` declaration seeds the fallback.
4095
+ * Additive — default off.
4096
+ */
4097
+ columnPinMenu?: boolean;
4098
+ /**
4099
+ * Controlled per-column pin state (batch BX): column key → `'left'` /
4100
+ * `'right'` / `null` (unpinned). When set, the map is the ONLY read source
4101
+ * for the rendered pin state — an explicit `null` entry overrides a static
4102
+ * `col.pinned` declaration (controlled-null-wins); absent keys fall back to
4103
+ * the column's own declaration, so `{}` never unpins static pins.
4104
+ */
4105
+ pinnedColumns?: Record<string, 'left' | 'right' | null>;
4106
+ /**
4107
+ * Fired on every pin-menu action with the column key and the next side
4108
+ * (`null` = unpin), in both controlled and uncontrolled modes (lift-ready).
4109
+ */
4110
+ onColumnPinnedChange?: (key: string, side: 'left' | 'right' | null) => void;
4111
+ /**
4112
+ * Pinned-count boundary drag (batch CV, iris 独有 — vxe has no pinned
4113
+ * boundary handle): when true, the LAST left-pinned leaf header's trailing
4114
+ * edge carries a draggable separator handle (8px grip + 2px primary line,
4115
+ * sticky inside the pinned cell) that adjusts the number of left-pinned
4116
+ * columns — drag right pins more / drag left unpins, commit-on-release (a
4117
+ * translateX ghost follows the pointer while dragging); Arrow-Left/Right
4118
+ * nudge the count by one. The commit writes `setColumnPinned('left' |
4119
+ * null)` per CHANGED column (the SAME dual-channel throat as the pin menu —
4120
+ * `onColumnPinnedChange` fires per column in both modes, no optimistic
4121
+ * flip when controlled) and then fires `onPinnedCountChange` once; no-op
4122
+ * drags fire nothing. Left-only count: no handle without at least one
4123
+ * left-pinned column; the boundary never crosses the first right-pinned
4124
+ * index (hard cap); widths approximate via the pinnedOffsets fallback
4125
+ * chain (non-numeric → default, fiat). While on, the boundary column's
4126
+ * `resizableColumns` handle is suppressed (a resize grip on the same edge
4127
+ * would fight the boundary drag). Additive — default off.
4128
+ */
4129
+ pinnedDrag?: boolean;
4130
+ /** Fired once per pinned-boundary commit with the new left-pinned column count (0 = none), AFTER the per-column `onColumnPinnedChange` calls. */
4131
+ onPinnedCountChange?: (count: number) => void;
2748
4132
  /** Called when a data row is clicked. Interactive child controls stop propagation. */
2749
4133
  onRowClick?: (row: Row, rowIndex: number) => void;
2750
- /** Called when an inline-editable cell is committed with a changed value. */
4134
+ /** Row double-click (vxe row-dblclick parity). */
4135
+ onRowDblClick?: (row: Row, rowIndex: number) => void;
2751
4136
  /**
2752
4137
  * Column visibility (vxe-grid columnConfig.visible parity). Map of
2753
4138
  * column key → visible (default true). Hidden columns are not rendered.
@@ -2756,13 +4141,31 @@ interface IrisTableProps<Row extends Record<string, unknown> = Record<string, un
2756
4141
  /** Fired when visibility changes (parent owns the map). */
2757
4142
  onColumnVisibilityChange?: (next: Record<string, boolean>) => void;
2758
4143
  /**
2759
- * Client-side filters (vxe-grid filterConfig parity, local mode). Map of
2760
- * column key filter text; rows are filtered with the core filterSort
2761
- * material (substring, case-insensitive).
4144
+ * Column show/hide transition (batch DY, iris 独有 — vxe has no fade): when
4145
+ * true, `columnVisibility` changes play a 200ms opacity + width transition
4146
+ * instead of snapping — a hiding column keeps its cells mounted while its
4147
+ * track collapses Wpx→0px and opacity fades to 0, then commits away; a
4148
+ * showing column mounts at 0px/opacity 0 and restores both. The duration is
4149
+ * token-driven (`--iris-duration-md`, fallback 200ms) and the whole machine
4150
+ * is disabled under `prefers-reduced-motion` (instant show/hide, vxe
4151
+ * parity). Mount-hidden columns never animate (only later toggles play); a
4152
+ * mid-fade revert restarts the fade in the new direction. Pure render-side
4153
+ * additive — `columnVisibility`/`onColumnVisibilityChange` keep their exact
4154
+ * semantics. Default false — byte-identical with the pre-prop render path.
2762
4155
  */
4156
+ columnFade?: boolean;
4157
+ /** Controlled column order (vxe customConfig parity): the panel's drag list reorders these keys; unnamed keys follow in source order, unknown keys ignored. Top-level columns only. */
4158
+ columnOrder?: string[];
4159
+ /** Fired when the panel confirms a new order. `undefined` clears the order (parent drops `columnOrder`). */
4160
+ onColumnOrderChange?: (order: string[] | undefined) => void;
4161
+ /** Client-side filters (vxe-grid filterConfig parity, local mode): column key → filter text; rows filtered with the core filterSort material (substring, case-insensitive). */
2763
4162
  filters?: Record<string, string>;
2764
- /** Fired when a filter value changes (parent owns the map). */
4163
+ /** Fired when a filter value changes (parent owns the map). Batch T: this IS the text filter channel (vxe filter-change parity) — a separate `onFilterChange` prop was intentionally NOT added; checked sets use `onFilterValuesChange`. */
2765
4164
  onFiltersChange?: (next: Record<string, string>) => void;
4165
+ /** Per-column checked filter sets (vxe filter-multiple parity): column key → values OR-matched against the raw `String(value)` of each row. Controlled via `onFilterValuesChange`; without a handler read-only. */
4166
+ filterValues?: IrisTableFilterValues;
4167
+ /** Fired when the filter panel confirms or clears a column's checked set. */
4168
+ onFilterValuesChange?: (next: IrisTableFilterValues) => void;
2766
4169
  /** Search form (vxe-grid formConfig parity). */
2767
4170
  formConfig?: IrisTableFormConfig;
2768
4171
  /** Toolbar (vxe-grid toolbarConfig parity, minimal built-ins). */
@@ -2772,8 +4175,12 @@ interface IrisTableProps<Row extends Record<string, unknown> = Record<string, un
2772
4175
  onRefresh?: () => void;
2773
4176
  /** Show the column-visibility toggle button. */
2774
4177
  columnSettings?: boolean;
4178
+ /** Custom column panel options (vxe customConfig parity): the columnSettings button opens the full panel (search + drag reorder + visibility toggles + reset) instead of the plain checkbox menu. */
4179
+ customConfig?: IrisTableCustomConfig;
2775
4180
  /** Enable the CSV import button. Receives parsed rows (header → keys). */
2776
4181
  onImport?: (rows: Record<string, unknown>[]) => void;
4182
+ /** Fired by the export button (vxe toolbar export parity, batch L). */
4183
+ onExport?: () => void;
2777
4184
  /** Custom action buttons rendered after the built-ins (vxe toolbar buttons parity). */
2778
4185
  buttons?: Array<{
2779
4186
  key: string;
@@ -2781,86 +4188,184 @@ interface IrisTableProps<Row extends Record<string, unknown> = Record<string, un
2781
4188
  onClick: () => void;
2782
4189
  icon?: string;
2783
4190
  }>;
4191
+ /** Batch action (vxe toolbar batch parity, batch M): a primary button rendered after the built-ins while `selectable === 'multi'` and rows are selected; receives the current selection keys. When `edit` is true (iris 独有), the button instead opens the built-in batch edit panel — an editable-column select + value input + 应用: ONE `commitRowList` writes the value into every selected row (selection unchanged, editRules bypassed like paste). */
4192
+ batch?: {
4193
+ label: string;
4194
+ onClick: (keys: Array<string | number>) => void;
4195
+ icon?: string;
4196
+ edit?: boolean;
4197
+ };
4198
+ };
4199
+ /** Zoom overlay (vxe toolbar zoom parity, batch U): when `showButton`, the
4200
+ * toolbar renders a toggle (⛶ when not zoomed, ✕ when zoomed) that pins the
4201
+ * table root as a fullscreen overlay (fixed, inset 0, popover z-index);
4202
+ * Esc exits. Local state — no parent props needed. */
4203
+ zoomConfig?: {
4204
+ showButton?: boolean;
4205
+ };
4206
+ /** Import preview (iris 独有 — vxe has no pre-import preview): when true,
4207
+ * the toolbar ⇪ CSV import shows a centered modal previewing the first 5
4208
+ * parsed rows (plus a total-count note when more) before anything lands;
4209
+ * 确认 calls `toolbar.onImport` with ALL parsed rows, 取消 / Esc / backdrop
4210
+ * close with zero calls. Default false — the import lands directly (vxe
4211
+ * parity). */
4212
+ importPreview?: boolean;
4213
+ /** Section layouts (vxe-grid layouts parity, batch U, suppression-only):
4214
+ * `form`/`toolbar` `'hidden'` skips that section (the config stays
4215
+ * accepted); `pager` `'hidden'` skips the proxy pager. Defaults render
4216
+ * every section exactly as before. */
4217
+ layouts?: {
4218
+ form?: 'top' | 'hidden';
4219
+ toolbar?: 'top' | 'hidden';
4220
+ pager?: 'bottom' | 'hidden';
2784
4221
  };
2785
4222
  /** Render with print-friendly styles (hides the toolbar, keeps rows). */
2786
4223
  printable?: boolean;
4224
+ }
4225
+
4226
+ interface IrisTableQueryProps<Row extends Record<string, unknown> = Record<string, unknown>> {
4227
+ /** Named view presets (batch AH, iris 独有) — toolbar select of saved snapshots. */
4228
+ views?: IrisTableViewConfig;
4229
+ /** Fired when the active view changes (select / save / delete clears null). */
4230
+ onActiveViewChange?: (key: string | null) => void;
4231
+ /** Batch CT — iris 独有 (vxe has no parity).
4232
+ * A `role=tablist` strip rendered ABOVE the toolbar: clicking a tab applies
4233
+ * each name in `views` IN ORDER through the same selectView path the toolbar
4234
+ * select uses (unknown names are skipped fail-inert; when several views touch
4235
+ * the same piece the last applied view wins and the toolbar select mirrors
4236
+ * that last view). Fail-closed: without the prop nothing renders, and no tab
4237
+ * is active until the first click. */
4238
+ tableTabs?: IrisTableTab[];
4239
+ /** Natural-language query (iris 独有): controlled string parsed by core
4240
+ * `parseTableQuery` (`age > 25 and role in (Test, PM) sort by name asc`);
4241
+ * the toolbar query input shows while present, parsed filters AND-merge
4242
+ * (`=`/`contains` → substring, `in` → filterValues OR-match, relational →
4243
+ * rules); `sort by` seeds only with no sort prop set; proxy comma-joins
4244
+ * substring/in into the remote filter map. Controlled-only. */
4245
+ query?: string;
4246
+ /** Fired on every keystroke (parent owns the string). */
4247
+ onQueryChange?: (next: string) => void;
4248
+ /** Render only the horizontally-visible columns plus pinned columns and overscan. */
4249
+ columnVirtualization?: boolean;
2787
4250
  /**
2788
- * Column drag-sort (vxe-grid columnDragConfig parity). Reorders leaf
2789
- * columns on drop; parent owns columns (pass the reordered array back).
4251
+ * Selection summary (batch AP, iris 独有 — vxe has no parity feature, the
4252
+ * header count is its closest cousin): when `selectable === 'multi'` and
4253
+ * rows are selected, the toolbar renders `已选 N 行`
4254
+ * (`data-iris-selection-summary`, i18n `table.selectionSummary`) plus a
4255
+ * `· 合计 X` per leaf column with `summary === 'sum'` (the SAME aggregate
4256
+ * material + `aggregateAccuracy` rounding + `String(value)` formatting the
4257
+ * summary row uses, computed over the SELECTED rows in bodyData order) and
4258
+ * a clear button (`data-iris-selection-clear`) that runs the shared
4259
+ * `clearSelection` path. Additive — default off.
2790
4260
  */
2791
- columnDrag?: {
2792
- /** Called with the reordered column array after a drop. */
2793
- onReorder: (columns: IrisTableColumn<Row>[]) => void;
2794
- };
2795
- /** Render a leading sequence-number column (vxe-grid seqConfig parity). */
2796
- seq?: boolean;
4261
+ selectionSummary?: boolean;
4262
+ /** Enable rectangular cell-range selection. */
4263
+ cellRange?: boolean;
2797
4264
  /**
2798
- * Cell merge (vxe-grid spanMethod parity): return `{ rowspan, colspan }`
2799
- * for a cell at (rowIndex, columnIndex); both default 1. Values > 1 make
2800
- * the cell span adjacent cells (the spanned cells are skipped).
4265
+ * Excel-style drag fill (batch AQ, iris 独有 vxe has no fill parity):
4266
+ * when `cellRange` has a live selected range (≥1 cell), a fill handle
4267
+ * (`data-iris-range-fill`, 6px primary square at the range's bottom-right
4268
+ * cell) appears; dragging it DOWN or RIGHT cyclically fills the target
4269
+ * rectangle from the source range values (`(r, c)` ← source
4270
+ * `((r - start.row) % rangeRows + start.row, …)`), formula columns and
4271
+ * keyless rows skipped, through ONE batched `commitRowList`, then extends
4272
+ * the range to the drag end (Excel parity). Dragging UP/LEFT is ignored
4273
+ * (the handle only grows the range). Additive — default off.
2801
4274
  */
2802
- spanMethod?: (params: {
2803
- rowIndex: number;
2804
- columnIndex: number;
2805
- }) => {
2806
- rowspan?: number;
2807
- colspan?: number;
2808
- } | null | undefined;
2809
- /** Row drag-sort configuration (composed over core createSortable). */
2810
- rowDrag?: {
2811
- /** Reorder callback — receives the reordered row array (parent owns data). */
2812
- onReorder: (rows: Row[]) => void;
4275
+ rangeFill?: boolean;
4276
+ /**
4277
+ * Cell drag-move (batch CN, iris 独有 — vxe has no cell-move parity): when
4278
+ * `cellRange` has a live selected range (≥1 cell), a move grip
4279
+ * (`data-iris-range-move`, 12×4 primary pill on the range's top edge at its
4280
+ * top-left cell) appears; dragging it to another cell CUT-MOVES the whole
4281
+ * block there (剪切移动 — source cells not covered by the destination rect
4282
+ * are cleared; locked/readonly and formula cells survive both phases) and
4283
+ * the selection follows the moved block (Excel parity). The drag end clamps
4284
+ * so the block always fits (down/up/right/left 越界). Zero-commit no-op
4285
+ * when the drag stays on the source block. Inert without `cellRange`.
4286
+ * Additive — default off.
4287
+ */
4288
+ cellDrag?: boolean;
4289
+ /**
4290
+ * Cell drag-copy (batch DZ, iris 独有 — vxe has no cell-copy parity): when
4291
+ * `cellRange` has a live selected range (≥1 cell), a copy grip
4292
+ * (`data-iris-range-copy`, 12×4 primary pill on the range's BOTTOM edge at
4293
+ * its top-left cell — the CN move grip owns the top edge, zero collision)
4294
+ * appears; dragging it to another cell COPIES the whole block there (源块
4295
+ * 不动 — the source keeps its values, unlike cellDrag's cut-move) through
4296
+ * ONE batched `commitRowList`, and the selection stays on the source block
4297
+ * (Excel parity — a copy never moves the selection). The whole destination
4298
+ * rectangle must FIT inside the table (越界忽略, deliberately divergent
4299
+ * from cellDrag's clamp): an out-of-bounds drag end shows no outline and
4300
+ * the release is a zero-commit no-op; a drop on the source block itself is
4301
+ * a zero-commit no-op too. Formula columns are never read/written;
4302
+ * locked/readonly destination cells survive; keyless rows skipped. Inert
4303
+ * without `cellRange`. Additive — default off.
4304
+ */
4305
+ cellDragCopy?: boolean;
4306
+ /** Clipboard batch (vxe-grid clipboard-config parity, batch O): Ctrl/Cmd+C copies the selected cell range; Ctrl/Cmd+V pastes TSV text into the range anchor onward (overflow beyond the last row/col is ignored). Requires `cellRange` to have a live selected range; additive — default off.
4307
+ * Batch BP (iris 独有 — vxe clipboard-config has no output-format switch): `copyFormat` selects the copy OUTPUT format for BOTH consumption points (Ctrl/Cmd+C and the range toolbar 复制 button) — `'tsv'` (default, byte-identical to batch O) / `'csv'` (RFC-4180, headerless range fiat like the 导出 CSV download) / `'html'` (a `<table>` fragment via core `toHtml`, with a header row of column titles — the toHtml contract — and the masked cell values, the batch-AY invariant across all three formats). Paste is unaffected — it always reads `\t`-delimited text. Invalid runtime values fail-closed to `'tsv'`.
4308
+ * Batch CU (iris 独有 — vxe clipboard-config always copies raw values, no format-preserving copy): `copyWithFormat` copies the FORMATTED text of formatter columns (the `contextCellText` display chain — mask → formatter → String, the same chain as the context-menu 复制值) instead of the raw/masked value, across ALL THREE `copyFormat` serializers. Only `col.formatter` columns switch chains — non-formatter columns stay byte-identical — and the formatted STRING still flows through the same serializers (RFC-4180 quoting + OWASP neutralization still apply). `exportRaw`'s copy-path skip is superseded on formatter columns (mask → formatter always); exports are untouched.
4309
+ */
4310
+ clipConfig?: {
4311
+ copy?: boolean;
4312
+ paste?: boolean;
4313
+ copyFormat?: 'tsv' | 'csv' | 'html';
4314
+ copyWithFormat?: boolean;
2813
4315
  };
2814
- /** Inline-edit configuration (vxe-grid editConfig parity). */
2815
- editConfig?: {
2816
- /** What opens the editor. Default `'dblclick'`. */
2817
- trigger?: 'click' | 'dblclick' | 'manual';
2818
- /** Show a required asterisk next to headers of columns with rules. */
2819
- showAsterisk?: boolean;
2820
- /** Drop the draft when opening another cell without committing. */
2821
- autoClear?: boolean;
4316
+ /** Paste options (iris 独有 — vxe-grid clipboard-config has no overflow-insert switch):
4317
+ * `insertIfOverflow` makes a SINGLE-CELL paste append clipboard lines that run past
4318
+ * the last row as brand-new rows (auto-id keys via `insertRowInList`, surplus cells
4319
+ * dropped, locked/readonly columns skipped) — one batched commit. Multi-cell
4320
+ * rectangle pastes stay clipped (fiat) and the default (absent) keeps batch-O
4321
+ * overflow-drop behavior byte-identical. Additive — default off.
4322
+ */
4323
+ pasteOptions?: {
4324
+ insertIfOverflow?: boolean;
2822
4325
  };
2823
- /** Edit-validation presentation (vxe-grid ValidConfig parity). */
2824
- validConfig?: IrisTableValidConfig;
2825
- onCellEdit?: (event: IrisTableCellEditEvent<Row>) => void;
2826
- /** Render an expandable detail panel beneath a row. */
2827
- renderDetail?: IrisTableRenderDetail<Row>;
2828
- /** Which rows can expand a detail panel. */
2829
- rowExpandable?: IrisTableRowExpandable<Row>;
2830
- /** Initially-expanded row keys (uncontrolled). Shared by detail rows + tree rows. */
2831
- defaultExpandedRowKeys?: Array<string | number>;
2832
- /** Expand every tree row that has children on mount (vxe expand-config
2833
- * expandAll parity). One-shot: seeds the expansion model with all tree keys
2834
- * on the first data arrival (proxy pages load async). Default false. */
2835
- expandAll?: boolean;
2836
- /** Notified with the expanded row keys whenever they change. */
2837
- onExpandedRowsChange?: (keys: Array<string | number>) => void;
2838
- /** Read a row's child rows to render the table as a tree. */
2839
- getSubRows?: (row: Row) => Row[] | undefined;
2840
- /** Enable WAI-ARIA grid keyboard navigation. */
2841
- keyboardNavigation?: boolean;
2842
- /** Enable virtual scrolling for the body. */
2843
- virtualScroll?: IrisTableVirtualOptions;
2844
- /** Render only the horizontally-visible columns plus pinned columns and overscan. */
2845
- columnVirtualization?: boolean;
2846
- /** Enable rectangular cell-range selection. */
2847
- cellRange?: boolean;
4326
+ /** Find & replace (vxe-grid find parity, batch O): Ctrl/Cmd+F (when not editing) opens a find/replace bar above the table; Enter/Shift+Enter step through matches; Esc closes and clears highlights. Matches over bodyData (flat mode), case-insensitive substring. Additive — default off. */
4327
+ fnr?: boolean;
4328
+ /** Batch CK (iris 独有 — vxe has no inline search highlight): a
4329
+ * case-insensitive literal-substring search over each text cell's display
4330
+ * chain (mask → formatter ?? raw — the same text autoLink consumes); every
4331
+ * occurrence renders as an inline `<mark data-iris-search-hit>` (the
4332
+ * surface-selected token — the same search-highlight language fnr uses for
4333
+ * matched cells). Display-only: no bar, no match state, no write-back —
4334
+ * the distinction from fnr is the mechanism, not the query.
4335
+ * `render`/`html`/`link`/`autoLink`/sparkline cells are untouched
4336
+ * (documented fiats). Additive; default off (fail-closed).
4337
+ */
4338
+ searchHighlight?: string;
4339
+ /** Built-in undo/redo (iris 独有 — vxe has no built-in undoRedoHistory): when enabled, every data mutation (row ops, paste, find&replace, range clear, cell/row edits, batch edit) records the POST-change row list; Ctrl/Cmd+Z undoes and Ctrl/Cmd+Y (or Ctrl/Cmd+Shift+Z) redoes — never while an inline editor is open. The toolbar renders ↶/↷ buttons after the title (disabled from canUndo/canRedo); restores prune selection keys that no longer exist. Additive — default off. */
4340
+ undo?: boolean;
2848
4341
  /** Shift-click checkbox range selection (vxe checkboxConfig `isShiftKey`
2849
4342
  * parity, batch G): shift-clicking a row checkbox toggles every
2850
4343
  * checkMethod-eligible row between the last-clicked anchor row and the
2851
4344
  * target (in body order); a plain click just moves the anchor. The header
2852
4345
  * select-all resets the anchor. Default false. */
2853
4346
  checkboxRange?: boolean;
2854
- /** Empty state node (replaces the row body when `data` is empty). */
2855
- emptyState?: ReactNode;
4347
+ /** Row-selection drag range (batch BT, iris 独有 vxe has no mouse-drag
4348
+ * checkbox range): pressing the row-selection cell in multi mode and
4349
+ * dragging past the 4px threshold continuously checks every
4350
+ * checkMethod-eligible row between the pressed anchor row and the hovered
4351
+ * row (closed interval in body order); checkMethod-disabled rows are
4352
+ * skipped. The applied set only ever grows during one drag (reverse drags
4353
+ * shrink the interval but never uncheck); a plain click still toggles a
4354
+ * single row. Default false. */
4355
+ selectionDrag?: boolean;
4356
+ /** Empty state node (replaces the row body when `data` is empty). Also accepts
4357
+ * an `IrisTableEmptyState` descriptor (iris 独有 — vxe has no empty-state
4358
+ * action button): `{ text?, action? }` renders the text plus an inline action
4359
+ * button on the same row. */
4360
+ emptyState?: React.ReactNode | IrisTableEmptyState;
2856
4361
  /** Show the loading state instead of rows. */
2857
4362
  loading?: boolean;
2858
4363
  /** Show the error state instead of rows (takes precedence over loading). */
2859
4364
  error?: boolean;
2860
4365
  /** Custom loading-state node. */
2861
- loadingState?: ReactNode;
4366
+ loadingState?: React.ReactNode;
2862
4367
  /** Custom error-state node. */
2863
- errorState?: ReactNode;
4368
+ errorState?: React.ReactNode;
2864
4369
  /** Fired by the built-in Retry button in the error state row. */
2865
4370
  onRetry?: () => void;
2866
4371
  /**
@@ -2872,16 +4377,107 @@ interface IrisTableProps<Row extends Record<string, unknown> = Record<string, un
2872
4377
  /** Cell tooltips (vxe-grid tooltipConfig parity, title mode, batch G): a
2873
4378
  * native `title` on every body cell, content from the callback or the raw
2874
4379
  * cell value; editing cells are exempt and empty content drops the tooltip.
2875
- * Truncation gating is not implemented titles render on every cell
2876
- * regardless of `showAll` (documented simplification, kept simple and
2877
- * explicit). */
4380
+ * With `showAll: false`, titles remain only for cells whose single-line
4381
+ * content measures wider than the rendered cell; SSR/jsdom zero-width
4382
+ * layouts fail open and retain the title. */
2878
4383
  tooltipConfig?: IrisTableTooltipConfig<Row>;
4384
+ /** Cell annotations (iris 独有, batch AZ — vxe has no cell-note concept): a
4385
+ * static map of notes keyed `${rowKey}::${columnKey}` — the same `::`
4386
+ * delimiter as the internal `cellId` (`annotations[cellId(k, col.key)]`).
4387
+ * A noted cell renders a corner badge (`data-iris-cell-note-badge`) + gets
4388
+ * `data-iris-cell-note` + the note as its title (beats `tooltipConfig`);
4389
+ * the dynamic `cellNote` callback wins over this map when both are set. */
4390
+ annotations?: Record<string, string>;
4391
+ /** Dynamic per-cell note (iris 独有, batch AZ): computed from the row +
4392
+ * column — wins over the static `annotations` map. With a note the cell
4393
+ * gets `data-iris-cell-note` + a corner badge + the note as its title
4394
+ * (beats `tooltipConfig`); a null/'' note renders nothing. */
4395
+ cellNote?: (row: Row, column: IrisTableColumn<Row>) => string | null;
4396
+ /** Hover note preview (batch BM, iris 独有 — vxe has no cell-note concept,
4397
+ * and its tooltip can only show the cell value): with `notePopover`, hovering
4398
+ * a noted cell shows a floating popover (`data-iris-note-popover`, role
4399
+ * tooltip, pure display — pointer-events none) anchored to the cell's badge
4400
+ * corner INSTEAD of the native `title`; Escape / outside pointer-down /
4401
+ * any scroll close it. Content-only: zero i18n / core. */
4402
+ notePopover?: boolean;
4403
+ /**
4404
+ * Annotation editing (batch BB, iris 独有 — vxe has no note editing): when
4405
+ * true, the context menu gains built-in items 添加批注 / 编辑批注 / 删除批注
4406
+ * (keys `__iris-annotate` / `__iris-annotate-edit` / `__iris-annotate-remove`,
4407
+ * i18n `table.annotate(.edit/.remove)`) appended AFTER the summary item,
4408
+ * chosen by the clicked cell's existing note (add when none, edit+remove
4409
+ * when one). The add/edit items open a floating annotate panel
4410
+ * (`data-iris-annotate-panel`) — textarea seeded from
4411
+ * `annotations[cellId(rowKey, col.key)]` + 保存 (`data-iris-annotate-save`)
4412
+ * + 删除 (`data-iris-annotate-remove`, only when a note exists); the remove
4413
+ * item deletes the cell's annotation directly. Requires `contextMenu`;
4414
+ * writes flow through `onAnnotationsChange` — without it the items still
4415
+ * show but save/remove are inert (documented).
4416
+ */
4417
+ annotationEditing?: boolean;
4418
+ /**
4419
+ * Annotation write channel (batch BB, iris 独有): receives the NEXT
4420
+ * annotations map on every annotate-panel save — empty text removes the
4421
+ * cell's key, non-empty sets it — and on remove (menu item or panel
4422
+ * button). The map stays fully controlled: `annotations` remains the read
4423
+ * source and the table holds no internal annotation state (same shape and
4424
+ * ownership as `onFiltersChange`).
4425
+ */
4426
+ onAnnotationsChange?: (next: Record<string, string>) => void;
4427
+ /**
4428
+ * Annotation CSV export (batch DU, iris 独有 — vxe has no note concept, so
4429
+ * no export parity): when true, `tableRef.current.exportAnnotationsCsv()`
4430
+ * serializes every noted cell of the current view as CSV
4431
+ * (`rowKey,column,annotation` — the same cellNoteState resolution as the
4432
+ * render, hidden columns excluded). Additive — default off (fail-closed:
4433
+ * without the prop the handle returns `''`).
4434
+ */
4435
+ exportAnnotations?: boolean;
4436
+ /**
4437
+ * Collaborative-presence cursors (batch BD, iris 独有 — vxe has no cursor
4438
+ * sharing): remote participants' selected cells. Each entry draws a 2px
4439
+ * colored outline on its cell (`data-iris-presence="true"`, outline in the
4440
+ * entry's `color` — first entry wins when several share a cell) plus a
4441
+ * corner label with the participant's name (`data-iris-presence-label`
4442
+ * with `-id`/`-name`). Pure display: the table holds no collaboration
4443
+ * state, so a NEW array reference re-renders while in-place mutation does
4444
+ * not (same controlled contract as `data` / `annotations`).
4445
+ */
4446
+ presence?: IrisTablePresenceEntry[];
4447
+ /** Header cell tooltips (vxe header-tooltip-config parity, batch P): a
4448
+ * native `title` on flat + grouped header cells; empty content drops the
4449
+ * tooltip. */
4450
+ headerTooltipConfig?: {
4451
+ content?: (column: IrisTableColumn<Row>) => string;
4452
+ };
4453
+ /** Footer cell tooltips (vxe footer-tooltip-config parity, batch P): a
4454
+ * native `title` on summary / footer-method / footer-data cells; empty
4455
+ * content drops the tooltip. */
4456
+ footerTooltipConfig?: {
4457
+ content?: (column: IrisTableColumn<Row>) => string;
4458
+ };
2879
4459
  /**
2880
4460
  * Right-click context menu (vxe-grid contextMenu parity, batch H). Opens on
2881
4461
  * body leaf cells only — header, seq, selection, expand, summary and footer
2882
4462
  * cells never open it. The menu floats at the cursor (virtual anchor),
2883
4463
  * closes on Escape / outside pointer-down / any scroll, and fires `onSelect`
2884
4464
  * with the clicked item's key and the cell's grid coordinates.
4465
+ *
4466
+ * Batch BW (iris 独有): EVERY menu unconditionally gains two built-in quick
4467
+ * actions after the user items (and after the value-distribution / summary
4468
+ * items when those props are on, before the annotate items) — 复制值
4469
+ * (key `__iris-copy-value`, i18n `table.copyValue`, copies the cell's
4470
+ * display text — mask → formatter → String — to the clipboard) and 清空
4471
+ * (key `__iris-clear-cell`, i18n `table.clearCell`, writes the cell to ''
4472
+ * through the same commitRowList funnel as the Delete shortcut — undo /
4473
+ * audit / onDataChange covered; locked/readonly cells no-op). Both keys are
4474
+ * intercepted at the onSelect wiring, so the user callback never sees them;
4475
+ * without a clipboard the copy no-ops safely.
4476
+ *
4477
+ * Set `formatActions` to true to additionally append opt-in region format
4478
+ * actions (number to two decimals and uppercase text). They remain
4479
+ * intercepted by the table and use the same commit funnel; the default is
4480
+ * false so an ordinary context menu is unchanged.
2885
4481
  */
2886
4482
  contextMenu?: {
2887
4483
  items: (params: IrisTableContextMenuParams<Row>) => Array<{
@@ -2890,19 +4486,121 @@ interface IrisTableProps<Row extends Record<string, unknown> = Record<string, un
2890
4486
  disabled?: boolean;
2891
4487
  }>;
2892
4488
  onSelect: (key: string, params: IrisTableContextMenuParams<Row>) => void;
4489
+ formatActions?: boolean;
2893
4490
  };
2894
- /** Imperative handle for row ops (vxe-grid edit insert/remove/setRow parity). */
2895
- tableRef?: MutableRefObject<IrisTableHandle<Row> | null>;
2896
- /** Fired after any internal row operation / edit write-back, with the new row list. */
2897
- onDataChange?: (rows: Row[]) => void;
2898
- /** Veto rows from selection (vxe-grid checkboxConfig.checkMethod parity). */
2899
- checkMethod?: (row: Row, rowIndex: number) => boolean;
2900
- /** Pager options (vxe-grid pagerConfig parity). */
2901
- pagerConfig?: IrisTablePagerConfig;
2902
- style?: CSSProperties;
2903
- className?: string;
4491
+ /**
4492
+ * Value distribution panel (batch AM, iris 独有): when true, the context
4493
+ * menu gains a built-in item (key `__iris_distribution`, i18n
4494
+ * `table.distribution`) that opens a floating panel counting each distinct
4495
+ * value of the CLICKED column over the current body rows top 20 + a
4496
+ * muted "其余 N 个" fold — computed by the core `valueDistribution`
4497
+ * material over `bodyData` with the `dataIndex ?? key` indirection.
4498
+ * Requires `contextMenu` to be set (the item appends to its items). */
4499
+ valueDistribution?: boolean;
2904
4500
  }
2905
4501
 
4502
+ /**
4503
+ * vxe-grid proxyConfig parity — the server-side data proxy (query slice).
4504
+ * When set, `data` is ignored: rows come from `query` (paged), the table
4505
+ * renders a pager below the body, and edit write-back keeps working.
4506
+ */
4507
+ interface IrisTableProxyConfig<Row extends Record<string, unknown>> {
4508
+ /**
4509
+ * Fetch one page. 1-based `page`; `sort`/`filters` are the ACTIVE state,
4510
+ * passed through when `remoteSort`/`remoteFilter` are enabled.
4511
+ */
4512
+ query: (params: IrisTableProxyQueryParams, signal?: AbortSignal) => Promise<{
4513
+ rows: Row[];
4514
+ total: number;
4515
+ }>;
4516
+ /** Optional Core resilient fetching (dedup/TTL/SWR, breaker, and rate limiting). */
4517
+ resilient?: ResilientFetcherOptions;
4518
+ /** Auto-load the first page on mount (vxe autoLoad parity). Default true. */
4519
+ autoLoad?: boolean;
4520
+ /** Sort changes re-query the server instead of sorting client-side (vxe proxyConfig.sort). Default false. */
4521
+ remoteSort?: boolean;
4522
+ /** Filter changes re-query the server instead of filtering client-side (vxe proxyConfig.filter). Default false. */
4523
+ remoteFilter?: boolean;
4524
+ /** Rows per page. Default 10. */
4525
+ pageSize?: number;
4526
+ /** Initial page (1-based). Default 1. */
4527
+ defaultPage?: number;
4528
+ /** Cumulative sequence numbers across pages (batch L): with the table `seq`
4529
+ * prop, the seq cell renders `(page - 1) * pageSize + rowIndex + 1` instead of `rowIndex + seqStartIndex`. `seqMethod` still wins. */
4530
+ seq?: boolean;
4531
+ /** Fired when the page changes. */
4532
+ onPageChange?: (page: number, pageSize: number) => void;
4533
+ }
4534
+ /**
4535
+ * Search-form configuration (vxe-grid formConfig parity): a field row above
4536
+ * the toolbar; submit merges values into the filters (client-side or proxy).
4537
+ */
4538
+ interface IrisTableFormConfig {
4539
+ fields: IrisTableFormField[];
4540
+ /** Label of the submit button. Defaults to the i18n `table.formSubmit` key. */
4541
+ submitText?: string;
4542
+ /** Label of the reset button. Defaults to the i18n `table.formReset` key. */
4543
+ resetText?: string;
4544
+ /** Fired on submit with every field's value (empty strings stripped). */
4545
+ onSearch?: (values: Record<string, string>) => void;
4546
+ /** Fired on reset with the reset values (defaults re-applied). */
4547
+ onReset?: (values: Record<string, string>) => void;
4548
+ }
4549
+ /** Empty-state descriptor (iris 独有 — vxe has no empty-state action button):
4550
+ * object form of `emptyState` renders centered text (optional) plus an inline
4551
+ * action button. A plain ReactNode stays on the node path untouched. */
4552
+ interface IrisTableEmptyState {
4553
+ /** Empty-state text (falls back to the localized default when omitted). */
4554
+ text?: ReactNode;
4555
+ /** Action button rendered inline after the text. */
4556
+ action?: {
4557
+ label: string;
4558
+ onClick: () => void;
4559
+ };
4560
+ }
4561
+ /** Pager configuration (vxe-grid pagerConfig parity). */
4562
+ interface IrisTablePagerConfig {
4563
+ /** Rows-per-page options rendered as a size selector next to the pager. A
4564
+ * change re-queries with the new size and resets the page to 1. */
4565
+ pageSizes?: number[];
4566
+ /** Show the total-row count (i18n `table.total`) before the size selector (vxe pagerConfig.showTotal parity). */
4567
+ showTotal?: boolean;
4568
+ }
4569
+ /** Public input surface for the React table adapter. */
4570
+ /** Row-density preset (iris 独有 — vxe has no density concept): the three
4571
+ * tiers stack ON TOP of `size` — both write `--iris-cell-pad-y`, and the
4572
+ * density rules come later in the stylesheet (same specificity, later
4573
+ * wins). Default comfortable. */
4574
+ type IrisTableDensity = 'comfortable' | 'compact' | 'cozy';
4575
+ interface IrisTableProps<Row extends Record<string, unknown> = Record<string, unknown>> extends IrisTableLayoutProps<Row>, IrisTableEditingProps<Row>, IrisTableQueryProps<Row>, IrisTableAdvancedProps<Row> {
4576
+ }
4577
+
4578
+ /** URL-state snapshot (batch DV): the pieces `urlState` reads/writes in the
4579
+ * `_table` query param. Mirror of `IrisTablePersistedState` minus the
4580
+ * layout/expansion pieces — a deep link carries what affects served rows. */
4581
+ interface IrisTableUrlState {
4582
+ /** Wire schema version — decode rejects anything else (forward-compat). */
4583
+ v: 1;
4584
+ /** Single-column sort (omitted when inactive; null never encoded). */
4585
+ sort?: IrisTableSortState | null;
4586
+ /** Multi-column sort list (multiSort mode only, non-empty). */
4587
+ sorts?: IrisTableSortState[];
4588
+ /** Text filters (column key → filter text, non-empty map only). */
4589
+ filters?: Record<string, string>;
4590
+ /** Checked filter sets (column key → values, non-empty map only). */
4591
+ filterValues?: IrisTableFilterValues;
4592
+ /** 1-based page (proxy only; omitted when 1). */
4593
+ page?: number;
4594
+ /** Rows per page (proxy only). */
4595
+ pageSize?: number;
4596
+ }
4597
+ /** Query-param key that carries the whole payload. */
4598
+ declare const IRIS_URL_STATE_KEY = "_table";
4599
+ /** Sticky zero-height endcap: pins the button to the bottom of the scroll
4600
+ * viewport (an absolute box would ride the content — the BU watermark
4601
+ * precedent); z 3 paints above the sticky header (z 2) / pinned columns
4602
+ * (z 1) but below the floating panels. pointerEvents none — the zero-height
4603
+ * strip never eats a click. */
2906
4604
  /**
2907
4605
  * Data-driven table. Renders as a CSS-grid layout (no native `<table>`) so it
2908
4606
  * can support future virtual scroll / column resize uniformly. Wires ARIA
@@ -2910,14 +4608,23 @@ interface IrisTableProps<Row extends Record<string, unknown> = Record<string, un
2910
4608
  *
2911
4609
  * Sortable columns cycle `none → asc → desc → none` on click.
2912
4610
  */
2913
- declare function IrisTable<Row extends Record<string, unknown>>({ columns, data, rowKey, selectable, selection: selectionProp, defaultSelection, onSelectionChange, sort: sortProp, defaultSort, onSortChange, multiSort, multiSortState: multiSortStateProp, defaultMultiSort, onMultiSortChange, striped, size, seqStartIndex, seqMethod, currentRowKey, onCurrentRowChange, beforeCurrentRowChange, currentColumnKey, onCurrentColumnChange, beforeCurrentColumnChange, showHeader, footerData, rowClassName, cellClassName, headerCellClassName, footerCellClassName, rowStyle, cellStyle, headerCellStyle, footerCellStyle, onCellClick, bordered, resizableColumns, columnWidths: columnWidthsProp, defaultColumnWidths, onColumnWidthsChange, onRowClick, onCellEdit, tableRef, onDataChange, checkMethod, pagerConfig, editConfig, validConfig, rowDrag, columnDrag, columnVisibility, onColumnVisibilityChange, filters, formConfig, toolbar, tooltipConfig, contextMenu, printable, seq, spanMethod, renderDetail, rowExpandable, defaultExpandedRowKeys, expandAll, onExpandedRowsChange, getSubRows, keyboardNavigation, cellRange, checkboxRange, virtualScroll, columnVirtualization, emptyState, loading, error, loadingState, errorState, onRetry, proxyConfig, style, className, ...rest }: IrisTableProps<Row>): React.ReactElement;
4611
+ declare function IrisTable<Row extends Record<string, unknown>>({ columns, data, rowKey, selectable, selection: selectionProp, defaultSelection, onSelectionChange, sort: sortProp, defaultSort, onSortChange, multiSort, multiSortState: multiSortStateProp, defaultMultiSort, onMultiSortChange, striped, size, density, densityToggle, seqStartIndex, seqMethod, currentRowKey, onCurrentRowChange, beforeCurrentRowChange, currentColumnKey, onCurrentColumnChange, beforeCurrentColumnChange, onHeaderClick, showHeader, footerData, footerMethod, footerSpanMethod, headerAlign, footerAlign, autoDetectTypes, summaryRowStyle, aggregateAccuracy, highlightHoverRow, showHeaderOverflow, showFooterOverflow, watermark, height, minHeight, maxHeight, scrollbarConfig, scrollbarThumb, scrollToTop, headerStats, editDirtyConfig, autoResize, syncResize, responsive, keepSource, zIndex, rowId, mergeFooterItems, rowClassName, cellClassName, headerCellClassName, footerCellClassName, rowStyle, cellStyle, conditionalStyles, headerCellStyle, footerCellStyle, onCellClick, onCellDblClick, onTableEvent, bordered, round, padding, resizableColumns, widthHint, autoResizeColumns, columnWidths: columnWidthsProp, defaultColumnWidths, onColumnWidthsChange, columnWidthsReset, columnPinMenu, pinnedColumns: pinnedColumnsProp, onColumnPinnedChange, pinnedDrag, onPinnedCountChange, onRowClick, onRowDblClick, onCellEdit, onEditStart, onEditClosed, editAutosave, onAutosave, editAutoHeight, charCount, editPreview, pattern, patternFill, columnStats, columnTotals, expandScrollPreserve, shortcutHints, onSelectAllChange, onScroll, tableRef, onDataChange, checkMethod, pagerConfig, editConfig, validConfig, rowDrag, rowDragBetween, columnDrag, columnVisibility: columnVisibilityProp, onColumnVisibilityChange, columnFade, columnOrder: columnOrderProp, onColumnOrderChange, filters, onFiltersChange, filterValues, onFilterValuesChange, formConfig, toolbar, zoomConfig, importPreview, layouts, tooltipConfig, annotations, cellNote, notePopover, annotationEditing, onAnnotationsChange, exportAnnotations, presence, headerTooltipConfig, footerTooltipConfig, contextMenu, valueDistribution, nlSummary, chartPreview, autoRefresh, freshness, validationSummary, auditLog, perfStats, versionHistory, editSidebar, compareWith, mergeCompare, autoLink, recentFilters, formulaTables, exportNames, printable, seq, spanMethod, mergeHeaderCells, renderDetail, rowExpandable, defaultExpandedRowKeys, expandAll, onExpandedRowsChange, onExpandChange, onTreeExpandChange, getSubRows, lazyLoad, expandAnimation, keyboardNavigation, tableShortcuts, editKeys, keymap, hotkeyScope, outerScope, groupBy, groupCollapsed, defaultGroupCollapsed, onGroupCollapseChange, cellRange, rangeFill, cellDrag, cellDragCopy, clipConfig, pasteOptions, fnr, searchHighlight, undo, checkboxRange, selectionDrag, virtualScroll, rowHeight, adaptiveRowHeight, persistState, autoSaveState, urlState, views, onActiveViewChange, tableTabs, query, onQueryChange, columnVirtualization, emptyState, loading, error, loadingState, errorState, onRetry, proxyConfig, showCellRefs, selectionSummary, style, className, ...rest }: IrisTableProps<Row>): React.ReactElement;
2914
4612
 
2915
4613
  /**
2916
4614
  * Serialize rows as a CSV string per RFC 4180. Column order determines field
2917
4615
  * order; cell values are read via `dataIndex` (defaulting to the column key).
2918
4616
  * Returns a plain string without BOM.
4617
+ *
4618
+ * Batch AY: masked-by-default export — a column with `mask` exports the
4619
+ * masked value unless it opts out via `exportRaw`. Masking materializes each
4620
+ * masked column's value onto a shadow row at the key the serializer reads
4621
+ * (string `dataIndex`, else `key`), the batch-AO shadow-row convention;
4622
+ * formula columns are already materialized by
4623
+ * `withComputedFormulaCells` before this serializer runs, so the mask applies
4624
+ * on top. No masks → the input array is returned as-is (reference-preserving).
2919
4625
  */
2920
4626
  declare function exportCsv<Row extends Record<string, unknown>>(rows: readonly Row[], columns: readonly IrisTableColumn<Row>[]): string;
4627
+
2921
4628
  /**
2922
4629
  * Trigger a download of the given CSV string. A host `FileSaveHandler` (set via
2923
4630
  * `setFileSaveHandler`) intercepts it for native save in desktop/mobile shells;
@@ -2962,6 +4669,8 @@ interface IrisVirtualScrollProps<T = unknown> {
2962
4669
  buffer?: number;
2963
4670
  /** Stable key per item. Falls back to index. */
2964
4671
  keyOf?: (item: T, index: number) => string | number;
4672
+ /** Optional Grid Core-owned controller. When omitted, this component owns one. */
4673
+ virtualizer?: Virtualizer;
2965
4674
  /** Render a single item. */
2966
4675
  renderItem: (item: T, index: number) => React.ReactNode;
2967
4676
  onScroll?: (scrollTop: number) => void;
@@ -3044,6 +4753,39 @@ interface IrisDatePickerProps {
3044
4753
  */
3045
4754
  declare function IrisDatePicker({ value: valueProp, defaultValue, onValueChange, min, max, weekStartsOn, locale, placeholder, disabled, invalid, placement, id, ariaDescribedby, style, className, ...rest }: IrisDatePickerProps): React.ReactElement;
3046
4755
 
4756
+ /**
4757
+ * Month-only picker composed from Iris Popover primitives.
4758
+ *
4759
+ * The public value is a local-time `Date` normalized to the first day of its
4760
+ * month. The panel intentionally offers a 12-month grid rather than a native
4761
+ * month input, select, or day-level calendar.
4762
+ *
4763
+ * @example
4764
+ * <IrisMonthPicker value={month} onValueChange={setMonth} locale="en-US" />
4765
+ */
4766
+ interface IrisMonthPickerProps {
4767
+ value?: Date | null;
4768
+ defaultValue?: Date | null;
4769
+ onValueChange?: (next: Date | null) => void;
4770
+ /** Initial visible year when no value is selected. */
4771
+ defaultMonth?: Date | null;
4772
+ /** Inclusive month bounds; individual days are ignored. */
4773
+ min?: Date;
4774
+ max?: Date;
4775
+ locale?: string;
4776
+ placeholder?: string;
4777
+ disabled?: boolean;
4778
+ invalid?: boolean;
4779
+ placement?: Placement;
4780
+ /** id forwarded to the trigger. */
4781
+ id?: string;
4782
+ /** Forwarded as aria-describedby on the trigger. */
4783
+ ariaDescribedby?: string;
4784
+ style?: React.CSSProperties;
4785
+ className?: string;
4786
+ }
4787
+ declare function IrisMonthPicker({ value: valueProp, defaultValue, onValueChange, defaultMonth, min, max, locale, placeholder, disabled, invalid, placement, id, ariaDescribedby, style, className, ...rest }: IrisMonthPickerProps): React.ReactElement;
4788
+
3047
4789
  interface IrisTreeNode {
3048
4790
  /** Stable unique identifier. */
3049
4791
  id: string;
@@ -3517,4 +5259,4 @@ interface IrisCommandPaletteProps extends Omit<React.HTMLAttributes<HTMLDivEleme
3517
5259
  */
3518
5260
  declare function IrisCommandPalette({ open, onOpenChange, items, placeholder, emptyText, filter, onSelect, virtual, style, ...rest }: IrisCommandPaletteProps): React.ReactElement | null;
3519
5261
 
3520
- export { AccordionContext, type AccordionContextValue, DialogContext, type DialogContextValue, type DragState, DrawerContext, type DrawerContextValue, DropdownContext, type DropdownContextValue, IrisAccordion, IrisAccordionItem, type IrisAccordionItemProps, type IrisAccordionProps, type IrisAccordionValue, IrisAffix, type IrisAffixProps, IrisAlert, type IrisAlertProps, type IrisAlertTone, IrisAnchor, type IrisAnchorItem, type IrisAnchorProps, IrisAspectRatio, type IrisAspectRatioProps, IrisAvatar, type IrisAvatarProps, type IrisAvatarShape, type IrisAvatarSize, IrisBackTop, type IrisBackTopProps, IrisBadge, type IrisBadgeProps, type IrisBadgeSize, type IrisBadgeTone, type IrisBadgeVariant, IrisBanner, type IrisBannerProps, type IrisBannerTone, IrisBreadcrumb, IrisBreadcrumbItem, type IrisBreadcrumbItemProps, type IrisBreadcrumbProps, IrisButton, type IrisButtonProps, type IrisButtonSize, type IrisButtonType, type IrisButtonVariant, IrisCalendar, type IrisCalendarProps, IrisCard, type IrisCardPadding, type IrisCardProps, type IrisCardVariant, IrisCarousel, type IrisCarouselProps, IrisCascader, type IrisCascaderNode, type IrisCascaderProps, type IrisCascaderSize, IrisCheckbox, type IrisCheckboxProps, type IrisCheckboxSize, type IrisCheckboxValue, IrisChip, type IrisChipProps, type IrisChipSize, type IrisChipTone, type IrisChipVariant, IrisColorPicker, type IrisColorPickerProps, IrisCombobox, type IrisComboboxOption, type IrisComboboxProps, type IrisComboboxSize, type IrisCommandItem, IrisCommandPalette, type IrisCommandPaletteProps, IrisCopyButton, type IrisCopyButtonProps, type IrisCopyButtonSize, IrisCountdown, type IrisCountdownProps, type IrisCountdownSize, IrisDatePicker, type IrisDatePickerProps, type IrisDateRange, IrisDateRangePicker, type IrisDateRangePickerProps, IrisDescriptions, type IrisDescriptionsItem, type IrisDescriptionsLayout, type IrisDescriptionsProps, IrisDialog, IrisDialogClose, type IrisDialogCloseProps, IrisDialogContent, type IrisDialogContentProps, IrisDialogDescription, type IrisDialogDescriptionProps, type IrisDialogProps, IrisDialogTitle, type IrisDialogTitleProps, IrisDialogTrigger, type IrisDialogTriggerProps, IrisDivider, type IrisDividerOrientation, type IrisDividerProps, type IrisDividerSpacing, IrisDragger, type IrisDraggerBounds, type IrisDraggerPosition, type IrisDraggerProps, IrisDrawer, IrisDrawerClose, type IrisDrawerCloseProps, IrisDrawerContent, type IrisDrawerContentProps, type IrisDrawerProps, type IrisDrawerSide, IrisDrawerTitle, type IrisDrawerTitleProps, IrisDrawerTrigger, type IrisDrawerTriggerProps, IrisDropdown, IrisDropdownItem, type IrisDropdownItemProps, IrisDropdownMenu, type IrisDropdownMenuProps, type IrisDropdownProps, IrisDropdownSeparator, type IrisDropdownSeparatorProps, IrisDropdownTrigger, type IrisDropdownTriggerProps, IrisEmptyState, type IrisEmptyStateProps, IrisFieldset, type IrisFieldsetProps, IrisFileUpload, type IrisFileUploadFile, type IrisFileUploadProps, type IrisFileUploadRejectReason, type IrisFileUploadRejection, IrisFloatButton, type IrisFloatButtonAction, type IrisFloatButtonProps, type IrisFloatButtonShape, IrisFormField, type IrisFormFieldProps, IrisGauge, type IrisGaugeProps, type IrisGaugeStatus, IrisIcon, type IrisIconProps, IrisImage, type IrisImageProps, IrisInput, type IrisInputProps, type IrisInputSize, type IrisInputType, IrisKbd, type IrisKbdProps, type IrisKbdSize, IrisList, type IrisListItem, type IrisListProps, IrisMarquee, type IrisMarqueeDirection, type IrisMarqueeProps, IrisMasonry, type IrisMasonryProps, type IrisMentionOption, IrisMentions, type IrisMentionsProps, IrisMenu, IrisMenuContent, type IrisMenuContentProps, IrisMenuItem, type IrisMenuItemProps, type IrisMenuProps, IrisMenuSeparator, type IrisMenuSeparatorProps, IrisMenuSub, type IrisMenuSubProps, IrisMenuTrigger, type IrisMenuTriggerProps, IrisNumberInput, type IrisNumberInputProps, type IrisNumberInputSize, IrisOtpInput, type IrisOtpInputProps, type IrisOtpInputSize, type IrisOtpInputType, IrisPagination, type IrisPaginationProps, type IrisPaginationSize, IrisPasswordInput, type IrisPasswordInputProps, IrisPopover, IrisPopoverContent, type IrisPopoverContentProps, type IrisPopoverProps, IrisPopoverTrigger, type IrisPopoverTriggerProps, IrisProgress, IrisProgressCircle, type IrisProgressCircleProps, type IrisProgressCircleStatus, type IrisProgressProps, type IrisProgressSize, type IrisProgressTone, IrisRadio, IrisRadioGroup, type IrisRadioGroupProps, type IrisRadioProps, type IrisRadioSize, IrisRangeSlider, type IrisRangeSliderProps, type IrisRangeSliderValue, IrisRating, type IrisRatingProps, type IrisRatingSize, IrisResizer, type IrisResizerHandle, type IrisResizerProps, type IrisResizerSize, IrisResult, type IrisResultProps, type IrisResultStatus, IrisRibbon, type IrisRibbonPlacement, type IrisRibbonProps, IrisScrollArea, type IrisScrollAreaAxis, type IrisScrollAreaProps, IrisSegmented, type IrisSegmentedOption, type IrisSegmentedProps, type IrisSegmentedSize, IrisSelect, type IrisSelectItem, type IrisSelectProps, type IrisSelectSize, type IrisSelectTriggerState, IrisSkeleton, type IrisSkeletonProps, type IrisSkeletonShape, IrisSlider, type IrisSliderOrientation, type IrisSliderProps, IrisSlot, type IrisSlotProps, IrisSpinner, type IrisSpinnerProps, type IrisSpinnerSize, IrisSplitButton, type IrisSplitButtonAction, type IrisSplitButtonProps, type IrisSplitButtonSize, type IrisSplitButtonVariant, IrisSplitter, type IrisSplitterOrientation, type IrisSplitterProps, IrisStatistic, type IrisStatisticProps, type IrisStatisticSize, type IrisStatisticTrend, type IrisStepStatus, IrisStepper, type IrisStepperOrientation, type IrisStepperProps, IrisStepperStep, type IrisStepperStepProps, IrisSwitch, type IrisSwitchProps, type IrisSwitchSize, IrisTable, type IrisTableAggregateOp, type IrisTableCellClickParams, type IrisTableCellEditEvent, type IrisTableColumn, type IrisTableColumnWidths, type IrisTableContextMenuParams, type IrisTableEditor, type IrisTableFormConfig, type IrisTableFormField, type IrisTableHandle, type IrisTablePagerConfig, type IrisTableProps, type IrisTableProxyQueryParams, type IrisTableRenderDetail, type IrisTableRowExpandable, type IrisTableSeqMethodParams, type IrisTableSortDirection, type IrisTableSortState, type IrisTableTooltipConfig, type IrisTableValidConfig, type IrisTableVirtualOptions, IrisTabs, IrisTabsContent, type IrisTabsContentProps, IrisTabsList, type IrisTabsListProps, type IrisTabsOrientation, type IrisTabsProps, IrisTabsTrigger, type IrisTabsTriggerProps, IrisTagInput, type IrisTagInputProps, IrisTextarea, type IrisTextareaProps, type IrisTextareaSize, IrisTimePicker, type IrisTimePickerFormat, type IrisTimePickerProps, type IrisTimeValue, IrisTimeline, type IrisTimelineItem, type IrisTimelineProps, type IrisTimelineVariant, type IrisToast, type IrisToastInput, type IrisToastPosition, type IrisToastVariant, IrisToastViewport, type IrisToastViewportProps, IrisToggleGroup, IrisToggleGroupItem, type IrisToggleGroupItemProps, type IrisToggleGroupMultipleProps, type IrisToggleGroupOrientation, type IrisToggleGroupProps, type IrisToggleGroupSingleProps, type IrisToggleGroupSize, type IrisToggleGroupType, type IrisToggleGroupValue, type IrisToggleGroupVariant, IrisToolbar, type IrisToolbarOrientation, type IrisToolbarProps, IrisTooltip, type IrisTooltipProps, IrisTour, type IrisTourProps, type IrisTourStep, IrisTransfer, type IrisTransferItem, type IrisTransferProps, type IrisTransferVirtualOptions, IrisTree, type IrisTreeNode, type IrisTreeProps, IrisTreeSelect, type IrisTreeSelectNode, type IrisTreeSelectProps, type IrisTreeSelectSize, type IrisTreeSelectionMode, type IrisTreeVirtualOptions, IrisVirtualScroll, type IrisVirtualScrollAlign, type IrisVirtualScrollHandle, type IrisVirtualScrollProps, IrisVisuallyHidden, type IrisVisuallyHiddenProps, IrisWatermark, type IrisWatermarkProps, MenuContext, type MenuContextValue, PopoverContext, type PopoverContextValue, RadioGroupContext, type RadioGroupContextValue, StepperContext, type StepperContextValue, TabsContext, type TabsContextValue, ToggleGroupContext, type ToggleGroupContextValue, type UseDragOptions, type UseToastReturn, __PROGRESS_STYLE_ID, __SKELETON_STYLE_ID, __SPINNER_STYLE_ID, __resetProgressStyles, __resetSkeletonStyles, __resetSpinnerStyles, clearToasts, defaultFilter, dismissToast, downloadCsv, downloadExcel, exportCsv, exportExcel, formatBytes, formatRemaining, getToasts, pushToast, subscribeToasts, useAccordionContext, useDialogContext, useDisposableScope, useDrag, useDrawerContext, useDropdownContext, useMachine, useMenuContext, usePopoverContext, useReconnectingSource, useResilientFetcher, useStepperContext, useStore, useStoreSelector, useTabsContext, useToast, useToggleGroupContext };
5262
+ export { AccordionContext, type AccordionContextValue, DialogContext, type DialogContextValue, type DragState, DrawerContext, type DrawerContextValue, DropdownContext, type DropdownContextValue, IRIS_URL_STATE_KEY, IrisAccordion, IrisAccordionItem, type IrisAccordionItemProps, type IrisAccordionProps, type IrisAccordionValue, IrisAffix, type IrisAffixProps, IrisAlert, type IrisAlertProps, type IrisAlertTone, IrisAnchor, type IrisAnchorItem, type IrisAnchorProps, IrisAspectRatio, type IrisAspectRatioProps, IrisAvatar, type IrisAvatarProps, type IrisAvatarShape, type IrisAvatarSize, IrisBackTop, type IrisBackTopProps, IrisBadge, type IrisBadgeProps, type IrisBadgeSize, type IrisBadgeTone, type IrisBadgeVariant, IrisBanner, type IrisBannerProps, type IrisBannerTone, IrisBreadcrumb, IrisBreadcrumbItem, type IrisBreadcrumbItemProps, type IrisBreadcrumbProps, IrisButton, type IrisButtonProps, type IrisButtonSize, type IrisButtonType, type IrisButtonVariant, IrisCalendar, type IrisCalendarProps, IrisCard, type IrisCardPadding, type IrisCardProps, type IrisCardVariant, IrisCarousel, type IrisCarouselProps, IrisCascader, type IrisCascaderNode, type IrisCascaderProps, type IrisCascaderSize, IrisCheckbox, type IrisCheckboxProps, type IrisCheckboxSize, type IrisCheckboxValue, IrisChip, type IrisChipProps, type IrisChipSize, type IrisChipTone, type IrisChipVariant, IrisColorPicker, type IrisColorPickerProps, IrisCombobox, type IrisComboboxOption, type IrisComboboxProps, type IrisComboboxSize, type IrisCommandItem, IrisCommandPalette, type IrisCommandPaletteProps, IrisCopyButton, type IrisCopyButtonProps, type IrisCopyButtonSize, IrisCountdown, type IrisCountdownProps, type IrisCountdownSize, IrisDatePicker, type IrisDatePickerProps, type IrisDateRange, IrisDateRangePicker, type IrisDateRangePickerProps, IrisDescriptions, type IrisDescriptionsItem, type IrisDescriptionsLayout, type IrisDescriptionsProps, IrisDialog, IrisDialogClose, type IrisDialogCloseProps, IrisDialogContent, type IrisDialogContentProps, IrisDialogDescription, type IrisDialogDescriptionProps, type IrisDialogProps, IrisDialogTitle, type IrisDialogTitleProps, IrisDialogTrigger, type IrisDialogTriggerProps, IrisDivider, type IrisDividerOrientation, type IrisDividerProps, type IrisDividerSpacing, IrisDragger, type IrisDraggerBounds, type IrisDraggerPosition, type IrisDraggerProps, IrisDrawer, IrisDrawerClose, type IrisDrawerCloseProps, IrisDrawerContent, type IrisDrawerContentProps, type IrisDrawerProps, type IrisDrawerSide, IrisDrawerTitle, type IrisDrawerTitleProps, IrisDrawerTrigger, type IrisDrawerTriggerProps, IrisDropdown, IrisDropdownItem, type IrisDropdownItemProps, IrisDropdownMenu, type IrisDropdownMenuProps, type IrisDropdownProps, IrisDropdownSeparator, type IrisDropdownSeparatorProps, IrisDropdownTrigger, type IrisDropdownTriggerProps, IrisEmptyState, type IrisEmptyStateProps, IrisFieldset, type IrisFieldsetProps, IrisFileUpload, type IrisFileUploadFile, type IrisFileUploadProps, type IrisFileUploadRejectReason, type IrisFileUploadRejection, IrisFloatButton, type IrisFloatButtonAction, type IrisFloatButtonProps, type IrisFloatButtonShape, IrisFormField, type IrisFormFieldProps, IrisGauge, type IrisGaugeProps, type IrisGaugeStatus, IrisIcon, type IrisIconProps, IrisImage, type IrisImageProps, IrisInput, type IrisInputProps, type IrisInputSize, type IrisInputType, IrisKbd, type IrisKbdProps, type IrisKbdSize, IrisList, type IrisListItem, type IrisListProps, IrisMarquee, type IrisMarqueeDirection, type IrisMarqueeProps, IrisMasonry, type IrisMasonryProps, type IrisMentionOption, IrisMentions, type IrisMentionsProps, IrisMenu, IrisMenuContent, type IrisMenuContentProps, IrisMenuItem, type IrisMenuItemProps, type IrisMenuProps, IrisMenuSeparator, type IrisMenuSeparatorProps, IrisMenuSub, type IrisMenuSubProps, IrisMenuTrigger, type IrisMenuTriggerProps, IrisMonthPicker, type IrisMonthPickerProps, IrisNumberInput, type IrisNumberInputProps, type IrisNumberInputSize, IrisOtpInput, type IrisOtpInputProps, type IrisOtpInputSize, type IrisOtpInputType, IrisPagination, type IrisPaginationProps, type IrisPaginationSize, IrisPasswordInput, type IrisPasswordInputProps, IrisPopover, IrisPopoverContent, type IrisPopoverContentProps, type IrisPopoverProps, IrisPopoverTrigger, type IrisPopoverTriggerProps, IrisProgress, IrisProgressCircle, type IrisProgressCircleProps, type IrisProgressCircleStatus, type IrisProgressProps, type IrisProgressSize, type IrisProgressTone, IrisRadio, IrisRadioGroup, type IrisRadioGroupProps, type IrisRadioProps, type IrisRadioSize, IrisRangeSlider, type IrisRangeSliderProps, type IrisRangeSliderValue, IrisRating, type IrisRatingProps, type IrisRatingSize, IrisResizer, type IrisResizerHandle, type IrisResizerProps, type IrisResizerSize, IrisResult, type IrisResultProps, type IrisResultStatus, IrisRibbon, type IrisRibbonPlacement, type IrisRibbonProps, IrisScrollArea, type IrisScrollAreaAxis, type IrisScrollAreaProps, IrisSegmented, type IrisSegmentedOption, type IrisSegmentedProps, type IrisSegmentedSize, IrisSelect, type IrisSelectItem, type IrisSelectProps, type IrisSelectSize, type IrisSelectTriggerState, IrisSkeleton, type IrisSkeletonProps, type IrisSkeletonShape, IrisSlider, type IrisSliderOrientation, type IrisSliderProps, IrisSlot, type IrisSlotProps, IrisSpinner, type IrisSpinnerProps, type IrisSpinnerSize, IrisSplitButton, type IrisSplitButtonAction, type IrisSplitButtonProps, type IrisSplitButtonSize, type IrisSplitButtonVariant, IrisSplitter, type IrisSplitterOrientation, type IrisSplitterProps, IrisStatistic, type IrisStatisticProps, type IrisStatisticSize, type IrisStatisticTrend, type IrisStepStatus, IrisStepper, type IrisStepperOrientation, type IrisStepperProps, IrisStepperStep, type IrisStepperStepProps, IrisSwitch, type IrisSwitchProps, type IrisSwitchSize, IrisTable, type IrisTableAggregateOp, type IrisTableAlign, type IrisTableAuditEntry, type IrisTableAutoSaveStateConfig, type IrisTableCellClickParams, type IrisTableCellEditEvent, type IrisTableColumn, type IrisTableColumnStat, type IrisTableColumnWidths, type IrisTableConditionalStyle, type IrisTableContextMenuParams, type IrisTableCustomConfig, type IrisTableEditClosedParams, type IrisTableEditDirtyConfig, type IrisTableEditStartParams, type IrisTableEditor, type IrisTableEmptyState, type IrisTableEvent, type IrisTableFilterOption, type IrisTableFilterValues, type IrisTableFooterMethodParams, type IrisTableFooterSpanMethod, type IrisTableFooterSpanParams, type IrisTableFormConfig, type IrisTableFormField, type IrisTableHandle, type IrisTableMergeCell, type IrisTableMergeFooterItem, type IrisTableNamedView, type IrisTablePagerConfig, type IrisTablePersistConfig, type IrisTablePersistPiece, type IrisTablePersistedState, type IrisTablePresenceEntry, type IrisTableProps, type IrisTableProxyQueryParams, type IrisTableRenderDetail, type IrisTableRowDragBetweenTarget, type IrisTableRowExpandable, type IrisTableScrollParams, type IrisTableScrollbarConfig, type IrisTableSeqMethodParams, type IrisTableSortDirection, type IrisTableSortState, type IrisTableSpan, type IrisTableTab, type IrisTableTooltipConfig, type IrisTableUrlState, type IrisTableValidConfig, type IrisTableViewConfig, type IrisTableVirtualOptions, IrisTabs, IrisTabsContent, type IrisTabsContentProps, IrisTabsList, type IrisTabsListProps, type IrisTabsOrientation, type IrisTabsProps, IrisTabsTrigger, type IrisTabsTriggerProps, IrisTagInput, type IrisTagInputProps, IrisTextarea, type IrisTextareaProps, type IrisTextareaSize, IrisTimePicker, type IrisTimePickerFormat, type IrisTimePickerProps, type IrisTimeValue, IrisTimeline, type IrisTimelineItem, type IrisTimelineProps, type IrisTimelineVariant, type IrisToast, type IrisToastInput, type IrisToastPosition, type IrisToastVariant, IrisToastViewport, type IrisToastViewportProps, IrisToggleGroup, IrisToggleGroupItem, type IrisToggleGroupItemProps, type IrisToggleGroupMultipleProps, type IrisToggleGroupOrientation, type IrisToggleGroupProps, type IrisToggleGroupSingleProps, type IrisToggleGroupSize, type IrisToggleGroupType, type IrisToggleGroupValue, type IrisToggleGroupVariant, IrisToolbar, type IrisToolbarOrientation, type IrisToolbarProps, IrisTooltip, type IrisTooltipProps, IrisTour, type IrisTourProps, type IrisTourStep, IrisTransfer, type IrisTransferItem, type IrisTransferProps, type IrisTransferVirtualOptions, IrisTree, type IrisTreeNode, type IrisTreeProps, IrisTreeSelect, type IrisTreeSelectNode, type IrisTreeSelectProps, type IrisTreeSelectSize, type IrisTreeSelectionMode, type IrisTreeVirtualOptions, IrisVirtualScroll, type IrisVirtualScrollAlign, type IrisVirtualScrollHandle, type IrisVirtualScrollProps, IrisVisuallyHidden, type IrisVisuallyHiddenProps, IrisWatermark, type IrisWatermarkProps, MenuContext, type MenuContextValue, PopoverContext, type PopoverContextValue, RadioGroupContext, type RadioGroupContextValue, StepperContext, type StepperContextValue, TabsContext, type TabsContextValue, ToggleGroupContext, type ToggleGroupContextValue, type UseDragOptions, type UseToastReturn, __PROGRESS_STYLE_ID, __SKELETON_STYLE_ID, __SPINNER_STYLE_ID, __resetProgressStyles, __resetSkeletonStyles, __resetSpinnerStyles, clearToasts, defaultFilter, dismissToast, downloadCsv, downloadExcel, exportCsv, exportExcel, formatBytes, formatRemaining, getToasts, pushToast, subscribeToasts, useAccordionContext, useDialogContext, useDisposableScope, useDrag, useDrawerContext, useDropdownContext, useMachine, useMenuContext, usePopoverContext, useReconnectingSource, useResilientFetcher, useStepperContext, useStore, useStoreSelector, useTabsContext, useToast, useToggleGroupContext };