@iris-ui-kit/react 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/admin.cjs +10 -3
  2. package/dist/admin.cjs.map +1 -1
  3. package/dist/admin.js +2 -2
  4. package/dist/behaviors.cjs +45 -0
  5. package/dist/behaviors.cjs.map +1 -1
  6. package/dist/behaviors.d.cts +38 -1
  7. package/dist/behaviors.d.ts +38 -1
  8. package/dist/behaviors.js +1 -1
  9. package/dist/{chunk-AUA5GBT6.js → chunk-4VPCQ3U4.js} +28 -27
  10. package/dist/chunk-4VPCQ3U4.js.map +1 -0
  11. package/dist/{chunk-AE2TTLTK.js → chunk-6S6MZC5G.js} +11 -4
  12. package/dist/chunk-6S6MZC5G.js.map +1 -0
  13. package/dist/{chunk-OD2O3BPM.js → chunk-KRFZ5KL4.js} +4 -4
  14. package/dist/chunk-KRFZ5KL4.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-53KFLVIZ.js → chunk-QZJXMCRR.js} +3 -2
  18. package/dist/chunk-QZJXMCRR.js.map +1 -0
  19. package/dist/{chunk-APA5KNCK.js → chunk-ZE4GH2GV.js} +49 -5
  20. package/dist/chunk-ZE4GH2GV.js.map +1 -0
  21. package/dist/data.cjs +1 -0
  22. package/dist/data.cjs.map +1 -1
  23. package/dist/data.d.cts +4 -2
  24. package/dist/data.d.ts +4 -2
  25. package/dist/data.js +1 -1
  26. package/dist/floating.cjs +9 -2
  27. package/dist/floating.cjs.map +1 -1
  28. package/dist/floating.js +1 -1
  29. package/dist/index.cjs +13444 -2591
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +1992 -63
  32. package/dist/index.d.ts +1992 -63
  33. package/dist/index.js +12998 -2209
  34. package/dist/index.js.map +1 -1
  35. package/dist/modal-utils.cjs +26 -25
  36. package/dist/modal-utils.cjs.map +1 -1
  37. package/dist/modal-utils.js +1 -1
  38. package/dist/skeletons.cjs +13 -7
  39. package/dist/skeletons.cjs.map +1 -1
  40. package/dist/skeletons.js +1 -1
  41. package/package.json +2 -2
  42. package/dist/chunk-53KFLVIZ.js.map +0 -1
  43. package/dist/chunk-AE2TTLTK.js.map +0 -1
  44. package/dist/chunk-APA5KNCK.js.map +0 -1
  45. package/dist/chunk-AUA5GBT6.js.map +0 -1
  46. package/dist/chunk-OD2O3BPM.js.map +0 -1
  47. package/dist/chunk-V3KHE2WB.js.map +0 -1
package/dist/index.d.cts CHANGED
@@ -1,5 +1,6 @@
1
+ import * as _iris_ui_kit_core from '@iris-ui-kit/core';
1
2
  import { ReadonlyStore, Store, MachineEvent, Machine, MachineState, RealtimeHandlers, RealtimeOptions, RealtimeStatus, DisposableScope, ResilientFetcherOptions, ResilientFetcher, Variant, Size, Placement, SpreadsheetXmlOptions } from '@iris-ui-kit/core';
2
- 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';
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';
3
4
  export { ThemeProvider, ThemeProviderProps, UseThemeReturn, useColorScheme, useDirection, useTheme, useThemeContext, useThemeOptional } from './theme.cjs';
4
5
  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';
5
6
  export { SkinProvider, SkinProviderProps, UseSkinReturn, useSkin, useSkinContext, useSkinOptional } from './skins.cjs';
@@ -14,7 +15,7 @@ export { UseAsyncResourceOptions, UseAsyncResourceReturn, UsePaginatedResourceOp
14
15
  export { UseResourceController, useResourceController } from './resource.cjs';
15
16
  export { UseDataSource, UseGroupedView, useDataSource, useGroupedView } from './data.cjs';
16
17
  export { DATA_STATE_CLASS, DataStateNodeProps, UseDataStateReturn, __resetDataStateStyles, installDataStateStyles, useDataState, usePrefersReducedMotion } from './motion.cjs';
17
- export { IrisClickOutside, IrisClickOutsideProps, IrisHotkey, IrisHotkeyProps, IrisLongPress, IrisLongPressProps, IrisMovable, IrisMovableBounds, IrisMovablePosition, IrisMovableProps, IrisResizable, IrisResizableHandle, IrisResizableProps, IrisResizableSize, IrisSortable, IrisSortableProps, SORTABLE_ITEM_ATTR } from './behaviors.cjs';
18
+ export { IrisClickOutside, IrisClickOutsideProps, IrisCompose, IrisComposeProps, IrisHotkey, IrisHotkeyProps, IrisLongPress, IrisLongPressProps, IrisMovable, IrisMovableBounds, IrisMovablePosition, IrisMovableProps, IrisResizable, IrisResizableHandle, IrisResizableProps, IrisResizableSize, IrisSortable, IrisSortableProps, SORTABLE_ITEM_ATTR } from './behaviors.cjs';
18
19
  export { UndoStackReactiveState, useUndoStack } from './undo.cjs';
19
20
  export { UndoStack, UndoStackOptions, createUndoStack } from '@iris-ui-kit/core/undo';
20
21
  export { IrisContainer, IrisContainerMaxWidth, IrisContainerProps, IrisDashboardCard, IrisDashboardCardProps, IrisDashboardGrid, IrisDashboardGridProps, IrisGrid, IrisGridColumns, IrisGridProps, IrisHeaderLayout, IrisHeaderLayoutProps, IrisStack, IrisStackAlign, IrisStackDirection, IrisStackJustify, IrisStackProps } from './layouts.cjs';
@@ -586,6 +587,12 @@ interface IrisComboboxProps {
586
587
  ariaDescribedby?: string;
587
588
  style?: React.CSSProperties;
588
589
  className?: string;
590
+ /**
591
+ * Opt-in windowed rendering of the listbox via the core virtualizer.
592
+ * When true, only the visible window (+ buffer) of options is rendered;
593
+ * keyboard navigation scrolls the active option into view. Default false.
594
+ */
595
+ virtual?: boolean;
589
596
  }
590
597
  /**
591
598
  * Filterable single-select (searchable select): a text input that type-ahead
@@ -595,7 +602,7 @@ interface IrisComboboxProps {
595
602
  *
596
603
  * React port of {@link import('@iris-ui-kit/vue').IrisCombobox}.
597
604
  */
598
- declare function IrisCombobox({ value: valueProp, defaultValue, onValueChange, options, placeholder, disabled, invalid, size, emptyText, id, ariaDescribedby, style, className, ...rest }: IrisComboboxProps): React.ReactElement;
605
+ declare function IrisCombobox({ value: valueProp, defaultValue, onValueChange, options, placeholder, disabled, invalid, size, emptyText, id, ariaDescribedby, style, className, virtual, ...rest }: IrisComboboxProps): React.ReactElement;
599
606
 
600
607
  type IrisTimelineVariant = 'default' | 'success' | 'warning' | 'danger' | 'info';
601
608
  interface IrisTimelineItem {
@@ -725,6 +732,18 @@ interface IrisTransferItem {
725
732
  value: string;
726
733
  disabled?: boolean;
727
734
  }
735
+ /** Opt-in windowed rendering of a pane's list (mirrors `IrisTableVirtualOptions`). */
736
+ interface IrisTransferVirtualOptions {
737
+ /** Per-item height in px (uniform). */
738
+ itemHeight: number;
739
+ /**
740
+ * Viewport height. Number → px; string → CSS length. Defaults to the pane's
741
+ * intrinsic list height (200px).
742
+ */
743
+ height?: number | string;
744
+ /** Extra rows rendered above and below the viewport. */
745
+ buffer?: number;
746
+ }
728
747
  interface IrisTransferProps {
729
748
  options: IrisTransferItem[];
730
749
  /** Values currently in the target (selected) pane. */
@@ -736,6 +755,11 @@ interface IrisTransferProps {
736
755
  /** Show a search box per pane. */
737
756
  searchable?: boolean;
738
757
  disabled?: boolean;
758
+ /**
759
+ * Opt-in windowed rendering of both pane lists via the core virtualizer
760
+ * (10k+ options stay smooth). Off by default — the plain path is unchanged.
761
+ */
762
+ virtual?: IrisTransferVirtualOptions;
739
763
  style?: React.CSSProperties;
740
764
  className?: string;
741
765
  }
@@ -747,7 +771,7 @@ interface IrisTransferProps {
747
771
  *
748
772
  * React port of {@link import('@iris-ui-kit/vue').IrisTransfer}.
749
773
  */
750
- declare function IrisTransfer({ options, value: valueProp, defaultValue, onValueChange, titles, searchable, disabled, style, className, ...rest }: IrisTransferProps): React.ReactElement;
774
+ declare function IrisTransfer({ options, value: valueProp, defaultValue, onValueChange, titles, searchable, disabled, virtual, style, className, ...rest }: IrisTransferProps): React.ReactElement;
751
775
 
752
776
  interface IrisWatermarkProps {
753
777
  /** Watermark text, tiled across the area. */
@@ -890,6 +914,13 @@ interface IrisMentionsProps {
890
914
  disabled?: boolean;
891
915
  invalid?: boolean;
892
916
  rows?: number;
917
+ /**
918
+ * Opt-in windowed rendering of the suggestion listbox via the core
919
+ * virtualizer. When true, only the visible window (+ buffer) of options is
920
+ * rendered; keyboard navigation scrolls the active option into view and
921
+ * every keystroke re-anchors the window to the top. Default false.
922
+ */
923
+ virtual?: boolean;
893
924
  /** id forwarded to the textarea. Set by `IrisFormField`. */
894
925
  id?: string;
895
926
  ariaDescribedby?: string;
@@ -904,7 +935,7 @@ interface IrisMentionsProps {
904
935
  *
905
936
  * React port of {@link import('@iris-ui-kit/vue').IrisMentions}.
906
937
  */
907
- declare function IrisMentions({ value, defaultValue, onValueChange, options, prefix, placeholder, disabled, invalid, rows, id, ariaDescribedby, style, className, ...rest }: IrisMentionsProps): React.ReactElement;
938
+ declare function IrisMentions({ value, defaultValue, onValueChange, options, prefix, placeholder, disabled, invalid, rows, virtual, id, ariaDescribedby, style, className, ...rest }: IrisMentionsProps): React.ReactElement;
908
939
 
909
940
  type IrisCascaderSize = 'sm' | 'md' | 'lg';
910
941
  interface IrisCascaderNode {
@@ -925,6 +956,12 @@ interface IrisCascaderProps {
925
956
  /** Separator between path labels in the trigger. */
926
957
  separator?: string;
927
958
  size?: IrisCascaderSize;
959
+ /**
960
+ * Opt-in: window each open column with the core virtualizer instead of
961
+ * rendering every option. Fixed deterministic sizing (viewport 240px, row
962
+ * height per size, buffer 4). Default false — no behavior change.
963
+ */
964
+ virtual?: boolean;
928
965
  id?: string;
929
966
  ariaDescribedby?: string;
930
967
  style?: React.CSSProperties;
@@ -938,7 +975,7 @@ interface IrisCascaderProps {
938
975
  *
939
976
  * React port of {@link import('@iris-ui-kit/vue').IrisCascader}.
940
977
  */
941
- declare function IrisCascader({ options, value, defaultValue, onValueChange, placeholder, disabled, invalid, separator, size, id, ariaDescribedby, style, className, ...rest }: IrisCascaderProps): React.ReactElement;
978
+ declare function IrisCascader({ options, value, defaultValue, onValueChange, placeholder, disabled, invalid, separator, size, virtual, id, ariaDescribedby, style, className, ...rest }: IrisCascaderProps): React.ReactElement;
942
979
 
943
980
  type IrisSegmentedSize = 'sm' | 'md' | 'lg';
944
981
  interface IrisSegmentedOption {
@@ -2295,11 +2332,31 @@ interface IrisSelectItem<T = unknown> {
2295
2332
  }
2296
2333
 
2297
2334
  type IrisSelectSize = Size;
2335
+ /**
2336
+ * State handed to `renderTrigger`. Additive superset of the historical
2337
+ * `{ value, label, open }` — existing destructuring callers keep compiling.
2338
+ */
2339
+ interface IrisSelectTriggerState<T = unknown> {
2340
+ value: T | undefined;
2341
+ label: string;
2342
+ open: boolean;
2343
+ /** Forwarded from the `id` prop; set by `IrisFormField`. */
2344
+ id?: string;
2345
+ /** Forwarded from the `ariaDescribedby` prop; set by `IrisFormField`. */
2346
+ ariaDescribedby?: string;
2347
+ /** Always present; `true` when the FormField (or caller) marks invalid. */
2348
+ invalid: boolean;
2349
+ /** Always present; `true` when the select is disabled. */
2350
+ disabled: boolean;
2351
+ }
2298
2352
  interface IrisSelectProps<T = unknown> {
2299
2353
  items: IrisSelectItem<T>[];
2300
- value?: T;
2301
- defaultValue?: T;
2302
- onValueChange?: (value: T) => void;
2354
+ /** Single value, or an array when `multiple`. */
2355
+ value?: T | T[];
2356
+ defaultValue?: T | T[];
2357
+ onValueChange?: (value: T | T[]) => void;
2358
+ /** Allow selecting multiple options (values become arrays). */
2359
+ multiple?: boolean;
2303
2360
  placeholder?: string;
2304
2361
  size?: IrisSelectSize;
2305
2362
  disabled?: boolean;
@@ -2309,14 +2366,17 @@ interface IrisSelectProps<T = unknown> {
2309
2366
  id?: string;
2310
2367
  /** Forwarded as `aria-describedby` on the trigger. Set by `IrisFormField`. */
2311
2368
  ariaDescribedby?: string;
2312
- /** Custom render for the trigger button. Receives current label + open state. */
2313
- renderTrigger?: (state: {
2314
- value: T | undefined;
2315
- label: string;
2316
- open: boolean;
2317
- }) => React.ReactNode;
2369
+ /** Custom render for the trigger button. Receives label + open state plus
2370
+ * the form wiring (`id` / `ariaDescribedby` / `invalid` / `disabled`). */
2371
+ renderTrigger?: (state: IrisSelectTriggerState<T>) => React.ReactNode;
2318
2372
  style?: React.CSSProperties;
2319
2373
  className?: string;
2374
+ /**
2375
+ * Opt-in windowed rendering of the listbox via the core virtualizer.
2376
+ * When true, only the visible window (+ buffer) of options is rendered;
2377
+ * keyboard navigation scrolls the active option into view. Default false.
2378
+ */
2379
+ virtual?: boolean;
2320
2380
  }
2321
2381
  /**
2322
2382
  * Single-select dropdown. Composes Popover (positioning + dismiss) with an
@@ -2331,32 +2391,55 @@ interface IrisSelectProps<T = unknown> {
2331
2391
  * placeholder="Pick a fruit"
2332
2392
  * />
2333
2393
  */
2334
- declare function IrisSelect<T = unknown>({ items, value: valueProp, defaultValue, onValueChange, placeholder, size, disabled, placement, invalid, id, ariaDescribedby, renderTrigger, style, className, ...rest }: IrisSelectProps<T>): React.ReactElement;
2394
+ 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;
2335
2395
 
2336
- type IrisTableSortDirection = 'asc' | 'desc';
2337
- /** Map of column key → current width in px (after any resizing). */
2338
- type IrisTableColumnWidths = Record<string, number>;
2339
- type IrisTableEditor = 'text' | 'number';
2340
- /** Aggregation op for a column's summary/footer cell. */
2341
- type IrisTableAggregateOp = 'sum' | 'avg' | 'min' | 'max' | 'count';
2342
- interface IrisTableVirtualOptions {
2343
- /** Per-row height in px (uniform). */
2344
- itemHeight: number;
2345
- /** Viewport height. Number → px; string → CSS length. */
2346
- height: number | string;
2347
- /** Extra rows rendered above and below the viewport. */
2348
- buffer?: number;
2349
- }
2350
- interface IrisTableSortState {
2351
- key: string;
2352
- direction: IrisTableSortDirection;
2353
- }
2354
2396
  interface IrisTableColumn<Row = Record<string, unknown>> {
2355
2397
  key: string;
2356
2398
  title: string;
2399
+ /** Icon/content rendered before the header title (vxe title-prefix parity). */
2400
+ titlePrefix?: React.ReactNode;
2401
+ /** Icon/content rendered after the header title (vxe title-suffix parity). */
2402
+ titleSuffix?: React.ReactNode;
2357
2403
  /** Path inside the row to read the cell value from. Defaults to `key`. */
2358
2404
  dataIndex?: keyof Row | string;
2405
+ /**
2406
+ * Single-line cell formula (batch AO, iris 独有 — vxe has no computed
2407
+ * columns; the closest is a display-only formatter). Evaluated by the core
2408
+ * `evaluateFormula` parser against each row: field refs + `+ - * / %` +
2409
+ * whitelist functions SUM/AVG/MIN/MAX/COUNT (case-insensitive), optional
2410
+ * leading `=`. The COMPUTED value feeds every data consumer — cell render,
2411
+ * sorting, filtering, grouping, summary, range stats, clipboard and CSV
2412
+ * export. Errors / unknown fields → null (empty cell). An `editable`
2413
+ * formula column is DISPLAY-ONLY: inline editing, row mode and batch edit
2414
+ * ignore it. Overrides `dataIndex` / `sortBy`. Leading `=` optional.
2415
+ */
2416
+ formula?: string;
2359
2417
  sortable?: boolean;
2418
+ /** Sort by another field (vxe sort-by parity): the comparator reads this
2419
+ * field instead of the column's own value. */
2420
+ sortBy?: string;
2421
+ /** Force the sort type (vxe sort-type parity). Default `'auto'` (numbers
2422
+ * compare numerically, everything else as strings). */
2423
+ sortType?: 'number' | 'string' | 'auto';
2424
+ /** Custom client-side filter (vxe filter-method parity). Return true to
2425
+ * keep the row. Overrides the default case-insensitive substring match. */
2426
+ filterMethod?: (value: unknown, row: Row, filterValue: string) => boolean;
2427
+ /** Single-select filter (vxe filter-multiple parity). The current filter
2428
+ * UI is value-based (one value per column), so this is the default. */
2429
+ filterMultiple?: boolean;
2430
+ /** Render the cell value as HTML (vxe type=html parity). Opt-in only —
2431
+ * the value is injected with `dangerouslySetInnerHTML`; ensure the content
2432
+ * is trusted to avoid XSS. */
2433
+ html?: boolean;
2434
+ /** Render the cell value as a link (vxe... no direct parity, batch L): return
2435
+ * `{ href, label?, target? }` or a plain href string; `null`/`undefined` falls
2436
+ * through to the formatter/raw value. The anchor text is `label` when given,
2437
+ * otherwise the formatted (or raw) text; `target: '_blank'` adds `rel="noreferrer"`. */
2438
+ link?: (value: unknown, row: Row) => {
2439
+ href: string;
2440
+ label?: string;
2441
+ target?: string;
2442
+ } | string | null;
2360
2443
  width?: number | string;
2361
2444
  /** Minimum width (px) when resizing. Default 60. */
2362
2445
  minWidth?: number;
@@ -2369,6 +2452,59 @@ interface IrisTableColumn<Row = Record<string, unknown>> {
2369
2452
  editable?: boolean;
2370
2453
  /** Editor kind. Default `'text'`. */
2371
2454
  editor?: IrisTableEditor;
2455
+ /**
2456
+ * Lock this column's cells against editing (batch BE, iris 独有 — vxe has
2457
+ * no cell-lock concept): `true` locks every cell of the column; a
2458
+ * predicate receives the row (and column) and returns whether THAT cell is
2459
+ * locked — a predicate ignoring its column argument is a row-level lock
2460
+ * (both levels share this one field). Locked cells are not editable —
2461
+ * every editing entry point no-ops (dblclick / click trigger / F2 / Tab
2462
+ * nav / row mode / batch edit / paste / fill / range clear / FNR replace /
2463
+ * Delete shortcut) — render with a striped background and
2464
+ * `data-iris-cell-locked="true"`, and stay fully interactive for
2465
+ * selection, copy and export.
2466
+ */
2467
+ locked?: boolean | ((row: Row, column: IrisTableColumn<Row>) => boolean);
2468
+ /**
2469
+ * Cell permission predicate (batch BJ, iris 独有 — vxe has no per-cell
2470
+ * permission concept): return `'readonly'` to make THAT cell read-only
2471
+ * through every editing entry point (dblclick / click trigger / F2 / Tab
2472
+ * nav / row mode / batch edit / paste / fill / range clear / FNR replace /
2473
+ * Delete shortcut); `'editable'` or absent → editable (default). DYNAMIC —
2474
+ * re-evaluated on every render (unlike `locked`, which is a static
2475
+ * declaration): permission follows the current row/column state without a
2476
+ * re-mount. Readonly cells render with a dotted texture and
2477
+ * `data-iris-cell-readonly="true"` (distinct from locked's 45° stripes),
2478
+ * and stay fully interactive for selection, copy and export. When a cell is
2479
+ * both locked and readonly, locked wins visually (stripes + not-allowed).
2480
+ */
2481
+ cellPermission?: (row: Row, column: IrisTableColumn<Row>) => 'readonly' | 'editable';
2482
+ /** Batch AN column preset (iris 独有): fills display defaults from the core
2483
+ * factory — `'money'` (2 decimals + thousands separator, right-aligned,
2484
+ * number editor + numeric editRules), `'progress'` (percent text, right),
2485
+ * `'date'` (String passthrough, left), `'status'` (UPPERCASE text, center).
2486
+ * User fields always win over the preset defaults (defined-fields-only
2487
+ * merge); localized formatting stays the caller's job. */
2488
+ preset?: _iris_ui_kit_core.ColumnPreset;
2489
+ /**
2490
+ * Native datalist suggestions while editing (batch AM, iris 独有): `true`
2491
+ * builds the option list from the DISTINCT cell values of this column over
2492
+ * the current body data (String-coerced, null/'' excluded, sorted, capped at
2493
+ * 50); an explicit array of `string | number` is used verbatim. Text editor
2494
+ * only — the number/select/textarea editors ignore it. */
2495
+ suggest?: boolean | Array<string | number>;
2496
+ /**
2497
+ * Options for the `'select'` editor (vxe edit-render options parity). A
2498
+ * column with `editor: 'select'` renders a native `<select>` while editing;
2499
+ * each option commits its TYPED value — a number option commits a number,
2500
+ * a string option a string (matched by `String(value)`). When the current
2501
+ * cell value matches no option, a synthetic option preserves it so a plain
2502
+ * blur never silently replaces it.
2503
+ */
2504
+ editOptions?: Array<{
2505
+ value: string | number;
2506
+ label: string;
2507
+ }>;
2372
2508
  /**
2373
2509
  * Validate a draft value before it commits. Return an error message to
2374
2510
  * REJECT the edit (the editor stays open, shows the message, and is marked
@@ -2376,6 +2512,12 @@ interface IrisTableColumn<Row = Record<string, unknown>> {
2376
2512
  * value (a number for the `'number'` editor) and the row being edited.
2377
2513
  */
2378
2514
  validate?: (value: unknown, row: Row) => string | null | undefined;
2515
+ /**
2516
+ * Declarative edit rules (vxe-grid editRules parity) evaluated on commit —
2517
+ * `required` / `min` / `max` / `type` / `pattern` / `validator` (sync or
2518
+ * async). Rules run first; the legacy `validate` callback runs after.
2519
+ */
2520
+ editRules?: _iris_ui_kit_core.EditRule<Row>[];
2379
2521
  /**
2380
2522
  * Aggregate this column in the table's summary/footer row. Any column with a
2381
2523
  * `summary` op makes the footer row appear; columns without one render blank.
@@ -2396,6 +2538,302 @@ interface IrisTableColumn<Row = Record<string, unknown>> {
2396
2538
  sorter?: (a: Row, b: Row) => number;
2397
2539
  /** Custom render for cell content. */
2398
2540
  render?: (value: unknown, row: Row, rowIndex: number) => React.ReactNode;
2541
+ /** Format a cell's value for display (vxe formatter parity, batch I). Applied AFTER
2542
+ * `render`/`html` and BEFORE the raw value; sorting, filtering, editing and summary
2543
+ * keep reading the RAW value. The tooltip defaults to the formatted text when it is
2544
+ * a string. With `clipConfig.copyWithFormat` (batch CU, iris 独有) the range copy
2545
+ * (Ctrl/Cmd+C / toolbar 复制) carries this formatted text instead of the raw value. */
2546
+ formatter?: (value: unknown, row: Row) => React.ReactNode;
2547
+ /** Mask this column's value for display (batch AY, iris 独有 — vxe has no
2548
+ * built-in masking): `'sensitive'` applies the core `maskValue` sensitive
2549
+ * rule (email → 11-digit phone → generic); a custom function receives the
2550
+ * RAW cell value and returns the masked string. Applied FIRST in the
2551
+ * display chain — `render`/`html`/`link`/`formatter`/tooltip all see the
2552
+ * masked value (a `formatter` receives the masked STRING); inline editing,
2553
+ * validation, sorting, filtering, summary, range stats and conditional
2554
+ * styles keep reading the RAW value. Export/copy mask by default unless
2555
+ * `exportRaw` is set. */
2556
+ mask?: 'sensitive' | ((value: unknown) => string);
2557
+ /** Export/copy the RAW value instead of the masked one (batch AY): when
2558
+ * true, `exportCsv`/`exportCurrentViewCsv`/`exportSelectionCsv` and the
2559
+ * clipboard TSV skip this column's mask. Display keeps masking. */
2560
+ exportRaw?: boolean;
2561
+ /**
2562
+ * Render this numeric column's cells as a mini trend line (batch BI, iris
2563
+ * 独有 — vxe has no sparkline): each cell shows a 20×8 SVG polyline of the
2564
+ * column's values over `filteredData[0..i]` INCLUSIVE (the current value is
2565
+ * the final point), so sorting/filtering reorder and trim the series.
2566
+ * Only cells whose RAW value is a finite number render an SVG (non-numeric
2567
+ * cells render nothing); series points coerce like `buildChartData`
2568
+ * (null/non-finite → gap). Wins over `render`/`html`/`link`/`formatter`/
2569
+ * raw; mask, editing, copy/export and summary stay untouched. The cell
2570
+ * `title` shows the series ("10, 4, 8") instead of the tooltip.
2571
+ */
2572
+ sparkline?: boolean;
2573
+ /** Show a header filter trigger + checkbox panel (vxe filterConfig parity, batch I).
2574
+ * Filtering OR-matches the raw `String(value)` against the checked set. */
2575
+ filterable?: boolean;
2576
+ /** Checkbox options for the filter panel; a column without options can't filter. */
2577
+ filterOptions?: IrisTableFilterOption[];
2578
+ /**
2579
+ * Group the body by this column's value (vxe group-config parity, batch M):
2580
+ * a group header row per distinct value (first-appearance order,
2581
+ * `data-iris-group-row`) showing the value + count, then that group's rows,
2582
+ * then a per-group summary row (`data-iris-group-summary`, same `summary`
2583
+ * ops as the footer computed over the group's rows) when any column has a
2584
+ * `summary` op. Flat mode only — tree mode ignores grouping (fail-closed);
2585
+ * proxy mode groups per loaded page. Only the first `groupBy` column drives
2586
+ * the plan — unless the table-level `groupBy?: string[]` (batch BS) is set,
2587
+ * which wins and drives nested multi-column grouping instead. Group headers are collapsible (batch BH, iris 独有): the
2588
+ * `data-iris-group-toggle` button collapses the group (rows + per-group
2589
+ * summary hidden, header + count stay) via `groupCollapsed` /
2590
+ * `defaultGroupCollapsed` / `onGroupCollapseChange`.
2591
+ */
2592
+ groupBy?: boolean;
2593
+ /** Hide this column entirely (vxe column visibleMethod parity, batch U): a
2594
+ * predicate evaluated in the display-columns memo (at most once per
2595
+ * render); `false` hides the column even when `columnVisibility` says
2596
+ * visible (the column's own veto wins). Absent / `true` keeps it. Scope
2597
+ * mirrors `columnVisibility`: top-level columns only — a grouped column's
2598
+ * leaf `visibleMethod` is not consulted (same documented simplification). */
2599
+ visibleMethod?: () => boolean;
2600
+ }
2601
+
2602
+ /**
2603
+ * One named view preset (batch AH, iris 独有): a user-saved snapshot of the
2604
+ * table's persistable state pieces — the SAME shape `persistState` loads and
2605
+ * saves, captured by the same collector and applied through the same change
2606
+ * callbacks.
2607
+ */
2608
+ interface IrisTableNamedView {
2609
+ /** View name (also the view's key in the toolbar select). */
2610
+ name: string;
2611
+ /** The state pieces captured when the view was saved. */
2612
+ snapshot: IrisTablePersistedState;
2613
+ }
2614
+ /**
2615
+ * Named view presets (batch AH, iris 独有 — vxe has no equivalent; its
2616
+ * closest is manual state saving). The toolbar renders a compact select
2617
+ * (`data-iris-table-views`) of user-saved snapshots: picking a view replays
2618
+ * its snapshot through the change callbacks (same per-piece gating as
2619
+ * `persistState`; `pageSize` reproduces the mount-restore sequence
2620
+ * `onPageChange(1, size)` + one request); the "+ 保存" item opens an inline
2621
+ * input (`data-iris-views-save`) that snapshots the CURRENT pieces under a
2622
+ * typed name (duplicate names upsert); the × button deletes the active view.
2623
+ * Views load from storage on mount with the same guards as `persistState`
2624
+ * and persist on every change; `activeKey` is controlled-only (never
2625
+ * persisted).
2626
+ */
2627
+ interface IrisTableViewConfig {
2628
+ /** Storage adapter (`getItem`/`setItem`; defaults to `localStorage`).
2629
+ * `false` keeps views in-memory only — no reads, no writes. */
2630
+ storage?: Pick<Storage, 'getItem' | 'setItem'> | false;
2631
+ /** Storage key. Default `'iris-table-views'`. */
2632
+ key?: string;
2633
+ /** Label formatter for a view name (rendered in the toolbar select). */
2634
+ label?: (name: string) => string;
2635
+ /** Controlled active view key; omit for uncontrolled (internal state). */
2636
+ activeKey?: string | null;
2637
+ }
2638
+
2639
+ type IrisTableSortDirection = 'asc' | 'desc';
2640
+ /** Map of column key → current width in px (after any resizing). */
2641
+ type IrisTableColumnWidths = Record<string, number>;
2642
+ /**
2643
+ * Custom column panel options (vxe-grid customConfig parity, batch S): the
2644
+ * toolbar `columnSettings` button opens the full panel — search, drag reorder,
2645
+ * visibility toggles and reset — in place of the plain checkbox menu.
2646
+ */
2647
+ interface IrisTableCustomConfig {
2648
+ /** Reset button label; defaults to the i18n `table.customConfig.reset` key. */
2649
+ resetText?: string;
2650
+ }
2651
+ type IrisTableEditor = 'text' | 'number' | 'select' | 'textarea';
2652
+ /** One checkbox option of a filterable column's filter panel (vxe filter-option parity). */
2653
+ interface IrisTableFilterOption {
2654
+ value: string;
2655
+ label: string;
2656
+ }
2657
+ /**
2658
+ * Per-column checked filter sets (vxe filter-multiple parity): column key →
2659
+ * values OR-matched against the raw `String(value)` of each row. Controlled
2660
+ * through `IrisTableProps.filterValues` / `onFilterValuesChange`.
2661
+ */
2662
+ type IrisTableFilterValues = Record<string, string[]>;
2663
+ /** Aggregation op for a column's summary/footer cell. */
2664
+ type IrisTableAggregateOp = 'sum' | 'avg' | 'min' | 'max' | 'count';
2665
+ /** Horizontal cell alignment (vxe align / header-align / footer-align parity). */
2666
+ type IrisTableAlign = 'left' | 'center' | 'right';
2667
+ interface IrisTableVirtualOptions {
2668
+ /** Per-row height in px (uniform), or a `(index) => px` function for known
2669
+ * variable heights (batch AG — the iris take on vxe `virtualYConfig` 增强
2670
+ * 模式; the fn receives the virtual PLAN index — memoize it). */
2671
+ itemHeight: number | ((index: number) => number);
2672
+ /** Viewport height. Number → px; string → CSS length. */
2673
+ height: number | string;
2674
+ /** Extra rows rendered above and below the viewport. */
2675
+ buffer?: number;
2676
+ }
2677
+ /** State pieces persistable via `persistState` (batch AG, iris 独有). */
2678
+ type IrisTablePersistPiece = 'sort' | 'multiSortState' | 'filters' | 'filterValues' | 'columnVisibility' | 'columnOrder' | 'columnWidths' | 'pageSize' | 'expandedKeys';
2679
+ /** One persisted state snapshot (batch AG): the pieces `persistState` loads
2680
+ * and saves, keyed by piece name — a piece appears only when defined + included. */
2681
+ interface IrisTablePersistedState {
2682
+ sort?: IrisTableSortState | null;
2683
+ multiSortState?: IrisTableSortState[];
2684
+ filters?: Record<string, string>;
2685
+ filterValues?: IrisTableFilterValues;
2686
+ columnVisibility?: Record<string, boolean>;
2687
+ columnOrder?: string[];
2688
+ columnWidths?: IrisTableColumnWidths;
2689
+ pageSize?: number;
2690
+ /** Batch BY: expanded row keys (detail panels + tree carets) captured by
2691
+ * the shared collector when `onExpandedRowsChange` is set and the table
2692
+ * actually expands (renderDetail or tree mode); restored through the
2693
+ * expansion model — `expansion.set` commits and replays
2694
+ * `onExpandedRowsChange(keys)` (expansion has no controlled prop, so the
2695
+ * callback is the parent-owned channel). Row keys are STRINGIFIED at the
2696
+ * model boundary, so the stored array is always strings; the snapshot
2697
+ * accepts raw keys and the restore coerces them. Stale keys (rows not
2698
+ * loaded yet) are fail-inert — the row simply renders expanded when it
2699
+ * arrives. */
2700
+ expandedKeys?: Array<string | number>;
2701
+ /** Batch AJ: natural-language query captured by the named-views collector
2702
+ * when `query` is set; restored FIRST via `onQueryChange` on view apply
2703
+ * (persistState path stays byte-identical; legacy views load unchanged). */
2704
+ query?: string;
2705
+ }
2706
+ /**
2707
+ * `persistState` configuration (batch AG, iris 独有 — vxe has no built-in
2708
+ * state persistence). Persists view state (sort / filters / column layout /
2709
+ * page size) to a storage adapter so a table remounts where the user left it.
2710
+ * The table is CONTROLLED: restore replays through the change callbacks and
2711
+ * saves serialize the current props on every change.
2712
+ */
2713
+ interface IrisTablePersistConfig {
2714
+ /** Storage adapter (`getItem`/`setItem`; defaults to `localStorage`).
2715
+ * `false` fully disables persistence — no reads, no writes. */
2716
+ storage?: Pick<Storage, 'getItem' | 'setItem'> | false;
2717
+ /** Storage key. Default `'iris-table-state'`. */
2718
+ key?: string;
2719
+ /** Pieces to persist. Defaults to ALL pieces. */
2720
+ include?: Array<IrisTablePersistPiece>;
2721
+ }
2722
+ /** Periodic full view-state snapshots (batch DM, iris 独有). Unlike
2723
+ * `persistState`, this config owns a separate timer/key and writes the same
2724
+ * JSON shape exposed by `tableRef.exportStateJson()`. */
2725
+ interface IrisTableAutoSaveStateConfig {
2726
+ /** Positive interval in milliseconds; zero/invalid values disable the timer. */
2727
+ intervalMs?: number;
2728
+ /** Storage adapter; defaults to `localStorage` when available. `false` disables IO. */
2729
+ storage?: Pick<Storage, 'getItem' | 'setItem'> | false;
2730
+ /** Storage key. Defaults to `'iris-table-auto-state'`. */
2731
+ key?: string;
2732
+ }
2733
+ /** One external drop target for rowDragBetween (batch DQ). */
2734
+ interface IrisTableRowDragBetweenTarget<Row extends Record<string, unknown> = Record<string, unknown>> {
2735
+ /** Value read from the target element's `data-iris-drop-zone` attribute. */
2736
+ key: string;
2737
+ /** Called once with the dragged row when it is released over that target. */
2738
+ onDrop: (row: Row) => void;
2739
+ }
2740
+
2741
+ /**
2742
+ * One table tab (batch CT, iris 独有 — vxe has no parity): a named tab in
2743
+ * the `tableTabs` strip rendered ABOVE the toolbar. Clicking the tab applies
2744
+ * each view name in `views` IN ORDER through the SAME `selectView` path the
2745
+ * toolbar select uses — unknown names are skipped fail-inert, and when
2746
+ * several views touch the same state piece the LAST applied view wins (the
2747
+ * toolbar select then mirrors that last view). An empty `views` array
2748
+ * renders an inert tab; without the `views` config the whole strip is inert.
2749
+ */
2750
+ interface IrisTableTab {
2751
+ /** Tab key (identity — the first occurrence wins on duplicates). */
2752
+ key: string;
2753
+ /** Tab label. */
2754
+ label: string;
2755
+ /** Named views applied in order on click; omitted → inert tab. */
2756
+ views?: string[];
2757
+ }
2758
+ interface IrisTableSortState {
2759
+ key: string;
2760
+ direction: IrisTableSortDirection;
2761
+ }
2762
+ /**
2763
+ * One search-form field (vxe-grid formConfig items parity). On submit the
2764
+ * field's value merges into the table filters under `key` (client-side path
2765
+ * or the proxy query); empty strings are inactive and stripped.
2766
+ */
2767
+ interface IrisTableFormField {
2768
+ /** Filter key — matched against column keys and the query `filters` map. */
2769
+ key: string;
2770
+ /** Visible field label. */
2771
+ label: string;
2772
+ /** Control kind. Default `'text'`. */
2773
+ type?: 'text' | 'select';
2774
+ /** Options when `type: 'select'`. */
2775
+ options?: Array<{
2776
+ value: string;
2777
+ label: string;
2778
+ }>;
2779
+ placeholder?: string;
2780
+ /** Initial value; reset restores it. */
2781
+ defaultValue?: string;
2782
+ }
2783
+ /** Params delivered to `IrisTableProps.proxyConfig.query` (vxe proxyConfig parity). */
2784
+ interface IrisTableProxyQueryParams {
2785
+ /** 1-based page number. */
2786
+ page: number;
2787
+ pageSize: number;
2788
+ sort: IrisTableSortState | null;
2789
+ /**
2790
+ * Multi-column sort (vxe sort-config.multiple parity), most-significant
2791
+ * first. Present only in multiSort mode — single mode keeps passing `sort`.
2792
+ */
2793
+ sorts?: IrisTableSortState[];
2794
+ filters: Record<string, string>;
2795
+ }
2796
+ /**
2797
+ * Edit-validation presentation (vxe-grid ValidConfig parity).
2798
+ */
2799
+ interface IrisTableValidConfig {
2800
+ /**
2801
+ * Render the inline editor error message (`data-iris-table-editor-error`).
2802
+ * `false` still runs validation and blocks the commit — only the message
2803
+ * element is skipped (`aria-invalid` stays). Default true.
2804
+ */
2805
+ showMessage?: boolean;
2806
+ }
2807
+ /** Params delivered to `IrisTableProps.seqMethod` (vxe seqMethod parity). */
2808
+ interface IrisTableSeqMethodParams {
2809
+ rowIndex: number;
2810
+ columnIndex: number;
2811
+ }
2812
+ /** Coordinates delivered to `IrisTableProps.onCellClick` (vxe cell-click parity). */
2813
+ interface IrisTableCellClickParams<Row = Record<string, unknown>> {
2814
+ row: Row;
2815
+ column: IrisTableColumn<Row>;
2816
+ rowIndex: number;
2817
+ columnIndex: number;
2818
+ }
2819
+ /**
2820
+ * Coordinates delivered to `IrisTableProps.contextMenu` callbacks (vxe
2821
+ * context-menu event params parity): the row/column under the cursor and its
2822
+ * grid position.
2823
+ */
2824
+ interface IrisTableContextMenuParams<Row = Record<string, unknown>> {
2825
+ row: Row;
2826
+ column: IrisTableColumn<Row>;
2827
+ rowIndex: number;
2828
+ columnIndex: number;
2829
+ }
2830
+
2831
+ /** Params delivered to `IrisTableProps.footerMethod` (vxe footer-method parity). */
2832
+ interface IrisTableFooterMethodParams<Row = Record<string, unknown>> {
2833
+ /** Leaf columns of the table (grouped headers flattened). */
2834
+ columns: IrisTableColumn<Row>[];
2835
+ /** Full body rows (sorted + filtered). */
2836
+ data: Row[];
2399
2837
  }
2400
2838
  interface IrisTableCellEditEvent<Row = Record<string, unknown>> {
2401
2839
  row: Row;
@@ -2404,13 +2842,879 @@ interface IrisTableCellEditEvent<Row = Record<string, unknown>> {
2404
2842
  newValue: unknown;
2405
2843
  rowIndex: number;
2406
2844
  }
2845
+ /** Params delivered to `IrisTableProps.onEditStart` (vxe edit-activated parity, batch V). */
2846
+ interface IrisTableEditStartParams<Row = Record<string, unknown>> {
2847
+ row: Row;
2848
+ column: IrisTableColumn<Row>;
2849
+ rowIndex: number;
2850
+ }
2851
+ /**
2852
+ * Params delivered to `IrisTableProps.onEditClosed` (vxe edit-closed parity,
2853
+ * batch V). Cell mode only — row-edit sessions commit per column through
2854
+ * their own stores and are not reported (documented simplification); an
2855
+ * async-validating commit that lands after `commitEdit` returned is also not
2856
+ * reported (the sync path fires with the committed value).
2857
+ */
2858
+ interface IrisTableEditClosedParams<Row = Record<string, unknown>> {
2859
+ row: Row;
2860
+ column: IrisTableColumn<Row>;
2861
+ rowIndex: number;
2862
+ /** The committed value; undefined when the edit was cancelled. */
2863
+ value?: unknown;
2864
+ /** true when the edit was cancelled (Escape) instead of committed. */
2865
+ cancelled: boolean;
2866
+ }
2867
+ /** Scroll coordinates delivered to `IrisTableProps.onScroll` (vxe scroll parity, batch V). */
2868
+ interface IrisTableScrollParams {
2869
+ scrollTop: number;
2870
+ scrollLeft: number;
2871
+ }
2407
2872
  type IrisTableRenderDetail<Row = Record<string, unknown>> = (row: Row, rowIndex: number) => React.ReactNode;
2408
2873
  type IrisTableRowExpandable<Row = Record<string, unknown>> = (row: Row, rowIndex: number) => boolean;
2409
-
2410
- /** Public input surface for the React table adapter. */
2411
- interface IrisTableProps<Row extends Record<string, unknown> = Record<string, unknown>> {
2874
+ /**
2875
+ * Cell tooltip configuration (vxe-grid tooltipConfig parity, title mode).
2876
+ * Renders a native `title` on every body cell — no portal, no positioning.
2877
+ * Empty content drops the tooltip (vxe empty-content parity); editing cells
2878
+ * are exempt.
2879
+ */
2880
+ interface IrisTableTooltipConfig<Row = Record<string, unknown>> {
2881
+ /**
2882
+ * Render a tooltip on every body cell. Default true when `tooltipConfig` is
2883
+ * set. With `false`, the native `title` is emitted only when the cell's
2884
+ * single-line content is measured wider than its rendered box; the table
2885
+ * rechecks after root resize. SSR/jsdom (where layout dimensions are zero)
2886
+ * fail open and keep the title. `true` keeps the title on every non-empty
2887
+ * cell.
2888
+ */
2889
+ showAll?: boolean;
2890
+ /**
2891
+ * Custom tooltip text for a cell. Defaults to the raw cell value. Returning
2892
+ * an empty string drops the tooltip (vxe empty-content parity).
2893
+ */
2894
+ content?: (row: Row, column: IrisTableColumn<Row>) => string;
2895
+ }
2896
+ /**
2897
+ * One header-merge entry (vxe-grid mergeHeaderCells parity, batch P). The
2898
+ * coordinate space is the FLAT header's leaf-column index: `row` 0 only —
2899
+ * entries with `row` > 0 are ignored (the flat header is a single row), and
2900
+ * grouped headers are NOT merged (documented simplification).
2901
+ */
2902
+ interface IrisTableMergeCell {
2903
+ /** Header row index — only 0 is supported (flat header). */
2904
+ row: number;
2905
+ /** Leaf-column index of the merged cell's origin. */
2906
+ col: number;
2907
+ /** Columns spanned (gridColumnEnd); the covered cells render null. */
2908
+ colspan?: number;
2909
+ /** Rows spanned (gridRowEnd); inert on the single flat header row. */
2910
+ rowspan?: number;
2911
+ }
2912
+ /**
2913
+ * Span result shared by `spanMethod` and `footerSpanMethod` (vxe
2914
+ * span-method / footer-span-method parity): both dimensions default to 1;
2915
+ * values > 1 make the cell span adjacent cells, which then render null.
2916
+ * Footer note: `rowspan` is inert in the footer stack (each footer row is
2917
+ * its own grid container — see `footerSpanMethod`).
2918
+ */
2919
+ interface IrisTableSpan {
2920
+ rowspan?: number;
2921
+ colspan?: number;
2922
+ }
2923
+ /** Params delivered to `IrisTableProps.footerSpanMethod` (vxe footer-span-method parity, batch P). */
2924
+ interface IrisTableFooterSpanParams<Row = Record<string, unknown>> {
2925
+ /** 0-based row index over the rendered footer stack (footerMethod rows →
2926
+ * summary row → footerData rows, whichever render). */
2927
+ rowIndex: number;
2928
+ columnIndex: number;
2929
+ /** Leaf columns of the table (grouped headers flattened). */
2412
2930
  columns: IrisTableColumn<Row>[];
2931
+ /** Full body rows (sorted + filtered). */
2413
2932
  data: Row[];
2933
+ }
2934
+ /** Footer cell merge callback (vxe footer-span-method parity, batch P). */
2935
+ type IrisTableFooterSpanMethod<Row = Record<string, unknown>> = (params: IrisTableFooterSpanParams<Row>) => IrisTableSpan | null;
2936
+ /** vxe-grid scrollbarConfig parity (batch Q): `theme: 'thin'` → 6px webkit + Firefox `scrollbar-width: thin` via `data-iris-scrollbar-thin`. */
2937
+ type IrisTableScrollbarConfig = {
2938
+ theme?: 'default' | 'thin';
2939
+ };
2940
+ /** vxe-grid editDirtyConfig parity (batch Q): a committed cell whose value
2941
+ * differs from its pre-edit original renders a primary dot
2942
+ * (`data-iris-cell-dirty`); committing the original value clears it.
2943
+ * `indicator: false` suppresses the dot (tracking stays); `className: true`
2944
+ * also adds an `iris-table-cell-dirty` class for custom styling. */
2945
+ type IrisTableEditDirtyConfig = {
2946
+ indicator?: boolean;
2947
+ className?: boolean;
2948
+ };
2949
+ /**
2950
+ * One conditional-formatting rule (batch AX, iris 独有 — vxe has no built-in
2951
+ * conditional-formatting engine). Passed via `IrisTableProps.conditionalStyles`:
2952
+ * a rule matches a body cell when its optional `column` filter (omitted →
2953
+ * every column) equals the cell's column key AND `when(row, value)` returns
2954
+ * true — `value` is the RAW cell value (`dataIndex ?? key` resolved, formula
2955
+ * columns computed via `getCellValue`). Matching rules merge in array order
2956
+ * after `cellStyle`; later rules win on conflicting style keys.
2957
+ */
2958
+ interface IrisTableConditionalStyle<Row = Record<string, unknown>> {
2959
+ /** Column key the rule applies to; omitted → every column. */
2960
+ column?: string;
2961
+ /** Match predicate: `row` is the full row object, `value` the raw cell value. */
2962
+ when: (row: Row, value: unknown) => boolean;
2963
+ /** Inline styles merged onto the body cell when the rule matches. */
2964
+ style: React.CSSProperties;
2965
+ }
2966
+ /**
2967
+ * One footer-merge entry (vxe-grid mergeFooterItems parity, batch R). The
2968
+ * coordinate space matches `footerSpanMethod`: `row` is the 0-based index
2969
+ * over the rendered footer stack (footerMethod rows → summary row →
2970
+ * footerData rows, whichever render) and `col` the leaf-column index — both
2971
+ * start at 0. The function (`footerSpanMethod`) wins when both are provided.
2972
+ */
2973
+ interface IrisTableMergeFooterItem {
2974
+ /** 0-based footer-stack row index (footerMethod rows → summary row → footerData rows). */
2975
+ row: number;
2976
+ /** Leaf-column index of the merged cell's origin. */
2977
+ col: number;
2978
+ /** Columns spanned (gridColumnEnd); the covered cells of the same row render null. */
2979
+ colspan?: number;
2980
+ /** Rows spanned — INERT (each footer row is its own grid container, so
2981
+ * `gridRowEnd` cannot cross rows): covered cells of later rows keep their
2982
+ * own data, like `footerSpanMethod`'s rowspan. */
2983
+ rowspan?: number;
2984
+ }
2985
+
2986
+ interface IrisTableHandle<Row extends Record<string, unknown> = Record<string, unknown>> {
2987
+ /** Insert a row at `index` (default: end). A missing `rowKeyField` value gets an auto id. */
2988
+ insertRow: (row: Row, index?: number) => void;
2989
+ /** 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. */
2990
+ cloneRow: (key: string | number, index?: number) => void;
2991
+ /** Remove the row with `key`; its selection is pruned. */
2992
+ removeRow: (key: string | number) => void;
2993
+ /** Batch-remove several rows by key (vxe removeRows parity): missing keys are silent no-ops, selection is pruned, one onDataChange fires. */
2994
+ removeRows: (keys: Array<string | number>) => void;
2995
+ /** Patch the row with `key` ({ ...row, ...patch }). */
2996
+ updateRow: (key: string | number, patch: Partial<Row>) => void;
2997
+ /** Re-fetch the current page (proxy mode). */
2998
+ refetch: () => void;
2999
+ /** 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). */
3000
+ loadData: (rows: Row[]) => void;
3001
+ /** Re-fetch the current page (vxe reloadData parity, batch V — alias of refetch). */
3002
+ reloadData: () => void;
3003
+ /** Merge params into the proxy query and fire the request (vxe commitProxy parity, batch V). */
3004
+ commitProxy: (overrides: Partial<IrisTableProxyQueryParams>) => void;
3005
+ /** Proxy state snapshot (vxe getProxyInfo parity, batch V): page/pageSize/total; null without a proxy. */
3006
+ getProxyInfo: () => {
3007
+ page: number;
3008
+ pageSize: number;
3009
+ total: number;
3010
+ } | null;
3011
+ /** Snapshot (copy) of the current live row list (vxe getTableData parity). */
3012
+ getData: () => Row[];
3013
+ /** 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. */
3014
+ getFilteredData: () => Row[];
3015
+ /** 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`). */
3016
+ exportCurrentViewCsv: () => string;
3017
+ /** Serialize the SELECTED rows as CSV (batch AP, iris 独有): selected rows
3018
+ * in bodyData order (filtered + sorted + tree-flattened) → the same
3019
+ * `exportCsv` shape as `exportCurrentViewCsv` (formula columns materialized
3020
+ * on shadow rows, hidden columns excluded); empty selection → `''` (caller
3021
+ * detects via `getSelection()`). */
3022
+ exportSelectionCsv: () => string;
3023
+ /** Serialize rows whose keys are explicitly supplied, preserving current
3024
+ * body/view order and the same formula/mask/hidden-column pipeline. */
3025
+ exportRowsCsv: (keys: Array<string | number>) => string;
3026
+ /** Multi-segment CSV export (batch DI, iris 独有): ONE file — the current
3027
+ * table block (`# current` + `exportCurrentViewCsv()` byte-for-byte) followed
3028
+ * by one `# <key>` + ref block per `exportNames` entry IN ORDER; segments
3029
+ * joined by a blank line (`\n\n`), no trailing newline. Each ref block is
3030
+ * serialized by its OWN keys (first row's keys as header) — NOT this table's
3031
+ * columns; empty ref rows → just the segment header; a `''` key skips that
3032
+ * segment (even its header). Empty/absent `exportNames` → the bare
3033
+ * current-table CSV (byte-identical to `exportCurrentViewCsv()`, zero
3034
+ * regression). Caller downloads via `downloadCsv`. */
3035
+ exportMultiCsv: () => string;
3036
+ /** Current selection keys (vxe getCheckboxRecords parity). */
3037
+ getSelection: () => Array<string | number>;
3038
+ /** Clear every selected row (vxe clearCheckboxRow parity). */
3039
+ clearSelection: () => void;
3040
+ /** Select every checkMethod-eligible row of the current page (vxe
3041
+ * setAllCheckboxRow(true) parity — `checkMethod` rows are skipped). */
3042
+ selectAll: () => void;
3043
+ /** Toggle a single row's selection by key (vxe toggleCheckboxRow parity —
3044
+ * a direct toggle that bypasses `checkMethod`). */
3045
+ toggleRowSelection: (key: string | number) => void;
3046
+ /** Scroll the row with `key` into view (vxe scrollToRow parity); no-op when the row is not rendered. */
3047
+ scrollToRow: (key: string | number) => void;
3048
+ /** 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`. */
3049
+ goToRow: (key: string | number) => void;
3050
+ /** Toggle a row's expand state (vxe toggleRowExpand parity): tree mode toggles the caret, detail mode the panel; no-op for plain tables. */
3051
+ toggleRowExpand: (key: string | number) => void;
3052
+ /** Clear the active sort (vxe clearSort parity) — single and multi channels. */
3053
+ clearSort: () => void;
3054
+ /** Clear every filter channel (vxe clearFilter parity): text filters + checked sets. */
3055
+ clearFilter: () => void;
3056
+ /** Set the current (highlighted) row (vxe setCurrentRow parity); no-op without onCurrentRowChange (or an unknown key). */
3057
+ setCurrentRow: (key: string | number) => void;
3058
+ /** Set the current (highlighted) column (vxe setCurrentColumn parity); no-op without onCurrentColumnChange (or an unknown key). */
3059
+ setCurrentColumn: (key: string) => void;
3060
+ /** 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. */
3061
+ getAuditLog: () => ReadonlyArray<IrisTableAuditEntry>;
3062
+ /** Wipe every audit entry (batch AT, iris 独有): the seq counter never resets — audit integrity. No-op without `auditLog`. */
3063
+ clearAuditLog: () => void;
3064
+ /** 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. */
3065
+ getVersions: () => ReadonlyArray<IrisTableVersionEntry>;
3066
+ /** 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`. */
3067
+ restoreVersion: (index: number) => void;
3068
+ /** 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()`). */
3069
+ exportVersionCsv: (index: number) => string;
3070
+ /** 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. */
3071
+ exportComparisonCsv: () => string;
3072
+ /** 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()`). */
3073
+ exportTimelineCsv: () => string;
3074
+ /** Export the annotated cells as CSV (batch DU, iris 独有 — vxe has no note
3075
+ * concept, so no export parity): spec-literal 3 columns
3076
+ * `rowKey,column,annotation`, one line per noted body cell in bodyData
3077
+ * order; notes resolve through the SAME cellNoteState path as the cell
3078
+ * render (dynamic `cellNote` wins over the static `annotations` map),
3079
+ * hidden columns excluded via the view-columns list; values flow through
3080
+ * core `toCsv` (RFC-4180 quoting + OWASP formula neutralization —
3081
+ * annotation text is untrusted data). Fail-closed: `exportAnnotations`
3082
+ * off → `''`; on but no notes on the current body → `''` (spec-literal
3083
+ * 无批注返回空 — the two states are indistinguishable, mirroring
3084
+ * `exportSelectionCsv`). */
3085
+ exportAnnotationsCsv: () => string;
3086
+ /** Export the CURRENT view state as JSON (batch BZ, iris 独有): all 9 spec
3087
+ * blocks — sort / filters / filterValues / columnVisibility / columnOrder /
3088
+ * columnWidths / pageSize / expandedKeys / query — captured by the SAME
3089
+ * collector as `persistState` (multiSortState deliberately excluded — not
3090
+ * in the spec; `importStateJson` accepts supersets). A piece appears only
3091
+ * when restorable (owning callback present; `pageSize` only with a proxy;
3092
+ * `expandedKeys` only when expandable AND restorable; `query` only when
3093
+ * set) — a bare table exports `'{}'`. Round-trips byte-identically through
3094
+ * `importStateJson`. */
3095
+ exportStateJson: () => string;
3096
+ /** Apply a previously exported state JSON (batch BZ, iris 独有): parses and
3097
+ * replays every present piece through the owning change callbacks (the same
3098
+ * per-piece gating as a view apply — `query` restores FIRST via
3099
+ * `onQueryChange`, `pageSize` reproduces `onPageChange(1, size)` + exactly
3100
+ * one request, `expandedKeys` replaces the whole set via the expansion
3101
+ * model). Invalid JSON or a non-object value → `false` with NOTHING applied;
3102
+ * valid JSON applies piece-by-piece lazily and returns `true` (ineligible
3103
+ * pieces — missing callback / wrong type — are skipped). */
3104
+ importStateJson: (json: string) => boolean;
3105
+ /** 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. */
3106
+ compareStates: (a: string, b: string) => string;
3107
+ }
3108
+ /**
3109
+ * Audit-trail entry shape (batch AT, iris 独有) — mirrors the core
3110
+ * `AuditLogEntry` contract (the handle returns a snapshot of the controller
3111
+ * ring). Row-level structural changes (insert/remove) carry only `rowKey`.
3112
+ */
3113
+ interface IrisTableAuditEntry {
3114
+ /** Monotonic sequence number (never resets on clear — audit integrity). */
3115
+ seq: number;
3116
+ /** Epoch ms when the entry was pushed. */
3117
+ at: number;
3118
+ /** Commit kind: edit / insert / remove / paste / batch / fill / undo / redo. */
3119
+ type: 'edit' | 'insert' | 'remove' | 'paste' | 'batch' | 'fill' | 'undo' | 'redo';
3120
+ /** Key of the first changed row (undefined when none could be resolved). */
3121
+ rowKey?: string | number;
3122
+ /** Column key of the first changed cell (undefined for row-level ops). */
3123
+ column?: string;
3124
+ /** Value before the change. */
3125
+ oldValue?: unknown;
3126
+ /** Value after the change. */
3127
+ newValue?: unknown;
3128
+ }
3129
+ /**
3130
+ * Version-history entry shape (batch BA, iris 独有) — a LIGHTWEIGHT mirror of
3131
+ * the core `VersionHistoryEntry` WITHOUT the rows (the handle snapshot stays
3132
+ * cheap; `restoreVersion(index)` fetches the rows from the controller).
3133
+ */
3134
+ interface IrisTableVersionEntry {
3135
+ /** Monotonic version index (never resets on clear). */
3136
+ index: number;
3137
+ /** Epoch ms when the version was pushed. */
3138
+ at: number;
3139
+ /** Commit-kind hint: edit / insert / remove / paste / batch / fill / undo / redo. */
3140
+ type: 'edit' | 'insert' | 'remove' | 'paste' | 'batch' | 'fill' | 'undo' | 'redo';
3141
+ }
3142
+ /**
3143
+ * Collaborative-presence cursor entry (batch BD, iris 独有 — vxe has no
3144
+ * cursor sharing): one remote participant's cursor on a selected cell. Pure
3145
+ * display — the table renders the entry verbatim and owns no collaboration
3146
+ * state or logic. `cellKey` uses the canonical `${rowKeyVal}::${colKey}`
3147
+ * delimiter (the same as `cellId` and the `annotations` map keys).
3148
+ */
3149
+ interface IrisTablePresenceEntry {
3150
+ /** Stable participant id (also surfaced as `data-iris-presence-id`). */
3151
+ id: string;
3152
+ /** Participant display name — the text of the cell's corner label. */
3153
+ name: string;
3154
+ /** Cursor color, used verbatim: the cell outline + the label background. */
3155
+ color: string;
3156
+ /** Target cell: `${rowKeyVal}::${colKey}` (same delimiter as `cellId`). */
3157
+ cellKey: string;
3158
+ }
3159
+
3160
+ interface IrisTableAdvancedProps<Row extends Record<string, unknown> = Record<string, unknown>> {
3161
+ nlSummary?: boolean;
3162
+ /**
3163
+ * Mini chart preview (batch AR, iris 独有): when true, the toolbar gains a
3164
+ * chart trigger (`data-iris-chart-trigger`) opening a floating panel
3165
+ * (`data-iris-chart-panel`) that charts the CURRENT filtered rows: a
3166
+ * numeric-column select (columns where `typeof getCellValue(row, col) ===
3167
+ * 'number'` for some row, or `col.summary === 'sum'`) plus a bar/line kind
3168
+ * toggle. The SVG (viewBox 0 0 300 120) is built from the core
3169
+ * `buildChartData` material over the first 20 values (a muted "共 N 行"
3170
+ * note when truncated) — structured JSX only, no SVG strings. Token colors
3171
+ * only; Esc / outside / scroll close it. Requires a toolbar render (the
3172
+ * gate admits `chartPreview` like `undo`).
3173
+ */
3174
+ chartPreview?: boolean;
3175
+ /**
3176
+ * Auto-refresh (batch AS, iris 独有 — vxe has no interval refresh): when
3177
+ * set, the table re-queries the proxy every `intervalMs` ms while in proxy
3178
+ * mode (non-proxy `data` tables are inert — there is nothing to refetch).
3179
+ * Each tick calls the SAME refetch the built-in ↻ button uses — the
3180
+ * standard refetch path, so `loading` flips true for the duration of the
3181
+ * request (the core source has no silent-refresh option; documented
3182
+ * behavior, not suppressed). `intervalMs` ≤ 0 disables the timer
3183
+ * (fail-closed). The interval restarts whenever `intervalMs` changes
3184
+ * (keyed on the scalar, so an inline object doesn't reset the timer every
3185
+ * render) and is cleared on unmount / proxy removal. Additive — default
3186
+ * off.
3187
+ */
3188
+ autoRefresh?: {
3189
+ intervalMs: number;
3190
+ };
3191
+ /**
3192
+ * Freshness stamp (batch AS, iris 独有 — vxe shows no data-arrival time):
3193
+ * when true, the toolbar renders `Updated at HH:MM:SS`
3194
+ * (`data-iris-freshness`, i18n `table.freshness`, 24h local `formatClock`)
3195
+ * re-stamped on EVERY live-data change — initial arrival, refetch, edit
3196
+ * commit, row ops / paste / batch / range clear, undo/redo (everything
3197
+ * that funnels through `setLiveData`). Hidden until the first row exists
3198
+ * (`liveData.length === 0`). Requires a toolbar render. Additive — default
3199
+ * off.
3200
+ */
3201
+ freshness?: boolean;
3202
+ /**
3203
+ * Validation summary (batch BR, iris 独有 — vxe shows no editRules outcome
3204
+ * counts): when true, the toolbar renders a muted commit-outcome ledger
3205
+ * (`data-iris-validation-summary`, i18n `table.validationSummary`, en
3206
+ * `Passed {ok} · Failed {fail}` / zh `通过 {ok} · 失败 {fail}`) for columns
3207
+ * with declarative `editRules`: ok = a commit that passed editRules and
3208
+ * landed (cell and row edit modes), fail = a commit attempt rejected by
3209
+ * editRules. Typing-time validation, legacy `validate` columns, paste/fill/
3210
+ * FNR/batch bypasses and Escape cancels never count. Hidden until at least
3211
+ * one outcome is counted; re-enabling the switch resets the ledger.
3212
+ * Requires a toolbar render (the gate admits `validationSummary` like
3213
+ * `freshness`). Additive — default off.
3214
+ */
3215
+ validationSummary?: boolean;
3216
+ /**
3217
+ * Audit log (batch AT, iris 独有 — vxe has no audit trail): when true, every
3218
+ * mutation commit appends ONE entry to a bounded (200) ring — inline/row
3219
+ * edits, insert/remove row ops, paste, fill, batch edit, undo/redo replay
3220
+ * (type hint per site; rowKey + first-changed-cell context from a light
3221
+ * diff of the row lists, documented simplification). The toolbar gains an
3222
+ * audit trigger (`data-iris-audit-trigger`) opening a floating panel
3223
+ * (`data-iris-audit-panel`, like the chart/stats panels — Esc / outside /
3224
+ * scroll close) listing newest-first entries (seq + `formatClock` time +
3225
+ * type + rowKey + column + muted old→new). `tableRef.getAuditLog()` /
3226
+ * `clearAuditLog()` expose the trail programmatically (the seq never
3227
+ * resets on clear — audit integrity). Requires a toolbar render (the gate
3228
+ * admits `auditLog` like `undo`). Additive — default off.
3229
+ */
3230
+ auditLog?: boolean;
3231
+ /**
3232
+ * Performance panel (batch BL, iris 独有 — vxe has no perf stats): when
3233
+ * true, every render commit samples `nowMs()` (render-top mark →
3234
+ * dependency-less `useLayoutEffect` run) into a core `createPerfStats`
3235
+ * latest-snapshot controller (`@iris-ui-kit/core/perf-stats` — own
3236
+ * subpath). Duration = render + layout phase, excludes paint
3237
+ * (documented). The toolbar gains a ⚡ trigger (`data-iris-perf-trigger`)
3238
+ * opening a floating panel (`data-iris-perf-panel`, like the audit panel
3239
+ * — Esc / outside / scroll close) showing the last render duration,
3240
+ * row count, leaf-column count and the audit-trail depth — live: the
3241
+ * panel subscribes to BOTH controllers, so `tableRef.clearAuditLog()`
3242
+ * refreshes the changes count in place; `auditLog` off → muted `—`. The
3243
+ * push notifies only the panel (separate portal root) — the table never
3244
+ * re-renders from its own measurement. Requires a toolbar render (the
3245
+ * gate admits `perfStats` like `auditLog`). Off = zero cost. Additive —
3246
+ * default off.
3247
+ */
3248
+ perfStats?: boolean;
3249
+ /**
3250
+ * Version history (batch BA, iris 独有 — vxe has no time-travel): when set,
3251
+ * every row-list commit (`commitRowList` — row ops, paste, fill, range
3252
+ * clear, batch edit, undo/redo replay) pushes the PRE-change rows into a
3253
+ * bounded ring (core `createVersionHistory`, default max 20; `max: 0`
3254
+ * unlimited; `max` read once at mount). The toolbar gains a history trigger
3255
+ * (`data-iris-history-trigger`) opening a floating panel
3256
+ * (`data-iris-history-panel`, like the audit panel — Esc / outside / scroll
3257
+ * close) listing versions newest-first (#index + `formatClock` time + commit
3258
+ * type); clicking an entry restores those rows through the normal write-back
3259
+ * channel (`commitRowList(rows, 'undo')` — auditable and undoable) WITHOUT
3260
+ * pushing a new version. Inline cell/row edits (the `commitValue` funnel)
3261
+ * don't create versions (documented — restore replaces the whole row list,
3262
+ * so row-level commits are the coherent unit). `tableRef.getVersions()`
3263
+ * (lightweight — no rows) / `restoreVersion(index)` expose the ring
3264
+ * programmatically. Requires a toolbar render (the gate admits
3265
+ * `versionHistory` like `undo`). Additive — default off.
3266
+ */
3267
+ versionHistory?: {
3268
+ max?: number;
3269
+ };
3270
+ /**
3271
+ * Compare view (batch AU, iris 独有 — vxe has no compare capability): a
3272
+ * snapshot the live rows are diffed against by `rowKey`. Every live row
3273
+ * absent from the snapshot renders `data-iris-row-removed`, every live row
3274
+ * present in both with ≥1 differing cell renders `data-iris-row-changed`
3275
+ * with `data-iris-cell-changed` on the changed cells and a title tooltip
3276
+ * `旧值: X → 新值: Y` (old = live value, new = snapshot value) that
3277
+ * overrides the tooltipConfig title (compare wins, documented); snapshot-
3278
+ * only rows are `added` in the core diff but have no rendered slot — the
3279
+ * compare view renders the live dataset (documented). Core `diffRows` is
3280
+ * framework-free; the memo is null without `compareWith` or `rowKey` —
3281
+ * additive, default off.
3282
+ */
3283
+ compareWith?: Row[];
3284
+ /**
3285
+ * Cell auto-link (batch CA, iris 独有 — vxe has no URL/email auto-
3286
+ * detection): when true, text cells run their display chain
3287
+ * (mask → formatter ?? raw) through core `detectAutoLink`; a whole-text
3288
+ * URL/email match renders an `<a data-iris-auto-link>` (_blank +
3289
+ * noreferrer) instead of plain text. Non-matching text falls through to
3290
+ * the formatter/raw branch unchanged; an explicit `col.link` column still
3291
+ * wins (evaluated before autoLink). Additive — default off.
3292
+ */
3293
+ autoLink?: boolean;
3294
+ /**
3295
+ * Recent filters (batch CB, iris 独有 — vxe has no "recent filters"
3296
+ * concept): when true, every filter-panel confirm (non-empty checked
3297
+ * set) records `{ key, values, ts }` into a core `createRecentFilters`
3298
+ * ring (newest-first, 10 entries, MRU — re-confirming the same set
3299
+ * bumps it to the top). The filter panel shows the recent entries
3300
+ * above the options; clicking one applies it immediately (across
3301
+ * columns) and closes. Additive — default off.
3302
+ */
3303
+ recentFilters?: boolean;
3304
+ /**
3305
+ * Edit-history sidebar (batch DB, iris 独有 — vxe has no edit history): a
3306
+ * right-side drawer panel (portal, `position: fixed`, 360px, NO backdrop —
3307
+ * non-modal) opened from the toolbar trigger (`data-iris-edit-sidebar-trigger`,
3308
+ * ⏳ right after the version-history trigger). It merges the batch-AT audit
3309
+ * ring and the batch-BA version ring into ONE timeline view, newest-first
3310
+ * (`at` desc; a same-ms tie lists the audit entry ABOVE its version — the
3311
+ * deterministic record-order arbitration). Version entries are clickable:
3312
+ * pressing one restores those rows through the normal write-back channel
3313
+ * (`commitRowList(rows, 'undo')` — auditable and undoable) WITHOUT pushing a
3314
+ * new version, exactly like the version-history panel, and closes. Audit
3315
+ * entries render seq + `formatClock` time + type + rowKey + column + muted
3316
+ * old→new. Fail-closed matrix: a recording layer whose prop is OFF
3317
+ * contributes NOTHING — the record layers are never implicitly enabled, so
3318
+ * with only `versionHistory` the panel lists versions alone, with only
3319
+ * `auditLog` audit entries alone, and with neither the empty state. The
3320
+ * panel subscribes to BOTH controllers (`useSyncExternalStore` each) so a
3321
+ * commit while it is open refreshes the timeline in place. Closes on Esc /
3322
+ * outside pointer-down / any scroll; the trigger is exempt (a press on it
3323
+ * toggles instead of close-then-reopen). Requires a toolbar render (the
3324
+ * gate admits `editSidebar` like `versionHistory`). Additive — default off.
3325
+ */
3326
+ editSidebar?: boolean;
3327
+ /**
3328
+ * Imperative handle (vxe-grid edit insert/remove/setRow parity + iris-only
3329
+ * additions): row ops, proxy/view/selection methods, and (batch BZ) the
3330
+ * full view-state JSON export/import — `exportStateJson()` /
3331
+ * `importStateJson(json)` (sort / filters / filterValues /
3332
+ * columnVisibility / columnOrder / columnWidths / pageSize / expandedKeys /
3333
+ * query — the same collector as `persistState`).
3334
+ */
3335
+ tableRef?: React.MutableRefObject<IrisTableHandle<Row> | null>;
3336
+ /** Fired after any internal row operation / edit write-back, with the new row list. */
3337
+ onDataChange?: (rows: Row[]) => void;
3338
+ /** Veto rows from selection (vxe-grid checkboxConfig.checkMethod parity). */
3339
+ checkMethod?: (row: Row, rowIndex: number) => boolean;
3340
+ /** Pager options (vxe-grid pagerConfig parity). */
3341
+ pagerConfig?: IrisTablePagerConfig;
3342
+ /** Fixed height (vxe-grid height parity, batch N): makes the root a vertical
3343
+ * scroll container with a sticky header row. Number → px; string → CSS length. */
3344
+ height?: number | string;
3345
+ /** Minimum height of the fixed-height container (with `height`/`maxHeight`). */
3346
+ minHeight?: number | string;
3347
+ /** Maximum height of the fixed-height container (with `height`/`minHeight`). */
3348
+ maxHeight?: number | string;
3349
+ /** Thin scrollbars (vxe-grid scrollbarConfig parity, batch Q): when
3350
+ * `theme: 'thin'`, the root and its virtual-scroll descendant get 6px
3351
+ * webkit scrollbars plus Firefox `scrollbar-width: thin` via
3352
+ * `data-iris-scrollbar-thin`. Default: browser scrollbars. */
3353
+ scrollbarConfig?: {
3354
+ theme?: 'default' | 'thin';
3355
+ };
3356
+ /** Batch DP (iris 独有): add token-driven custom thumb styling to the native
3357
+ * scrollbar while retaining native scrolling and accessibility. */
3358
+ scrollbarThumb?: boolean;
3359
+ /** Batch DN (iris 独有): show count/average statistics for numeric columns
3360
+ * inside their leaf headers, separate from footer/column totals. */
3361
+ headerStats?: boolean;
3362
+ /** Dirty-cell tracking (vxe-grid editDirtyConfig parity, batch Q): a cell
3363
+ * whose committed value differs from its pre-edit original renders a
3364
+ * primary dot (`data-iris-cell-dirty`, cell gets `position: relative`);
3365
+ * committing the original value clears it. `indicator: false` suppresses
3366
+ * the dot (tracking stays); `className: true` also adds an
3367
+ * `iris-table-cell-dirty` class for custom styling. */
3368
+ editDirtyConfig?: {
3369
+ indicator?: boolean;
3370
+ className?: boolean;
3371
+ };
3372
+ /** Fill the parent (vxe-grid auto-resize parity, batch Q): a
3373
+ * ResizeObserver measures the root and, when no explicit `height` is set,
3374
+ * renders `height: 100%` so the table fills AND tracks its parent (the
3375
+ * fixed-height scroll machinery engages after the first positive
3376
+ * measure). When `height` IS set the measured size is kept internally and
3377
+ * the explicit height wins (no visible change). Without ResizeObserver
3378
+ * (jsdom/SSR) the scroll engagement is a no-op. Default false. */
3379
+ autoResize?: boolean;
3380
+ /**
3381
+ * Re-measure on content changes (vxe-grid syncResize parity, batch R):
3382
+ * when true, `autoResize` is off and NO explicit `height` is set, an
3383
+ * effect keyed on data / loading / error / footerData / size / bordered
3384
+ * runs the SAME root measure autoResize uses (plus on
3385
+ * `visibilitychange`), so the fixed-height machinery tracks
3386
+ * content-driven size changes without a ResizeObserver. Same application
3387
+ * rules as `autoResize`: with `height` set the explicit height wins and
3388
+ * the effect does nothing. Default false. */
3389
+ syncResize?: boolean;
3390
+ /**
3391
+ * Narrow-width responsive mode (iris 独有 — vxe has no responsive column
3392
+ * behavior): a prop-gated ResizeObserver measures the root; when the
3393
+ * container measures below 480px (strictly — 480 exactly is full width),
3394
+ * the lowest-priority top-level columns are greedily hidden until the
3395
+ * natural width fits (pinned columns survive, at least one column stays),
3396
+ * and — only when columns STILL overflow after collapsing — a horizontal
3397
+ * scroll hint bar (`data-iris-scroll-hint`) + root overflowX auto appear
3398
+ * so no data is unreachable. At/above 480px, without ResizeObserver
3399
+ * (jsdom/SSR) or with the prop off, the render is byte-identical. Default
3400
+ * false. */
3401
+ responsive?: boolean;
3402
+ /**
3403
+ * Seed the live row list with a COPY of `data` (vxe-grid keepSource
3404
+ * parity, batch R): `liveData` initializes to `[...data]` instead of the
3405
+ * `data` reference, so mutating the original array after mount cannot
3406
+ * change the table. The table is immutable either way — it never mutates
3407
+ * the rows it receives; `keepSource` just decouples the initial seed.
3408
+ * Later controlled re-feeds (new `data` reference) keep the hand-off. */
3409
+ keepSource?: boolean;
3410
+ /**
3411
+ * Root stacking (vxe-grid zIndex parity, batch R): sets `z-index` on the
3412
+ * root with `position: relative` (CSS z-index is inert on static
3413
+ * elements). Rendered before `style` — a caller-provided style can still
3414
+ * override. */
3415
+ zIndex?: number;
3416
+ /** Highlight rows on hover (vxe highlight-hover-row parity, batch N). Default true. */
3417
+ highlightHoverRow?: boolean;
3418
+ /** 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. */
3419
+ showHeaderOverflow?: boolean;
3420
+ /** 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. */
3421
+ showFooterOverflow?: boolean;
3422
+ /** 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. */
3423
+ watermark?: string;
3424
+ style?: React.CSSProperties;
3425
+ className?: string;
3426
+ }
3427
+
3428
+ interface IrisTableEditingProps<Row extends Record<string, unknown> = Record<string, unknown>> {
3429
+ /**
3430
+ * Column drag-sort (vxe-grid columnDragConfig parity). Reorders leaf
3431
+ * columns on drop; parent owns columns (pass the reordered array back).
3432
+ * Batch CH (iris 独有 — vxe has no drag-out pin): when `columnPinMenu` is
3433
+ * ALSO on, dragging a column header past the table's LEFT edge pins it
3434
+ * left on release (drag-out pin) instead of reordering — a second gesture
3435
+ * into the pin menu's state channel (same `onColumnPinnedChange` contract,
3436
+ * both controlled/uncontrolled modes, never a reorder). Plain `columnDrag`
3437
+ * without `columnPinMenu` keeps the vxe reorder-only behavior.
3438
+ * Batch DK (iris 独有): a pinned intra-zone reorder ALSO fires
3439
+ * `onColumnOrderChange` with the new top-level key list (flat leaf tables
3440
+ * only; grouped leaves stay `onReorder`-only) so a header frozen-zone
3441
+ * reorder is durable for controlled parents through the same channel the
3442
+ * settings panel uses.
3443
+ */
3444
+ columnDrag?: {
3445
+ /** Called with the reordered column array after a drop. */
3446
+ onReorder: (columns: IrisTableColumn<Row>[]) => void;
3447
+ };
3448
+ /** Render a leading sequence-number column (vxe-grid seqConfig parity). */
3449
+ seq?: boolean;
3450
+ /**
3451
+ * Excel-style row/column references (batch AO, iris 独有 — vxe seqConfig
3452
+ * shows numbers only, no column letters): muted A/B/C… letter badges
3453
+ * (`data-iris-cell-ref`) after every LEAF header title (A = first leaf;
3454
+ * seq/selection/detail/drag columns are skipped, grouped leaves follow
3455
+ * source order) plus a leading row-number column 1, 2, 3…
3456
+ * (`data-iris-row-ref`). When `seq` is on the seq column IS the row
3457
+ * number — no duplicate column. Additive — default off.
3458
+ */
3459
+ showCellRefs?: boolean;
3460
+ /**
3461
+ * Cell merge (vxe-grid spanMethod parity): return `{ rowspan, colspan }`
3462
+ * for a cell at (rowIndex, columnIndex); both default 1. Values > 1 make
3463
+ * the cell span adjacent cells (the spanned cells are skipped).
3464
+ */
3465
+ spanMethod?: (params: {
3466
+ rowIndex: number;
3467
+ columnIndex: number;
3468
+ }) => {
3469
+ rowspan?: number;
3470
+ colspan?: number;
3471
+ } | null | undefined;
3472
+ /**
3473
+ * Header merge (vxe-grid mergeHeaderCells parity, batch P): merge entries
3474
+ * keyed by leaf-column index of the FLAT header row (`row` 0 only — rows
3475
+ * > 0 are ignored). A merge cell renders with `gridColumnEnd: span
3476
+ * colspan` / `gridRowEnd: span rowspan`; the covered cells render null.
3477
+ * Grouped headers and `columnVirtualization` are not merged (documented
3478
+ * simplification).
3479
+ */
3480
+ mergeHeaderCells?: IrisTableMergeCell[];
3481
+ /**
3482
+ * Footer merge (vxe-grid mergeFooterItems parity, batch R): declarative
3483
+ * span entries in the SAME coordinate space as `footerSpanMethod` — `row`
3484
+ * is the 0-based index over the rendered footer stack (footerMethod rows →
3485
+ * summary row → footerData rows, whichever render) and `col` the
3486
+ * leaf-column index; both start at 0. A merge cell renders `gridColumnEnd:
3487
+ * span colspan`; the covered cells of the same row render null. `rowspan`
3488
+ * is inert (each footer row is its own grid container — covered cells of
3489
+ * later rows keep their own data; mirrors `footerSpanMethod`'s rowspan).
3490
+ * The function wins: when `footerSpanMethod` is provided,
3491
+ * `mergeFooterItems` is ignored. Entries outside the rendered stack are
3492
+ * no-ops.
3493
+ */
3494
+ mergeFooterItems?: IrisTableMergeFooterItem[];
3495
+ /**
3496
+ * Row key fallback (vxe-grid deprecated string `rowId` parity, re-typed as
3497
+ * a function, batch R): when a row lacks the `rowKey` field, this callback
3498
+ * supplies the row's key — used by selection, expansion, dirty tracking,
3499
+ * editing and tree flattening. `rowKey` wins over `rowId`; without either,
3500
+ * the row index is used at index-bearing call sites (unchanged). The
3501
+ * imperative handle's row ops, clipboard paste and find&replace write-backs
3502
+ * still address rows by the `rowKey` field only (keyless rows are skipped
3503
+ * there). */
3504
+ rowId?: (row: Row, rowIndex: number) => string | number;
3505
+ /** Row drag-sort configuration (composed over core createSortable). */
3506
+ rowDrag?: {
3507
+ /** Reorder callback — receives the reordered row array (parent owns data). */
3508
+ onReorder: (rows: Row[]) => void;
3509
+ };
3510
+ /** 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. */
3511
+ rowDragBetween?: IrisTableRowDragBetweenTarget<Row>[];
3512
+ /** Inline-edit configuration (vxe-grid editConfig parity). */
3513
+ editConfig?: {
3514
+ /** What opens the editor. Default `'dblclick'`. */
3515
+ trigger?: 'click' | 'dblclick' | 'manual';
3516
+ /** Show a required asterisk next to headers of columns with rules. */
3517
+ showAsterisk?: boolean;
3518
+ /** Drop the draft when opening another cell without committing. */
3519
+ autoClear?: boolean;
3520
+ /** 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. */
3521
+ mode?: 'cell' | 'row';
3522
+ };
3523
+ /** Edit-validation presentation (vxe-grid ValidConfig parity). */
3524
+ validConfig?: IrisTableValidConfig;
3525
+ onCellEdit?: (event: IrisTableCellEditEvent<Row>) => void;
3526
+ /** Edit start (vxe edit-activated parity, batch V): fired when an inline editor opens (cell double-click; cell mode only). */
3527
+ onEditStart?: (params: IrisTableEditStartParams<Row>) => void;
3528
+ /** 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`). */
3529
+ onEditClosed?: (params: IrisTableEditClosedParams<Row>) => void;
3530
+ /** 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. */
3531
+ editAutosave?: boolean;
3532
+ /** Batch BQ (iris 独有): parent persistence hook fired by `editAutosave` with the post-commit row list. */
3533
+ onAutosave?: (rows: Row[]) => void;
3534
+ /** 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). */
3535
+ editAutoHeight?: boolean;
3536
+ /** Batch CG (iris 独有 — vxe has no equivalent; Excel-style status-bar parity):
3537
+ * a live character count in the editing cell's bottom-right corner (cell AND
3538
+ * row edit modes, recomputed per keystroke from the session draft) plus a
3539
+ * cell-count/sum badge at the selected range's bottom-right cell when
3540
+ * `cellRange` has a live selection (a pure reduction over the rangeStats
3541
+ * material — count = Σ column non-null counts, sum = Σ numeric column sums,
3542
+ * `null` = no numeric data — rounded via the same `aggregateAccuracy` gate as
3543
+ * the summary row). Additive; default off (fail-closed).
3544
+ */
3545
+ charCount?: boolean;
3546
+ /** Batch CQ (iris 独有 — vxe has no equivalent): show a live preview of the
3547
+ * formatter-applied result below the editing cell — recomputed per keystroke
3548
+ * from the session draft through the SAME display chain as the committed cell
3549
+ * (mask → formatter, with the commit path's draft coercion for number/select
3550
+ * editors), rendered as a muted small line (`data-iris-edit-preview`). Only
3551
+ * columns with a `formatter` render a preview. Additive; default off
3552
+ * (fail-closed).
3553
+ */
3554
+ editPreview?: boolean;
3555
+ /** Batch DH (iris 独有 — vxe has no equivalent; data-consistency assist):
3556
+ * while an inline (cell-mode) editor is open, every other cell in the SAME
3557
+ * column whose committed value exactly matches the current draft renders a
3558
+ * light highlight (`data-iris-input-hint` + a `--iris-input-hint` token
3559
+ * background) — a glanceable "these rows already share this value" cue
3560
+ * while typing. Matching is RAW (`String(raw) === String(draft)`, same
3561
+ * draft caliber as the editor/commit path — not the masked/formatted
3562
+ * display). The editing cell itself is exempt. An empty draft is
3563
+ * fail-closed (never floods the whole column). Computed live per keystroke
3564
+ * via the existing cell-edit store — zero new state. Row-edit mode is a
3565
+ * documented fiat: each column's draft lives in its own session, so row
3566
+ * mode does not participate. Additive; default off (fail-closed).
3567
+ */
3568
+ pattern?: boolean;
3569
+ /** Batch DL (iris 独有): alias for the pattern-edit consistency hint. While
3570
+ * an inline draft is open, matching committed values in the same column get
3571
+ * `data-iris-input-hint`; kept as a separate switch for the batch contract. */
3572
+ patternFill?: boolean;
3573
+ /** Batch CR (iris 独有 — vxe has no equivalent; Excel status-bar parity):
3574
+ * show a full-width horizontal strip directly below the toolbar
3575
+ * (`data-iris-column-totals`) with the column totals for every
3576
+ * `summary === 'sum'` column — aggregated over the CURRENT body rows with
3577
+ * the exact summary-row value pipeline (`aggregate` + the
3578
+ * `aggregateAccuracy` rounding gate + `renderSummary` fallback), one grid
3579
+ * cell per leaf column (`data-iris-column-totals-cell`) so tracks stay
3580
+ * aligned; non-sum columns render empty placeholders. The strip shows even
3581
+ * with an empty body (`0`). Additive; default off (fail-closed).
3582
+ */
3583
+ columnTotals?: boolean;
3584
+ /** Batch CS (iris 独有 — vxe has no equivalent; vxe keeps the pixel offset, never re-anchors).
3585
+ * In virtual mode, an expansion commit re-locates the first visible row
3586
+ * (the content anchor, with its partial offset) in the NEW plan and
3587
+ * writes `newIndex × slotHeight + relativeTop` — the rows under the
3588
+ * cursor stay put across tree/detail expand AND collapse. Uniform slot
3589
+ * heights only (`rowHeight`/`virtualScroll.itemHeight` functions are
3590
+ * pixel-only — the variable-height offset tree is child-internal);
3591
+ * non-virtual tables are inert (documented fiat); full-set restores
3592
+ * (`expandAll` / `persistState` replay) fall back to the virtualizer's
3593
+ * re-clamp; a single-key commit stays exact. Additive; default off
3594
+ * (fail-closed).
3595
+ */
3596
+ expandScrollPreserve?: boolean;
3597
+ /** Batch CJ (iris 独有 — vxe has no shortcut help): show a `?` toolbar
3598
+ * trigger that opens a floating panel listing every built-in keyboard
3599
+ * shortcut with its EFFECTIVE key — the same normalized map every handler
3600
+ * matches against, so `keymap` remaps reflect live and a listed key always
3601
+ * actually works. Read-only reference (no rebind UI). Additive; default
3602
+ * off (fail-closed).
3603
+ */
3604
+ shortcutHints?: boolean;
3605
+ /** Header select-all toggle (additive — not in vxe's emits, batch V): fired with the PRE-toggle header state and the current selection keys. */
3606
+ onSelectAllChange?: (state: boolean | 'indeterminate', selection: Array<string | number>) => void;
3607
+ /** 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). */
3608
+ onScroll?: (params: IrisTableScrollParams) => void;
3609
+ /** Render an expandable detail panel beneath a row. */
3610
+ renderDetail?: IrisTableRenderDetail<Row>;
3611
+ /** Which rows can expand a detail panel. */
3612
+ rowExpandable?: IrisTableRowExpandable<Row>;
3613
+ /** Initially-expanded row keys (uncontrolled). Shared by detail rows + tree rows. */
3614
+ defaultExpandedRowKeys?: Array<string | number>;
3615
+ /** Expand every tree row that has children on mount (vxe expand-config
3616
+ * expandAll parity). One-shot: seeds the expansion model with all tree keys
3617
+ * on the first data arrival (proxy pages load async). Default false. */
3618
+ expandAll?: boolean;
3619
+ /** 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). */
3620
+ onExpandedRowsChange?: (keys: Array<string | number>) => void;
3621
+ /** Detail expand toggle (vxe toggle-row-expand parity): `expanded` is the NEW state after the toggle. */
3622
+ onExpandChange?: (row: Row, expanded: boolean) => void;
3623
+ /** Tree expand toggle (vxe toggle-tree-expand parity): `expanded` is the NEW state after the toggle. */
3624
+ onTreeExpandChange?: (row: Row, expanded: boolean) => void;
3625
+ /** Read a row's child rows to render the table as a tree. */
3626
+ getSubRows?: (row: Row) => Row[] | undefined;
3627
+ /** 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). */
3628
+ lazyLoad?: (row: Row, load: (children: Row[]) => void) => void;
3629
+ /** Batch CL (iris 独有 — vxe has no expand animation):
3630
+ * animate detail-panel and tree-row expansion with a max-height + opacity
3631
+ * enter transition (token-driven — `--iris-table-expand-max` cap and
3632
+ * `--iris-duration-md` duration, both with fallbacks;
3633
+ * `prefers-reduced-motion: reduce` turns the animation off entirely).
3634
+ * Pure CSS entrance — zero state/effect; root tree rows (depth 0) stay
3635
+ * static. Inert in virtual mode (lazy slots would replay the animation on
3636
+ * scroll-mount). Additive; default off (fail-closed).
3637
+ */
3638
+ expandAnimation?: boolean;
3639
+ /**
3640
+ * Enable WAI-ARIA grid keyboard navigation (single-tabstop roving cell
3641
+ * focus). Arrow keys move one cell; Home/End jump to the row's first/last
3642
+ * cell; PageUp/PageDown jump 10 rows (clamped; virtual tables also scroll
3643
+ * the viewport ±10 × row height); Tab/Shift+Tab move row-major to the
3644
+ * next/prev cell (clamped at the bounds — no wrap, focus never leaves the
3645
+ * table); Enter is an alias of ArrowDown (F2 stays the edit-start key).
3646
+ * While an inline editor is open the editor's own keys win — Tab commits
3647
+ * and moves to the next editable column (batch J), unchanged.
3648
+ */
3649
+ keyboardNavigation?: boolean;
3650
+ /** Batch AN shortcuts (iris 独有 — vxe keyboardConfig has no edit/clear
3651
+ * keys): F2 begins editing the focused cell's column (when editable),
3652
+ * Delete/Backspace clears it to `''` — one batched `commitRowList`
3653
+ * (undo-covered via the undo funnel). Requires `keyboardNavigation`'s
3654
+ * focused-cell state (single-tabstop roving cell focus); without it the
3655
+ * shortcuts are inert. While an inline editor is open the editor's own
3656
+ * keys win. Additive — default off. */
3657
+ tableShortcuts?: boolean;
3658
+ /** Batch DR (iris 独有): edit keys for the focused editable cell. F2 is
3659
+ * always included when this prop is present; Enter and Space extend it. */
3660
+ editKeys?: Array<'F2' | 'Enter' | 'Space'>;
3661
+ /** Batch BG (iris 独有 — vxe keyboardConfig has no rebinding): rebind the
3662
+ * built-in shortcut keys. ONE key spec string per action
3663
+ * (`Modifier+Key`, case-insensitive; `Ctrl`/`Cmd`/`Meta` share one
3664
+ * ctrl-or-meta flag — `Ctrl+C` matches Ctrl OR Cmd). Actions:
3665
+ * `edit` (default F2) / `clear` (Delete, Backspace) need `tableShortcuts`;
3666
+ * `undo` (Ctrl+Z) / `redo` (Ctrl+Y, Ctrl+Shift+Z) need `undo`;
3667
+ * `copy` (Ctrl+C) / `paste` (Ctrl+V) need `clipConfig`;
3668
+ * `fill` (Ctrl+D — one-step drag-down) needs `rangeFill` + a live range;
3669
+ * `query` (Ctrl+K — focuses the query input) needs the controlled `query`.
3670
+ * An override REPLACES that action's bindings wholesale (aliases included);
3671
+ * invalid specs (`''` / `'Meta'` / `'Ctrl+'` …) are dropped fail-closed —
3672
+ * the action keeps its default. Modifiers match exactly: `Ctrl+Shift+Z`
3673
+ * redoes, `Alt+Ctrl+Z` is inert. Additive — default off (defaults unchanged). */
3674
+ keymap?: Partial<Record<_iris_ui_kit_core.IrisTableKeyAction, string>>;
3675
+ /** Batch DJ (iris 独有 — vxe keyboardConfig has no focus gate): shortcut
3676
+ * scope for the table's WINDOW keydown listeners (undo/redo, clip
3677
+ * copy/paste, fnr Ctrl+F + Escape, batch-edit Escape). `hotkeyScope`
3678
+ * (default `true`) gates the shortcuts to fire only while the focus is
3679
+ * INSIDE the table (`rootRef.contains(e.target)` — the focused element,
3680
+ * read live from the keydown target, no extra focus/blur state). Set it to
3681
+ * `false` for the permissive compatibility mode where the same bindings
3682
+ * fire regardless of where the focus is. `outerScope` (default `false`)
3683
+ * forces the GLOBAL scope (fire from anywhere) and wins over
3684
+ * `hotkeyScope`. Fail-closed by default: fnr/batch-edit tighten from
3685
+ * anywhere → in-table; undo/clip keep their existing in-table behavior. */
3686
+ hotkeyScope?: boolean;
3687
+ /** Force GLOBAL shortcut scope (fire from anywhere, ignoring
3688
+ * `hotkeyScope`). Default `false`. */
3689
+ outerScope?: boolean;
3690
+ /** 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). */
3691
+ groupBy?: string[];
3692
+ /** Batch BH (iris 独有 — vxe group-config has no collapse): controlled set of
3693
+ * collapsed group keys. Keys are `String(cell value)` of the `groupBy` column —
3694
+ * the same identity `data-iris-group-key` carries. When set, the rendered body
3695
+ * only changes after the parent writes the prop back (no optimistic flip).
3696
+ * Inert without `groupBy` / in tree mode. */
3697
+ groupCollapsed?: Array<string | number>;
3698
+ /** Default collapsed group keys (uncontrolled mode). */
3699
+ defaultGroupCollapsed?: Array<string | number>;
3700
+ /** Fired on every group-header toggle with the next collapsed keys, in BOTH
3701
+ * controlled and uncontrolled modes (lift-ready). */
3702
+ onGroupCollapseChange?: (next: Array<string | number>) => void;
3703
+ /** Enable virtual scrolling for the body. */
3704
+ virtualScroll?: IrisTableVirtualOptions;
3705
+ /** 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). */
3706
+ rowHeight?: number | ((index: number) => number);
3707
+ /** 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'. */
3708
+ persistState?: IrisTablePersistConfig;
3709
+ /** Batch DM (iris 独有): periodically persist the complete exported view
3710
+ * state to a separate storage key and restore it once on mount. */
3711
+ autoSaveState?: IrisTableAutoSaveStateConfig;
3712
+ }
3713
+
3714
+ interface IrisTableLayoutProps<Row extends Record<string, unknown> = Record<string, unknown>> {
3715
+ columns: IrisTableColumn<Row>[];
3716
+ /** Table data. Optional when `proxyConfig` is set (server-side source). */
3717
+ data?: Row[];
2414
3718
  /** Field to use as the row key. */
2415
3719
  rowKey?: string;
2416
3720
  /** Selection mode. */
@@ -2421,50 +3725,630 @@ interface IrisTableProps<Row extends Record<string, unknown> = Record<string, un
2421
3725
  sort?: IrisTableSortState | null;
2422
3726
  defaultSort?: IrisTableSortState | null;
2423
3727
  onSortChange?: (next: IrisTableSortState | null) => void;
3728
+ /** Multi-column sort (vxe sort-config.multiple parity): header clicks
3729
+ * append/cycle columns in click order instead of replacing. Default false. */
3730
+ multiSort?: boolean;
3731
+ /** Controlled multi-column sort state (multiSort mode). */
3732
+ multiSortState?: IrisTableSortState[];
3733
+ /** Default multi-column sort (multiSort mode, uncontrolled). */
3734
+ defaultMultiSort?: IrisTableSortState[];
3735
+ onMultiSortChange?: (next: IrisTableSortState[]) => void;
2424
3736
  striped?: boolean;
3737
+ /** Size preset (vxe-grid size parity): medium / small / mini. */
3738
+ size?: 'medium' | 'small' | 'mini';
3739
+ /**
3740
+ * Row-density preset (iris 独有 — vxe has no density concept): three tiers
3741
+ * of row/cell padding stacked on top of `size` (both write
3742
+ * `--iris-cell-pad-y`; density wins on ties). Default comfortable.
3743
+ */
3744
+ density?: IrisTableDensity;
3745
+ /**
3746
+ * Toolbar density-toggle button (iris 独有 — vxe has no density toggle):
3747
+ * cycles comfortable → compact → cozy → comfortable; while shown, the
3748
+ * button state wins over the `density` prop.
3749
+ */
3750
+ densityToggle?: boolean;
3751
+ /** First sequence number (vxe seq-config.startIndex parity). Default 1. */
3752
+ seqStartIndex?: number;
3753
+ /** Custom sequence renderer (vxe seq-config.seqMethod parity). */
3754
+ seqMethod?: (params: IrisTableSeqMethodParams) => string | number;
3755
+ /** Current (highlighted) row key (vxe row-config.isCurrent parity). */
3756
+ currentRowKey?: string | number;
3757
+ /** Fired when the current row changes (row click). */
3758
+ onCurrentRowChange?: (key: string | number, row: Row) => void;
3759
+ /** Veto a current-row change: return false to keep the previous row. */
3760
+ beforeCurrentRowChange?: (key: string | number, row: Row) => boolean | void;
3761
+ /** Current (highlighted) column key (vxe column-config.isCurrent parity). */
3762
+ currentColumnKey?: string;
3763
+ /** Fired when the current column changes (header click). */
3764
+ onCurrentColumnChange?: (key: string) => void;
3765
+ /** Header cell click (vxe header-click parity). Fired after the sort toggle on sortable headers. */
3766
+ onHeaderClick?: (column: IrisTableColumn<Row>) => void;
3767
+ /** Veto a current-column change: return false to keep the previous column. */
3768
+ beforeCurrentColumnChange?: (key: string) => boolean | void;
3769
+ /** Hide the header row(s) (vxe show-header parity). Default true. */
3770
+ showHeader?: boolean;
3771
+ /**
3772
+ * Custom footer rows (vxe footer-data parity): rendered below the summary
3773
+ * row, one grid row per entry; structure matches `data`.
3774
+ */
3775
+ footerData?: Row[];
3776
+ /** 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. */
3777
+ footerMethod?: (params: IrisTableFooterMethodParams<Row>) => Row[];
3778
+ /** 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. */
3779
+ footerSpanMethod?: IrisTableFooterSpanMethod<Row>;
3780
+ /** Header cell alignment (vxe header-align parity): `headerAlign` wins over
3781
+ * the column's `align`, then 'left'. Applies to flat + grouped headers. */
3782
+ headerAlign?: IrisTableAlign;
3783
+ /** Footer/summary cell alignment (vxe footer-align parity): `footerAlign`
3784
+ * wins over the column's `align`. Applies to summary, footer-method, footer-data. */
3785
+ footerAlign?: IrisTableAlign;
3786
+ /**
3787
+ * Auto-detect column types (batch CX, iris 独有 — vxe requires the caller
3788
+ * to declare `sortType` per column; no auto inference): on FIRST data
3789
+ * arrival, each leaf column's value kind (`string`/`number`/`date`/
3790
+ * `boolean`) is inferred by the core `detectColumnType` from its first 50
3791
+ * non-nullish values (all-samples-agree; mixed columns and numeric/boolean
3792
+ * STRINGS fall back to `string`). Detected columns receive the matching
3793
+ * default alignment + `sortType` — `number` → right-aligned + `'number'`
3794
+ * sort, everything else → left + `'string'` — filling ONLY the fields the
3795
+ * caller left `undefined` (explicit `align`/`sortType` always win; preset
3796
+ * defaults survive). One-shot per mount (later data re-feeds never
3797
+ * re-detect); SSR-safe (effect-driven, the fill lands post-hydration).
3798
+ * Default false — byte-identical with the pre-prop render path.
3799
+ */
3800
+ autoDetectTypes?: boolean;
3801
+ /** Batch CM (iris 独有 — vxe has no summary sticky parity): `'sticky'` pins
3802
+ * the GLOBAL summary row (op row or footerMethod rows — the two renders
3803
+ * that occupy the same footer slot) to the viewport's bottom edge inside
3804
+ * the fixed-height scroll container (`position: sticky; bottom: 0`;
3805
+ * gated by `[data-iris-table-fixed-height]`, same z-index 1 as pinned
3806
+ * columns). Two explicit fiats: per-group summary rows never stick (groups
3807
+ * would fight over the bottom edge) and footerData rows never stick
3808
+ * (contractually rendered below the summary). Pure CSS additive; default
3809
+ * `'default'` — fail-closed, no sticky attr. */
3810
+ summaryRowStyle?: 'default' | 'sticky';
3811
+ /**
3812
+ * Decimal places for summary/footer aggregate values (vxe
3813
+ * aggregateAccuracyConfig parity, batch P): a finite numeric op result is
3814
+ * rounded via `Number(value.toFixed(n))` at the single summary point
3815
+ * (global + per-group summaries), before `renderSummary` — custom renderers
3816
+ * see the rounded value. Non-finite results are left untouched. Values
3817
+ * outside 0–100 (inclusive) are ignored — no rounding (`toFixed`
3818
+ * RangeError guard). Default: no rounding.
3819
+ */
3820
+ aggregateAccuracy?: number;
3821
+ /** Per-row class hook (vxe row-class-name parity). */
3822
+ rowClassName?: (row: Row, rowIndex: number) => string;
3823
+ /** Per-cell class hook (vxe cell-class-name parity). */
3824
+ cellClassName?: (row: Row, column: IrisTableColumn<Row>, rowIndex: number) => string;
3825
+ /** Per-header-cell class hook (vxe header-cell-class-name parity). */
3826
+ headerCellClassName?: (column: IrisTableColumn<Row>) => string;
3827
+ /** Per-footer-cell class hook (vxe footer-cell-class-name parity). */
3828
+ footerCellClassName?: (column: IrisTableColumn<Row>, rowIndex: number) => string;
3829
+ /** Per-row inline style hook (vxe row-style parity). */
3830
+ rowStyle?: (row: Row, rowIndex: number) => React.CSSProperties;
3831
+ /** Per-cell inline style hook (vxe cell-style parity). */
3832
+ cellStyle?: (row: Row, column: IrisTableColumn<Row>, rowIndex: number) => React.CSSProperties;
3833
+ /** 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). */
3834
+ conditionalStyles?: IrisTableConditionalStyle<Row>[];
3835
+ /** 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. */
3836
+ formulaTables?: Record<string, Row[]>;
3837
+ /** 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. */
3838
+ exportNames?: Array<{
3839
+ key: string;
3840
+ ref: () => Row[];
3841
+ }>;
3842
+ /** Per-header-cell inline style hook (vxe header-cell-style parity). */
3843
+ headerCellStyle?: (column: IrisTableColumn<Row>) => React.CSSProperties;
3844
+ /** Per-footer-cell inline style hook (vxe footer-cell-style parity). */
3845
+ footerCellStyle?: (column: IrisTableColumn<Row>, rowIndex: number) => React.CSSProperties;
3846
+ /** Cell click (vxe cell-click parity). Fired after internal handlers. */
3847
+ onCellClick?: (params: IrisTableCellClickParams<Row>) => void;
3848
+ /** Cell double-click (vxe cell-dblclick parity). Fired AFTER the inline edit starts on editable columns; non-editable columns fire it too. */
3849
+ onCellDblClick?: (params: IrisTableCellClickParams<Row>) => void;
2425
3850
  bordered?: boolean;
3851
+ /**
3852
+ * Rounded root corners (vxe-grid round parity, batch P): the root gets
3853
+ * `border-radius: var(--iris-radius-lg, 10px)` when `bordered && round`;
3854
+ * otherwise the default md radius applies.
3855
+ */
3856
+ round?: boolean;
3857
+ /**
3858
+ * Cell padding override (vxe-grid deprecated `padding` parity, batch P):
3859
+ * sets `--iris-cell-pad` on the root; every cell padding reads
3860
+ * `var(--iris-cell-pad, var(--iris-cell-pad-y, 8px) 12px)`, so the size
3861
+ * presets (small/mini) still win through `--iris-cell-pad-y`.
3862
+ */
3863
+ padding?: string;
2426
3864
  /** Enable column resizing (drag the header's trailing edge or focus + arrow keys). */
2427
3865
  resizableColumns?: boolean;
3866
+ /** Batch DS (iris 独有): show the live pixel width while a resize drag is active. */
3867
+ widthHint?: boolean;
3868
+ /**
3869
+ * Auto-fit column widths on double-click (iris 独有, batch DG — vxe has no
3870
+ * auto-resize): when true (WITH `resizableColumns`, so the handle exists),
3871
+ * double-clicking a column boundary measures the widest rendered content
3872
+ * (header + body cells, `scrollWidth` already includes both-side padding)
3873
+ * and writes the clamped width via `onColumnWidthsChange` (the same duck
3874
+ * channel as drag/keyboard). Falls back fail-closed: no handle without
3875
+ * `resizableColumns`; virtual scrolling measures only the rendered window
3876
+ * (vxe autoResize behavior). Additive — default off.
3877
+ */
3878
+ autoResizeColumns?: boolean;
2428
3879
  /** Controlled per-column pixel widths, keyed by column `key`. */
2429
3880
  columnWidths?: IrisTableColumnWidths;
2430
3881
  defaultColumnWidths?: IrisTableColumnWidths;
2431
3882
  onColumnWidthsChange?: (next: IrisTableColumnWidths) => void;
3883
+ /**
3884
+ * Toolbar reset-widths button (iris 独有, batch BO): clicking it calls
3885
+ * `onColumnWidthsChange({})` — the empty map means zero overrides, so every
3886
+ * column falls back to its declared width. Like `zoomConfig`, this prop
3887
+ * alone does not create the toolbar.
3888
+ */
3889
+ columnWidthsReset?: boolean;
3890
+ /**
3891
+ * Column header pin menu (batch BX, iris 独有 — vxe has no built-in
3892
+ * header pin menu): when true, right-clicking a column HEADER opens a
3893
+ * built-in menu — 固定左 (key `__iris-pin-left`) when the column is not
3894
+ * pinned, 取消固定 (key `__iris-unpin`) when it is pinned left OR right
3895
+ * (the item flips with the column's CURRENT pin state, single and mutually
3896
+ * exclusive — spec has no pin-right action). The menu is fully independent
3897
+ * of `contextMenu` (which only opens on body cells and never on headers):
3898
+ * `columnPinMenu` works with NO `contextMenu` configured, and the two are
3899
+ * separate floating instances — opening one closes the other. Every action
3900
+ * fires `onColumnPinnedChange` in BOTH controlled and uncontrolled modes
3901
+ * (`onColumnWidthsChange` dual-channel precedent, no optimistic flip when
3902
+ * controlled); without `pinnedColumns` the table holds the pin state
3903
+ * internally and the static `col.pinned` declaration seeds the fallback.
3904
+ * Additive — default off.
3905
+ */
3906
+ columnPinMenu?: boolean;
3907
+ /**
3908
+ * Controlled per-column pin state (batch BX): column key → `'left'` /
3909
+ * `'right'` / `null` (unpinned). When set, the map is the ONLY read source
3910
+ * for the rendered pin state — an explicit `null` entry overrides a static
3911
+ * `col.pinned` declaration (controlled-null-wins); absent keys fall back to
3912
+ * the column's own declaration, so `{}` never unpins static pins.
3913
+ */
3914
+ pinnedColumns?: Record<string, 'left' | 'right' | null>;
3915
+ /**
3916
+ * Fired on every pin-menu action with the column key and the next side
3917
+ * (`null` = unpin), in both controlled and uncontrolled modes (lift-ready).
3918
+ */
3919
+ onColumnPinnedChange?: (key: string, side: 'left' | 'right' | null) => void;
3920
+ /**
3921
+ * Pinned-count boundary drag (batch CV, iris 独有 — vxe has no pinned
3922
+ * boundary handle): when true, the LAST left-pinned leaf header's trailing
3923
+ * edge carries a draggable separator handle (8px grip + 2px primary line,
3924
+ * sticky inside the pinned cell) that adjusts the number of left-pinned
3925
+ * columns — drag right pins more / drag left unpins, commit-on-release (a
3926
+ * translateX ghost follows the pointer while dragging); Arrow-Left/Right
3927
+ * nudge the count by one. The commit writes `setColumnPinned('left' |
3928
+ * null)` per CHANGED column (the SAME dual-channel throat as the pin menu —
3929
+ * `onColumnPinnedChange` fires per column in both modes, no optimistic
3930
+ * flip when controlled) and then fires `onPinnedCountChange` once; no-op
3931
+ * drags fire nothing. Left-only count: no handle without at least one
3932
+ * left-pinned column; the boundary never crosses the first right-pinned
3933
+ * index (hard cap); widths approximate via the pinnedOffsets fallback
3934
+ * chain (non-numeric → default, fiat). While on, the boundary column's
3935
+ * `resizableColumns` handle is suppressed (a resize grip on the same edge
3936
+ * would fight the boundary drag). Additive — default off.
3937
+ */
3938
+ pinnedDrag?: boolean;
3939
+ /** Fired once per pinned-boundary commit with the new left-pinned column count (0 = none), AFTER the per-column `onColumnPinnedChange` calls. */
3940
+ onPinnedCountChange?: (count: number) => void;
2432
3941
  /** Called when a data row is clicked. Interactive child controls stop propagation. */
2433
3942
  onRowClick?: (row: Row, rowIndex: number) => void;
2434
- /** Called when an inline-editable cell is committed with a changed value. */
2435
- onCellEdit?: (event: IrisTableCellEditEvent<Row>) => void;
2436
- /** Render an expandable detail panel beneath a row. */
2437
- renderDetail?: IrisTableRenderDetail<Row>;
2438
- /** Which rows can expand a detail panel. */
2439
- rowExpandable?: IrisTableRowExpandable<Row>;
2440
- /** Initially-expanded row keys (uncontrolled). Shared by detail rows + tree rows. */
2441
- defaultExpandedRowKeys?: Array<string | number>;
2442
- /** Notified with the expanded row keys whenever they change. */
2443
- onExpandedRowsChange?: (keys: Array<string | number>) => void;
2444
- /** Read a row's child rows to render the table as a tree. */
2445
- getSubRows?: (row: Row) => Row[] | undefined;
2446
- /** Enable WAI-ARIA grid keyboard navigation. */
2447
- keyboardNavigation?: boolean;
2448
- /** Enable virtual scrolling for the body. */
2449
- virtualScroll?: IrisTableVirtualOptions;
3943
+ /** Row double-click (vxe row-dblclick parity). */
3944
+ onRowDblClick?: (row: Row, rowIndex: number) => void;
3945
+ /**
3946
+ * Column visibility (vxe-grid columnConfig.visible parity). Map of
3947
+ * column key visible (default true). Hidden columns are not rendered.
3948
+ */
3949
+ columnVisibility?: Record<string, boolean>;
3950
+ /** Fired when visibility changes (parent owns the map). */
3951
+ onColumnVisibilityChange?: (next: Record<string, boolean>) => void;
3952
+ /** 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. */
3953
+ columnOrder?: string[];
3954
+ /** Fired when the panel confirms a new order. `undefined` clears the order (parent drops `columnOrder`). */
3955
+ onColumnOrderChange?: (order: string[] | undefined) => void;
3956
+ /** Client-side filters (vxe-grid filterConfig parity, local mode): column key → filter text; rows filtered with the core filterSort material (substring, case-insensitive). */
3957
+ filters?: Record<string, string>;
3958
+ /** 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`. */
3959
+ onFiltersChange?: (next: Record<string, string>) => void;
3960
+ /** 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. */
3961
+ filterValues?: IrisTableFilterValues;
3962
+ /** Fired when the filter panel confirms or clears a column's checked set. */
3963
+ onFilterValuesChange?: (next: IrisTableFilterValues) => void;
3964
+ /** Search form (vxe-grid formConfig parity). */
3965
+ formConfig?: IrisTableFormConfig;
3966
+ /** Toolbar (vxe-grid toolbarConfig parity, minimal built-ins). */
3967
+ toolbar?: {
3968
+ title?: string;
3969
+ /** Fired by the refresh button. */
3970
+ onRefresh?: () => void;
3971
+ /** Show the column-visibility toggle button. */
3972
+ columnSettings?: boolean;
3973
+ /** 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. */
3974
+ customConfig?: IrisTableCustomConfig;
3975
+ /** Enable the CSV import button. Receives parsed rows (header → keys). */
3976
+ onImport?: (rows: Record<string, unknown>[]) => void;
3977
+ /** Fired by the export button (vxe toolbar export parity, batch L). */
3978
+ onExport?: () => void;
3979
+ /** Custom action buttons rendered after the built-ins (vxe toolbar buttons parity). */
3980
+ buttons?: Array<{
3981
+ key: string;
3982
+ label: string;
3983
+ onClick: () => void;
3984
+ icon?: string;
3985
+ }>;
3986
+ /** 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). */
3987
+ batch?: {
3988
+ label: string;
3989
+ onClick: (keys: Array<string | number>) => void;
3990
+ icon?: string;
3991
+ edit?: boolean;
3992
+ };
3993
+ };
3994
+ /** Zoom overlay (vxe toolbar zoom parity, batch U): when `showButton`, the
3995
+ * toolbar renders a toggle (⛶ when not zoomed, ✕ when zoomed) that pins the
3996
+ * table root as a fullscreen overlay (fixed, inset 0, popover z-index);
3997
+ * Esc exits. Local state — no parent props needed. */
3998
+ zoomConfig?: {
3999
+ showButton?: boolean;
4000
+ };
4001
+ /** Import preview (iris 独有 — vxe has no pre-import preview): when true,
4002
+ * the toolbar ⇪ CSV import shows a centered modal previewing the first 5
4003
+ * parsed rows (plus a total-count note when more) before anything lands;
4004
+ * 确认 calls `toolbar.onImport` with ALL parsed rows, 取消 / Esc / backdrop
4005
+ * close with zero calls. Default false — the import lands directly (vxe
4006
+ * parity). */
4007
+ importPreview?: boolean;
4008
+ /** Section layouts (vxe-grid layouts parity, batch U, suppression-only):
4009
+ * `form`/`toolbar` `'hidden'` skips that section (the config stays
4010
+ * accepted); `pager` `'hidden'` skips the proxy pager. Defaults render
4011
+ * every section exactly as before. */
4012
+ layouts?: {
4013
+ form?: 'top' | 'hidden';
4014
+ toolbar?: 'top' | 'hidden';
4015
+ pager?: 'bottom' | 'hidden';
4016
+ };
4017
+ /** Render with print-friendly styles (hides the toolbar, keeps rows). */
4018
+ printable?: boolean;
4019
+ }
4020
+
4021
+ interface IrisTableQueryProps<Row extends Record<string, unknown> = Record<string, unknown>> {
4022
+ /** Named view presets (batch AH, iris 独有) — toolbar select of saved snapshots. */
4023
+ views?: IrisTableViewConfig;
4024
+ /** Fired when the active view changes (select / save / delete clears null). */
4025
+ onActiveViewChange?: (key: string | null) => void;
4026
+ /** Batch CT — iris 独有 (vxe has no parity).
4027
+ * A `role=tablist` strip rendered ABOVE the toolbar: clicking a tab applies
4028
+ * each name in `views` IN ORDER through the same selectView path the toolbar
4029
+ * select uses (unknown names are skipped fail-inert; when several views touch
4030
+ * the same piece the last applied view wins and the toolbar select mirrors
4031
+ * that last view). Fail-closed: without the prop nothing renders, and no tab
4032
+ * is active until the first click. */
4033
+ tableTabs?: IrisTableTab[];
4034
+ /** Natural-language query (iris 独有): controlled string parsed by core
4035
+ * `parseTableQuery` (`age > 25 and role in (Test, PM) sort by name asc`);
4036
+ * the toolbar query input shows while present, parsed filters AND-merge
4037
+ * (`=`/`contains` → substring, `in` → filterValues OR-match, relational →
4038
+ * rules); `sort by` seeds only with no sort prop set; proxy comma-joins
4039
+ * substring/in into the remote filter map. Controlled-only. */
4040
+ query?: string;
4041
+ /** Fired on every keystroke (parent owns the string). */
4042
+ onQueryChange?: (next: string) => void;
2450
4043
  /** Render only the horizontally-visible columns plus pinned columns and overscan. */
2451
4044
  columnVirtualization?: boolean;
4045
+ /**
4046
+ * Selection summary (batch AP, iris 独有 — vxe has no parity feature, the
4047
+ * header count is its closest cousin): when `selectable === 'multi'` and
4048
+ * rows are selected, the toolbar renders `已选 N 行`
4049
+ * (`data-iris-selection-summary`, i18n `table.selectionSummary`) plus a
4050
+ * `· 合计 X` per leaf column with `summary === 'sum'` (the SAME aggregate
4051
+ * material + `aggregateAccuracy` rounding + `String(value)` formatting the
4052
+ * summary row uses, computed over the SELECTED rows in bodyData order) and
4053
+ * a clear button (`data-iris-selection-clear`) that runs the shared
4054
+ * `clearSelection` path. Additive — default off.
4055
+ */
4056
+ selectionSummary?: boolean;
2452
4057
  /** Enable rectangular cell-range selection. */
2453
4058
  cellRange?: boolean;
2454
- /** Empty state node (replaces the row body when `data` is empty). */
2455
- emptyState?: ReactNode;
4059
+ /**
4060
+ * Excel-style drag fill (batch AQ, iris 独有 — vxe has no fill parity):
4061
+ * when `cellRange` has a live selected range (≥1 cell), a fill handle
4062
+ * (`data-iris-range-fill`, 6px primary square at the range's bottom-right
4063
+ * cell) appears; dragging it DOWN or RIGHT cyclically fills the target
4064
+ * rectangle from the source range values (`(r, c)` ← source
4065
+ * `((r - start.row) % rangeRows + start.row, …)`), formula columns and
4066
+ * keyless rows skipped, through ONE batched `commitRowList`, then extends
4067
+ * the range to the drag end (Excel parity). Dragging UP/LEFT is ignored
4068
+ * (the handle only grows the range). Additive — default off.
4069
+ */
4070
+ rangeFill?: boolean;
4071
+ /**
4072
+ * Cell drag-move (batch CN, iris 独有 — vxe has no cell-move parity): when
4073
+ * `cellRange` has a live selected range (≥1 cell), a move grip
4074
+ * (`data-iris-range-move`, 12×4 primary pill on the range's top edge at its
4075
+ * top-left cell) appears; dragging it to another cell CUT-MOVES the whole
4076
+ * block there (剪切移动 — source cells not covered by the destination rect
4077
+ * are cleared; locked/readonly and formula cells survive both phases) and
4078
+ * the selection follows the moved block (Excel parity). The drag end clamps
4079
+ * so the block always fits (down/up/right/left 越界). Zero-commit no-op
4080
+ * when the drag stays on the source block. Inert without `cellRange`.
4081
+ * Additive — default off.
4082
+ */
4083
+ cellDrag?: boolean;
4084
+ /** 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.
4085
+ * 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'`.
4086
+ * 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.
4087
+ */
4088
+ clipConfig?: {
4089
+ copy?: boolean;
4090
+ paste?: boolean;
4091
+ copyFormat?: 'tsv' | 'csv' | 'html';
4092
+ copyWithFormat?: boolean;
4093
+ };
4094
+ /** Paste options (iris 独有 — vxe-grid clipboard-config has no overflow-insert switch):
4095
+ * `insertIfOverflow` makes a SINGLE-CELL paste append clipboard lines that run past
4096
+ * the last row as brand-new rows (auto-id keys via `insertRowInList`, surplus cells
4097
+ * dropped, locked/readonly columns skipped) — one batched commit. Multi-cell
4098
+ * rectangle pastes stay clipped (fiat) and the default (absent) keeps batch-O
4099
+ * overflow-drop behavior byte-identical. Additive — default off.
4100
+ */
4101
+ pasteOptions?: {
4102
+ insertIfOverflow?: boolean;
4103
+ };
4104
+ /** 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. */
4105
+ fnr?: boolean;
4106
+ /** Batch CK (iris 独有 — vxe has no inline search highlight): a
4107
+ * case-insensitive literal-substring search over each text cell's display
4108
+ * chain (mask → formatter ?? raw — the same text autoLink consumes); every
4109
+ * occurrence renders as an inline `<mark data-iris-search-hit>` (the
4110
+ * surface-selected token — the same search-highlight language fnr uses for
4111
+ * matched cells). Display-only: no bar, no match state, no write-back —
4112
+ * the distinction from fnr is the mechanism, not the query.
4113
+ * `render`/`html`/`link`/`autoLink`/sparkline cells are untouched
4114
+ * (documented fiats). Additive; default off (fail-closed).
4115
+ */
4116
+ searchHighlight?: string;
4117
+ /** 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. */
4118
+ undo?: boolean;
4119
+ /** Shift-click checkbox range selection (vxe checkboxConfig `isShiftKey`
4120
+ * parity, batch G): shift-clicking a row checkbox toggles every
4121
+ * checkMethod-eligible row between the last-clicked anchor row and the
4122
+ * target (in body order); a plain click just moves the anchor. The header
4123
+ * select-all resets the anchor. Default false. */
4124
+ checkboxRange?: boolean;
4125
+ /** Row-selection drag range (batch BT, iris 独有 — vxe has no mouse-drag
4126
+ * checkbox range): pressing the row-selection cell in multi mode and
4127
+ * dragging past the 4px threshold continuously checks every
4128
+ * checkMethod-eligible row between the pressed anchor row and the hovered
4129
+ * row (closed interval in body order); checkMethod-disabled rows are
4130
+ * skipped. The applied set only ever grows during one drag (reverse drags
4131
+ * shrink the interval but never uncheck); a plain click still toggles a
4132
+ * single row. Default false. */
4133
+ selectionDrag?: boolean;
4134
+ /** Empty state node (replaces the row body when `data` is empty). Also accepts
4135
+ * an `IrisTableEmptyState` descriptor (iris 独有 — vxe has no empty-state
4136
+ * action button): `{ text?, action? }` renders the text plus an inline action
4137
+ * button on the same row. */
4138
+ emptyState?: React.ReactNode | IrisTableEmptyState;
2456
4139
  /** Show the loading state instead of rows. */
2457
4140
  loading?: boolean;
2458
4141
  /** Show the error state instead of rows (takes precedence over loading). */
2459
4142
  error?: boolean;
2460
4143
  /** Custom loading-state node. */
2461
- loadingState?: ReactNode;
4144
+ loadingState?: React.ReactNode;
2462
4145
  /** Custom error-state node. */
2463
- errorState?: ReactNode;
4146
+ errorState?: React.ReactNode;
2464
4147
  /** Fired by the built-in Retry button in the error state row. */
2465
4148
  onRetry?: () => void;
2466
- style?: CSSProperties;
2467
- className?: string;
4149
+ /**
4150
+ * Server-side data proxy (vxe-grid proxyConfig parity, query slice). When
4151
+ * set, rows come from the proxy `query` (paged) and a pager renders below
4152
+ * the body; `loading`/`error` are driven by the proxy state.
4153
+ */
4154
+ proxyConfig?: IrisTableProxyConfig<Row>;
4155
+ /** Cell tooltips (vxe-grid tooltipConfig parity, title mode, batch G): a
4156
+ * native `title` on every body cell, content from the callback or the raw
4157
+ * cell value; editing cells are exempt and empty content drops the tooltip.
4158
+ * With `showAll: false`, titles remain only for cells whose single-line
4159
+ * content measures wider than the rendered cell; SSR/jsdom zero-width
4160
+ * layouts fail open and retain the title. */
4161
+ tooltipConfig?: IrisTableTooltipConfig<Row>;
4162
+ /** Cell annotations (iris 独有, batch AZ — vxe has no cell-note concept): a
4163
+ * static map of notes keyed `${rowKey}::${columnKey}` — the same `::`
4164
+ * delimiter as the internal `cellId` (`annotations[cellId(k, col.key)]`).
4165
+ * A noted cell renders a corner badge (`data-iris-cell-note-badge`) + gets
4166
+ * `data-iris-cell-note` + the note as its title (beats `tooltipConfig`);
4167
+ * the dynamic `cellNote` callback wins over this map when both are set. */
4168
+ annotations?: Record<string, string>;
4169
+ /** Dynamic per-cell note (iris 独有, batch AZ): computed from the row +
4170
+ * column — wins over the static `annotations` map. With a note the cell
4171
+ * gets `data-iris-cell-note` + a corner badge + the note as its title
4172
+ * (beats `tooltipConfig`); a null/'' note renders nothing. */
4173
+ cellNote?: (row: Row, column: IrisTableColumn<Row>) => string | null;
4174
+ /** Hover note preview (batch BM, iris 独有 — vxe has no cell-note concept,
4175
+ * and its tooltip can only show the cell value): with `notePopover`, hovering
4176
+ * a noted cell shows a floating popover (`data-iris-note-popover`, role
4177
+ * tooltip, pure display — pointer-events none) anchored to the cell's badge
4178
+ * corner INSTEAD of the native `title`; Escape / outside pointer-down /
4179
+ * any scroll close it. Content-only: zero i18n / core. */
4180
+ notePopover?: boolean;
4181
+ /**
4182
+ * Annotation editing (batch BB, iris 独有 — vxe has no note editing): when
4183
+ * true, the context menu gains built-in items 添加批注 / 编辑批注 / 删除批注
4184
+ * (keys `__iris-annotate` / `__iris-annotate-edit` / `__iris-annotate-remove`,
4185
+ * i18n `table.annotate(.edit/.remove)`) appended AFTER the summary item,
4186
+ * chosen by the clicked cell's existing note (add when none, edit+remove
4187
+ * when one). The add/edit items open a floating annotate panel
4188
+ * (`data-iris-annotate-panel`) — textarea seeded from
4189
+ * `annotations[cellId(rowKey, col.key)]` + 保存 (`data-iris-annotate-save`)
4190
+ * + 删除 (`data-iris-annotate-remove`, only when a note exists); the remove
4191
+ * item deletes the cell's annotation directly. Requires `contextMenu`;
4192
+ * writes flow through `onAnnotationsChange` — without it the items still
4193
+ * show but save/remove are inert (documented).
4194
+ */
4195
+ annotationEditing?: boolean;
4196
+ /**
4197
+ * Annotation write channel (batch BB, iris 独有): receives the NEXT
4198
+ * annotations map on every annotate-panel save — empty text removes the
4199
+ * cell's key, non-empty sets it — and on remove (menu item or panel
4200
+ * button). The map stays fully controlled: `annotations` remains the read
4201
+ * source and the table holds no internal annotation state (same shape and
4202
+ * ownership as `onFiltersChange`).
4203
+ */
4204
+ onAnnotationsChange?: (next: Record<string, string>) => void;
4205
+ /**
4206
+ * Annotation CSV export (batch DU, iris 独有 — vxe has no note concept, so
4207
+ * no export parity): when true, `tableRef.current.exportAnnotationsCsv()`
4208
+ * serializes every noted cell of the current view as CSV
4209
+ * (`rowKey,column,annotation` — the same cellNoteState resolution as the
4210
+ * render, hidden columns excluded). Additive — default off (fail-closed:
4211
+ * without the prop the handle returns `''`).
4212
+ */
4213
+ exportAnnotations?: boolean;
4214
+ /**
4215
+ * Collaborative-presence cursors (batch BD, iris 独有 — vxe has no cursor
4216
+ * sharing): remote participants' selected cells. Each entry draws a 2px
4217
+ * colored outline on its cell (`data-iris-presence="true"`, outline in the
4218
+ * entry's `color` — first entry wins when several share a cell) plus a
4219
+ * corner label with the participant's name (`data-iris-presence-label`
4220
+ * with `-id`/`-name`). Pure display: the table holds no collaboration
4221
+ * state, so a NEW array reference re-renders while in-place mutation does
4222
+ * not (same controlled contract as `data` / `annotations`).
4223
+ */
4224
+ presence?: IrisTablePresenceEntry[];
4225
+ /** Header cell tooltips (vxe header-tooltip-config parity, batch P): a
4226
+ * native `title` on flat + grouped header cells; empty content drops the
4227
+ * tooltip. */
4228
+ headerTooltipConfig?: {
4229
+ content?: (column: IrisTableColumn<Row>) => string;
4230
+ };
4231
+ /** Footer cell tooltips (vxe footer-tooltip-config parity, batch P): a
4232
+ * native `title` on summary / footer-method / footer-data cells; empty
4233
+ * content drops the tooltip. */
4234
+ footerTooltipConfig?: {
4235
+ content?: (column: IrisTableColumn<Row>) => string;
4236
+ };
4237
+ /**
4238
+ * Right-click context menu (vxe-grid contextMenu parity, batch H). Opens on
4239
+ * body leaf cells only — header, seq, selection, expand, summary and footer
4240
+ * cells never open it. The menu floats at the cursor (virtual anchor),
4241
+ * closes on Escape / outside pointer-down / any scroll, and fires `onSelect`
4242
+ * with the clicked item's key and the cell's grid coordinates.
4243
+ *
4244
+ * Batch BW (iris 独有): EVERY menu unconditionally gains two built-in quick
4245
+ * actions after the user items (and after the value-distribution / summary
4246
+ * items when those props are on, before the annotate items) — 复制值
4247
+ * (key `__iris-copy-value`, i18n `table.copyValue`, copies the cell's
4248
+ * display text — mask → formatter → String — to the clipboard) and 清空
4249
+ * (key `__iris-clear-cell`, i18n `table.clearCell`, writes the cell to ''
4250
+ * through the same commitRowList funnel as the Delete shortcut — undo /
4251
+ * audit / onDataChange covered; locked/readonly cells no-op). Both keys are
4252
+ * intercepted at the onSelect wiring, so the user callback never sees them;
4253
+ * without a clipboard the copy no-ops safely.
4254
+ *
4255
+ * Set `formatActions` to true to additionally append opt-in region format
4256
+ * actions (number to two decimals and uppercase text). They remain
4257
+ * intercepted by the table and use the same commit funnel; the default is
4258
+ * false so an ordinary context menu is unchanged.
4259
+ */
4260
+ contextMenu?: {
4261
+ items: (params: IrisTableContextMenuParams<Row>) => Array<{
4262
+ key: string;
4263
+ label: string;
4264
+ disabled?: boolean;
4265
+ }>;
4266
+ onSelect: (key: string, params: IrisTableContextMenuParams<Row>) => void;
4267
+ formatActions?: boolean;
4268
+ };
4269
+ /**
4270
+ * Value distribution panel (batch AM, iris 独有): when true, the context
4271
+ * menu gains a built-in item (key `__iris_distribution`, i18n
4272
+ * `table.distribution`) that opens a floating panel counting each distinct
4273
+ * value of the CLICKED column over the current body rows — top 20 + a
4274
+ * muted "其余 N 个" fold — computed by the core `valueDistribution`
4275
+ * material over `bodyData` with the `dataIndex ?? key` indirection.
4276
+ * Requires `contextMenu` to be set (the item appends to its items). */
4277
+ valueDistribution?: boolean;
4278
+ }
4279
+
4280
+ /**
4281
+ * vxe-grid proxyConfig parity — the server-side data proxy (query slice).
4282
+ * When set, `data` is ignored: rows come from `query` (paged), the table
4283
+ * renders a pager below the body, and edit write-back keeps working.
4284
+ */
4285
+ interface IrisTableProxyConfig<Row extends Record<string, unknown>> {
4286
+ /**
4287
+ * Fetch one page. 1-based `page`; `sort`/`filters` are the ACTIVE state,
4288
+ * passed through when `remoteSort`/`remoteFilter` are enabled.
4289
+ */
4290
+ query: (params: IrisTableProxyQueryParams) => Promise<{
4291
+ rows: Row[];
4292
+ total: number;
4293
+ }>;
4294
+ /** Auto-load the first page on mount (vxe autoLoad parity). Default true. */
4295
+ autoLoad?: boolean;
4296
+ /** Sort changes re-query the server instead of sorting client-side (vxe proxyConfig.sort). Default false. */
4297
+ remoteSort?: boolean;
4298
+ /** Filter changes re-query the server instead of filtering client-side (vxe proxyConfig.filter). Default false. */
4299
+ remoteFilter?: boolean;
4300
+ /** Rows per page. Default 10. */
4301
+ pageSize?: number;
4302
+ /** Initial page (1-based). Default 1. */
4303
+ defaultPage?: number;
4304
+ /** Cumulative sequence numbers across pages (batch L): with the table `seq`
4305
+ * prop, the seq cell renders `(page - 1) * pageSize + rowIndex + 1` instead of `rowIndex + seqStartIndex`. `seqMethod` still wins. */
4306
+ seq?: boolean;
4307
+ /** Fired when the page changes. */
4308
+ onPageChange?: (page: number, pageSize: number) => void;
4309
+ }
4310
+ /**
4311
+ * Search-form configuration (vxe-grid formConfig parity): a field row above
4312
+ * the toolbar; submit merges values into the filters (client-side or proxy).
4313
+ */
4314
+ interface IrisTableFormConfig {
4315
+ fields: IrisTableFormField[];
4316
+ /** Label of the submit button. Defaults to the i18n `table.formSubmit` key. */
4317
+ submitText?: string;
4318
+ /** Label of the reset button. Defaults to the i18n `table.formReset` key. */
4319
+ resetText?: string;
4320
+ /** Fired on submit with every field's value (empty strings stripped). */
4321
+ onSearch?: (values: Record<string, string>) => void;
4322
+ /** Fired on reset with the reset values (defaults re-applied). */
4323
+ onReset?: (values: Record<string, string>) => void;
4324
+ }
4325
+ /** Empty-state descriptor (iris 独有 — vxe has no empty-state action button):
4326
+ * object form of `emptyState` renders centered text (optional) plus an inline
4327
+ * action button. A plain ReactNode stays on the node path untouched. */
4328
+ interface IrisTableEmptyState {
4329
+ /** Empty-state text (falls back to the localized default when omitted). */
4330
+ text?: ReactNode;
4331
+ /** Action button rendered inline after the text. */
4332
+ action?: {
4333
+ label: string;
4334
+ onClick: () => void;
4335
+ };
4336
+ }
4337
+ /** Pager configuration (vxe-grid pagerConfig parity). */
4338
+ interface IrisTablePagerConfig {
4339
+ /** Rows-per-page options rendered as a size selector next to the pager. A
4340
+ * change re-queries with the new size and resets the page to 1. */
4341
+ pageSizes?: number[];
4342
+ /** Show the total-row count (i18n `table.total`) before the size selector (vxe pagerConfig.showTotal parity). */
4343
+ showTotal?: boolean;
4344
+ }
4345
+ /** Public input surface for the React table adapter. */
4346
+ /** Row-density preset (iris 独有 — vxe has no density concept): the three
4347
+ * tiers stack ON TOP of `size` — both write `--iris-cell-pad-y`, and the
4348
+ * density rules come later in the stylesheet (same specificity, later
4349
+ * wins). Default comfortable. */
4350
+ type IrisTableDensity = 'comfortable' | 'compact' | 'cozy';
4351
+ interface IrisTableProps<Row extends Record<string, unknown> = Record<string, unknown>> extends IrisTableLayoutProps<Row>, IrisTableEditingProps<Row>, IrisTableQueryProps<Row>, IrisTableAdvancedProps<Row> {
2468
4352
  }
2469
4353
 
2470
4354
  /**
@@ -2474,14 +4358,23 @@ interface IrisTableProps<Row extends Record<string, unknown> = Record<string, un
2474
4358
  *
2475
4359
  * Sortable columns cycle `none → asc → desc → none` on click.
2476
4360
  */
2477
- declare function IrisTable<Row extends Record<string, unknown>>({ columns, data, rowKey, selectable, selection: selectionProp, defaultSelection, onSelectionChange, sort: sortProp, defaultSort, onSortChange, striped, bordered, resizableColumns, columnWidths: columnWidthsProp, defaultColumnWidths, onColumnWidthsChange, onRowClick, onCellEdit, renderDetail, rowExpandable, defaultExpandedRowKeys, onExpandedRowsChange, getSubRows, keyboardNavigation, cellRange, virtualScroll, columnVirtualization, emptyState, loading, error, loadingState, errorState, onRetry, style, className, ...rest }: IrisTableProps<Row>): React.ReactElement;
4361
+ 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, headerStats, editDirtyConfig, autoResize, syncResize, responsive, keepSource, zIndex, rowId, mergeFooterItems, rowClassName, cellClassName, headerCellClassName, footerCellClassName, rowStyle, cellStyle, conditionalStyles, headerCellStyle, footerCellStyle, onCellClick, onCellDblClick, bordered, round, padding, resizableColumns, widthHint, autoResizeColumns, columnWidths: columnWidthsProp, defaultColumnWidths, onColumnWidthsChange, columnWidthsReset, columnPinMenu, pinnedColumns, onColumnPinnedChange, pinnedDrag, onPinnedCountChange, onRowClick, onRowDblClick, onCellEdit, onEditStart, onEditClosed, editAutosave, onAutosave, editAutoHeight, charCount, editPreview, pattern, patternFill, columnTotals, expandScrollPreserve, shortcutHints, onSelectAllChange, onScroll, tableRef, onDataChange, checkMethod, pagerConfig, editConfig, validConfig, rowDrag, rowDragBetween, columnDrag, columnVisibility, onColumnVisibilityChange, columnOrder, 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, 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, clipConfig, pasteOptions, fnr, searchHighlight, undo, checkboxRange, selectionDrag, virtualScroll, rowHeight, persistState, autoSaveState, views, onActiveViewChange, tableTabs, query, onQueryChange, columnVirtualization, emptyState, loading, error, loadingState, errorState, onRetry, proxyConfig, showCellRefs, selectionSummary, style, className, ...rest }: IrisTableProps<Row>): React.ReactElement;
2478
4362
 
2479
4363
  /**
2480
4364
  * Serialize rows as a CSV string per RFC 4180. Column order determines field
2481
4365
  * order; cell values are read via `dataIndex` (defaulting to the column key).
2482
4366
  * Returns a plain string without BOM.
4367
+ *
4368
+ * Batch AY: masked-by-default export — a column with `mask` exports the
4369
+ * masked value unless it opts out via `exportRaw`. Masking materializes each
4370
+ * masked column's value onto a shadow row at the key the serializer reads
4371
+ * (string `dataIndex`, else `key`), the batch-AO shadow-row convention;
4372
+ * formula columns are already materialized by
4373
+ * `withComputedFormulaCells` before this serializer runs, so the mask applies
4374
+ * on top. No masks → the input array is returned as-is (reference-preserving).
2483
4375
  */
2484
4376
  declare function exportCsv<Row extends Record<string, unknown>>(rows: readonly Row[], columns: readonly IrisTableColumn<Row>[]): string;
4377
+
2485
4378
  /**
2486
4379
  * Trigger a download of the given CSV string. A host `FileSaveHandler` (set via
2487
4380
  * `setFileSaveHandler`) intercepts it for native save in desktop/mobile shells;
@@ -2535,6 +4428,12 @@ interface IrisVirtualScrollProps<T = unknown> {
2535
4428
  }) => void;
2536
4429
  style?: React.CSSProperties;
2537
4430
  className?: string;
4431
+ /** ARIA role for the scroll container (e.g. "listbox"). Forwarded to the root. */
4432
+ role?: string;
4433
+ /** Tab order for the scroll container (roving-tabindex hosts pass -1). */
4434
+ tabIndex?: number;
4435
+ /** Keydown handler on the scroll container (keydowns from focused rows bubble). */
4436
+ onKeyDown?: React.KeyboardEventHandler<HTMLDivElement>;
2538
4437
  }
2539
4438
  /**
2540
4439
  * Virtual scroller. Renders only the visible window of items plus a
@@ -2622,6 +4521,20 @@ interface IrisTreeNode {
2622
4521
  loadChildren?: () => Promise<IrisTreeNode[]>;
2623
4522
  }
2624
4523
  type IrisTreeSelectionMode = 'none' | 'single' | 'multi';
4524
+ /**
4525
+ * Opt-in windowed rendering for {@link IrisTree}. Mirrors
4526
+ * `IrisTableVirtualOptions`. Tree rows are uniform height (padding 4px +
4527
+ * line-height of `--iris-font-size-md`); `itemHeight` must be ≥ the rendered
4528
+ * row height for the active font.
4529
+ */
4530
+ interface IrisTreeVirtualOptions {
4531
+ /** Per-row height in px (uniform). */
4532
+ itemHeight: number;
4533
+ /** Viewport height. Number → px; string → CSS length passed through. */
4534
+ height: number | string;
4535
+ /** Extra rows rendered above and below the viewport (default 4). */
4536
+ buffer?: number;
4537
+ }
2625
4538
 
2626
4539
  interface IrisTreeProps {
2627
4540
  nodes: IrisTreeNode[];
@@ -2655,6 +4568,12 @@ interface IrisTreeProps {
2655
4568
  errorState?: React.ReactNode;
2656
4569
  style?: React.CSSProperties;
2657
4570
  className?: string;
4571
+ /**
4572
+ * Opt-in windowed rendering: only the visible window + buffer of `treeitem`
4573
+ * rows is mounted, via `IrisVirtualScroll` / the core `createVirtualizer`.
4574
+ * Keyboard navigation scrolls the active row into view. Default off.
4575
+ */
4576
+ virtual?: IrisTreeVirtualOptions;
2658
4577
  }
2659
4578
  /**
2660
4579
  * Tree control. Renders a hierarchy of `IrisTreeNode`s with expand/collapse,
@@ -2672,8 +4591,11 @@ interface IrisTreeProps {
2672
4591
  * animated loading / error / empty state in place of the tree. Per-node
2673
4592
  * `loadChildren` lazy loading is independent of this top-level state. Semantic
2674
4593
  * parity with the Vue adapter's `IrisTree`.
4594
+ *
4595
+ * Opt-in `virtual` prop: pass {@link IrisTreeVirtualOptions} to render only the
4596
+ * visible window of treeitems (uniform rows) via `IrisVirtualScroll`.
2675
4597
  */
2676
- declare function IrisTree({ nodes, expanded: expandedProp, defaultExpanded, onExpandedChange, selected: selectedProp, defaultSelected, onSelectedChange, selectionMode, checkable, defaultChecked, onCheckedChange, ariaLabel, loading, error, emptyState, loadingState, errorState, style, className, ...rest }: IrisTreeProps): React.ReactElement;
4598
+ declare function IrisTree({ nodes, expanded: expandedProp, defaultExpanded, onExpandedChange, selected: selectedProp, defaultSelected, onSelectedChange, selectionMode, checkable, defaultChecked, onCheckedChange, ariaLabel, loading, error, emptyState, loadingState, errorState, style, className, virtual, ...rest }: IrisTreeProps): React.ReactElement;
2677
4599
 
2678
4600
  interface IrisListItem<T = unknown> {
2679
4601
  value: T;
@@ -3036,6 +4958,13 @@ interface IrisCommandPaletteProps extends Omit<React.HTMLAttributes<HTMLDivEleme
3036
4958
  /** Custom filter; default is a tolerant subsequence/fuzzy match. */
3037
4959
  filter?: (query: string, item: IrisCommandItem) => number | null;
3038
4960
  onSelect?: (item: IrisCommandItem) => void;
4961
+ /**
4962
+ * Opt-in windowed rendering of the results list via the core virtualizer.
4963
+ * When true, only the visible window (+ buffer) of rows is rendered and
4964
+ * keyboard navigation scrolls the active row into view. Default false —
4965
+ * the plain list renders bit-for-bit as before.
4966
+ */
4967
+ virtual?: boolean;
3039
4968
  }
3040
4969
  /**
3041
4970
  * Command palette: searchable, keyboard-driven action launcher. Built on the
@@ -3043,6 +4972,6 @@ interface IrisCommandPaletteProps extends Omit<React.HTMLAttributes<HTMLDivEleme
3043
4972
  * (consumer wires the listener), type to filter, ↑/↓ to navigate, Enter to
3044
4973
  * execute the focused item, Escape to dismiss.
3045
4974
  */
3046
- declare function IrisCommandPalette({ open, onOpenChange, items, placeholder, emptyText, filter, onSelect, style, ...rest }: IrisCommandPaletteProps): React.ReactElement | null;
4975
+ declare function IrisCommandPalette({ open, onOpenChange, items, placeholder, emptyText, filter, onSelect, virtual, style, ...rest }: IrisCommandPaletteProps): React.ReactElement | null;
3047
4976
 
3048
- 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, 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 IrisTableCellEditEvent, type IrisTableColumn, type IrisTableColumnWidths, type IrisTableEditor, type IrisTableProps, type IrisTableRenderDetail, type IrisTableRowExpandable, type IrisTableSortDirection, type IrisTableSortState, 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, IrisTree, type IrisTreeNode, type IrisTreeProps, IrisTreeSelect, type IrisTreeSelectNode, type IrisTreeSelectProps, type IrisTreeSelectSize, type IrisTreeSelectionMode, 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 };
4977
+ 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 IrisTableAlign, type IrisTableAuditEntry, type IrisTableAutoSaveStateConfig, type IrisTableCellClickParams, type IrisTableCellEditEvent, type IrisTableColumn, type IrisTableColumnWidths, type IrisTableConditionalStyle, type IrisTableContextMenuParams, type IrisTableCustomConfig, type IrisTableEditClosedParams, type IrisTableEditDirtyConfig, type IrisTableEditStartParams, type IrisTableEditor, type IrisTableEmptyState, 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 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 };