@jetbrains/ring-ui 8.0.0-beta.2 → 8.0.0-beta.4

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 (121) hide show
  1. package/babel.config.js +1 -1
  2. package/components/auth-dialog-service/auth-dialog-service.js +2 -2
  3. package/components/checkbox/checkbox.d.ts +1 -1
  4. package/components/collapse/collapse-content.js +2 -2
  5. package/components/collapse/collapse-control.js +2 -2
  6. package/components/collapse/collapse.js +2 -2
  7. package/components/collapsible-group/collapsible-group.css +138 -0
  8. package/components/collapsible-group/collapsible-group.d.ts +20 -0
  9. package/components/collapsible-group/collapsible-group.js +73 -0
  10. package/components/confirm-service/confirm-service.js +2 -2
  11. package/components/data-list/data-list.d.ts +1 -1
  12. package/components/data-list/data-list.mock.d.ts +1 -1
  13. package/components/data-list/item.d.ts +1 -1
  14. package/components/data-list/selection.d.ts +1 -1
  15. package/components/data-list/selection.js +1 -1
  16. package/components/date-picker/months.js +2 -2
  17. package/components/date-picker/use-scroll-behavior.js +5 -6
  18. package/components/date-picker/years.js +2 -2
  19. package/components/dialog/dialog.d.ts +2 -2
  20. package/components/dialog/dialog.js +2 -2
  21. package/components/dropdown-menu/dropdown-menu.d.ts +4 -4
  22. package/components/dropdown-menu/dropdown-menu.js +4 -4
  23. package/components/editable-heading/editable-heading.d.ts +1 -2
  24. package/components/editable-heading/editable-heading.js +18 -19
  25. package/components/expand/collapsible-group.css +23 -89
  26. package/components/expand/collapsible-group.d.ts +8 -16
  27. package/components/expand/collapsible-group.js +13 -72
  28. package/components/global/compose-refs.d.ts +2 -1
  29. package/components/global/compose-refs.js +24 -8
  30. package/components/global/create-stateful-context.js +5 -5
  31. package/components/global/focus-with-temporary-tabindex.d.ts +11 -0
  32. package/components/global/focus-with-temporary-tabindex.js +21 -0
  33. package/components/global/intersection-observer-context.d.ts +31 -11
  34. package/components/global/intersection-observer-context.js +47 -28
  35. package/components/global/is-within-interactive-element.d.ts +6 -0
  36. package/components/global/is-within-interactive-element.js +26 -0
  37. package/components/global/is-within-navigable-element.d.ts +6 -0
  38. package/components/global/is-within-navigable-element.js +27 -0
  39. package/components/global/parse-css-duration.d.ts +5 -0
  40. package/components/global/parse-css-duration.js +13 -0
  41. package/components/global/rerender-hoc.d.ts +4 -2
  42. package/components/global/rerender-hoc.js +4 -4
  43. package/components/global/schedule-with-cleanup.d.ts +12 -0
  44. package/components/global/schedule-with-cleanup.js +34 -0
  45. package/components/{legacy-table/selection.d.ts → global/table-selection.d.ts} +14 -14
  46. package/components/{legacy-table/selection.js → global/table-selection.js} +2 -2
  47. package/components/global/theme.d.ts +4 -3
  48. package/components/global/theme.js +8 -8
  49. package/components/i18n/i18n-context.js +1 -1
  50. package/components/input/input.d.ts +1 -1
  51. package/components/island/adaptive-island-hoc.js +4 -4
  52. package/components/island/content.d.ts +7 -2
  53. package/components/island/content.js +5 -5
  54. package/components/legacy-table/cell.js +1 -1
  55. package/components/legacy-table/header-cell.js +1 -1
  56. package/components/legacy-table/header.js +1 -1
  57. package/components/legacy-table/multitable.d.ts +1 -1
  58. package/components/legacy-table/row.d.ts +1 -1
  59. package/components/legacy-table/row.js +1 -1
  60. package/components/legacy-table/selection-adapter.d.ts +3 -3
  61. package/components/legacy-table/selection-shortcuts-hoc.d.ts +5 -5
  62. package/components/legacy-table/simple-table.d.ts +2 -2
  63. package/components/legacy-table/simple-table.js +3 -3
  64. package/components/legacy-table/smart-table.d.ts +5 -5
  65. package/components/legacy-table/smart-table.js +3 -3
  66. package/components/legacy-table/table.js +1 -1
  67. package/components/login-dialog/service.js +2 -2
  68. package/components/popup/popup.d.ts +2 -0
  69. package/components/popup/popup.js +2 -2
  70. package/components/popup/popup.target.d.ts +3 -2
  71. package/components/popup/popup.target.js +4 -6
  72. package/components/query-assist/query-assist.d.ts +3 -1
  73. package/components/query-assist/query-assist.js +2 -2
  74. package/components/radio/radio-item.d.ts +3 -3
  75. package/components/radio/radio-item.js +3 -4
  76. package/components/radio/radio.d.ts +2 -2
  77. package/components/radio/radio.js +1 -1
  78. package/components/select/select-popup.d.ts +1 -1
  79. package/components/select/select.d.ts +4 -2
  80. package/components/slider/slider.js +4 -5
  81. package/components/tab-trap/tab-trap.d.ts +3 -3
  82. package/components/tab-trap/tab-trap.js +3 -5
  83. package/components/table/default-item-renderer.d.ts +35 -11
  84. package/components/table/default-item-renderer.js +47 -47
  85. package/components/table/internal/column-animation.d.ts +16 -0
  86. package/components/table/internal/column-animation.js +45 -0
  87. package/components/table/internal/table-header.d.ts +4 -0
  88. package/components/table/internal/table-header.js +357 -0
  89. package/components/table/internal/virtual-items.d.ts +34 -0
  90. package/components/table/{table-virtualize.js → internal/virtual-items.js} +78 -44
  91. package/components/table/item-virtualization.d.ts +35 -0
  92. package/components/table/item-virtualization.js +28 -0
  93. package/components/table/table-const.d.ts +40 -6
  94. package/components/table/table-const.js +14 -5
  95. package/components/table/table-primitives.d.ts +21 -0
  96. package/components/table/table-primitives.js +25 -0
  97. package/components/table/table-props.d.ts +280 -0
  98. package/components/table/table-props.js +1 -0
  99. package/components/table/table.css +171 -66
  100. package/components/table/table.d.ts +205 -224
  101. package/components/table/table.js +298 -2
  102. package/components/tags-input/tags-input.d.ts +3 -1
  103. package/components/tooltip/tooltip.js +2 -2
  104. package/components/upload/upload.d.ts +4 -3
  105. package/components/upload/upload.js +3 -7
  106. package/components/user-agreement/service.js +2 -2
  107. package/components/util-stories.d.ts +26 -0
  108. package/components/util-stories.js +61 -0
  109. package/package.json +41 -41
  110. package/components/date-picker/use-intersection-observer.d.ts +0 -6
  111. package/components/date-picker/use-intersection-observer.js +0 -48
  112. package/components/global/composeRefs.d.ts +0 -6
  113. package/components/global/composeRefs.js +0 -7
  114. package/components/global/use-event-callback.d.ts +0 -1
  115. package/components/global/use-event-callback.js +0 -15
  116. package/components/table/table-base.d.ts +0 -24
  117. package/components/table/table-base.js +0 -79
  118. package/components/table/table-component.d.ts +0 -53
  119. package/components/table/table-component.js +0 -101
  120. package/components/table/table-virtualize.d.ts +0 -32
  121. /package/components/legacy-table/{table.css → legacy-table.css} +0 -0
@@ -1,10 +1,10 @@
1
1
  import { Component } from 'react';
2
- import { type RadioProps } from './radio-item';
2
+ import RadioItem, { type RadioProps } from './radio-item';
3
3
  /**
4
4
  * @name Radio
5
5
  */
6
6
  export default class Radio extends Component<RadioProps> {
7
- static Item: import("react").ForwardRefExoticComponent<import("./radio-item").RadioItemProps & import("react").RefAttributes<import("./radio-item").RadioItemInner>>;
7
+ static Item: typeof RadioItem;
8
8
  uid: string;
9
9
  render(): import("react").JSX.Element;
10
10
  }
@@ -8,6 +8,6 @@ export default class Radio extends Component {
8
8
  static Item = RadioItem;
9
9
  uid = getUID('ring-radio-');
10
10
  render() {
11
- return <RadioContext.Provider value={{ name: this.uid, ...this.props }}>{this.props.children}</RadioContext.Provider>;
11
+ return <RadioContext value={{ name: this.uid, ...this.props }}>{this.props.children}</RadioContext>;
12
12
  }
13
13
  }
@@ -127,7 +127,7 @@ export default class SelectPopup<T = unknown> extends PureComponent<SelectPopupP
127
127
  list?: List<T> | null;
128
128
  listRef: (el: List<T> | null) => void;
129
129
  filterRef: (el: HTMLInputElement | null) => void;
130
- composedFilterRef: import("memoize-one").MemoizedFn<(...refs: (Ref<HTMLInputElement> | undefined)[]) => (value: T_1 | null) => void>;
130
+ composedFilterRef: import("memoize-one").MemoizedFn<(...refs: (Ref<HTMLInputElement> | undefined)[]) => (value: T_1 | null) => () => void>;
131
131
  shortcutsScope: string;
132
132
  shortcutsMap: {
133
133
  tab: (event: Event) => void;
@@ -264,7 +264,7 @@ export default class Select<T = unknown> extends Component<SelectProps<T>, Selec
264
264
  private _getAvatar;
265
265
  filter?: HTMLInputElement | null;
266
266
  filterRef: (el: HTMLInputElement | null) => void;
267
- composedFilterRef: import("memoize-one").MemoizedFn<(...refs: (Ref<HTMLInputElement> | undefined)[]) => (value: T_1 | null) => void>;
267
+ composedFilterRef: import("memoize-one").MemoizedFn<(...refs: (Ref<HTMLInputElement> | undefined)[]) => (value: T_1 | null) => () => void>;
268
268
  getShortcutsMap(): {
269
269
  enter: () => true | undefined;
270
270
  esc: (event: KeyboardEvent) => boolean | undefined;
@@ -282,5 +282,7 @@ export default class Select<T = unknown> extends Component<SelectProps<T>, Selec
282
282
  export type SingleSelectAttrs<T = unknown> = React.JSX.LibraryManagedAttributes<typeof Select, SingleSelectProps<T>>;
283
283
  export type MultipleSelectAttrs<T = unknown> = React.JSX.LibraryManagedAttributes<typeof Select, MultipleSelectProps<T>>;
284
284
  export type SelectAttrs<T = unknown> = React.JSX.LibraryManagedAttributes<typeof Select, SelectProps<T>>;
285
- export declare const RerenderableSelect: React.ForwardRefExoticComponent<Omit<any, "ref"> & React.RefAttributes<any>>;
285
+ export declare const RerenderableSelect: ({ ref, ...props }: Omit<any, "ref"> & {
286
+ ref?: Ref<any> | undefined;
287
+ }) => React.JSX.Element;
286
288
  export {};
@@ -1,11 +1,10 @@
1
- import { Fragment, useEffect, useRef, useState } from 'react';
1
+ import { Fragment, useEffect, useEffectEvent, useRef, useState } from 'react';
2
2
  import * as React from 'react';
3
3
  import classNames from 'classnames';
4
4
  import { isArray } from '../global/typescript-utils';
5
5
  import Shortcuts from '../shortcuts/shortcuts';
6
6
  import getUID from '../global/get-uid';
7
7
  import { adjustValues, calculateMarks, calculateValue, HUNDRED, toPercent, toRange, validateValue } from './slider.utils';
8
- import useEventCallback from '../global/use-event-callback';
9
8
  import styles from './slider.css';
10
9
  export const Slider = ({ defaultValue, value, min = 0, max = HUNDRED, step = 1, disabled, marks, showTicks, showTag, className, renderTag, onChange, }) => {
11
10
  const ref = useRef(null);
@@ -86,7 +85,7 @@ export const Slider = ({ defaultValue, value, min = 0, max = HUNDRED, step = 1,
86
85
  setIsDragging(true);
87
86
  previouslyDragged.current = false;
88
87
  };
89
- const handleMouseUp = useEventCallback(({ pageX }) => {
88
+ const handleMouseUp = useEffectEvent(({ pageX }) => {
90
89
  const nextValues = adjustValues(validValues, ref, draggedIndex, pageX, max, min, validStep);
91
90
  if (nextValues[0] > nextValues[1]) {
92
91
  nextValues.reverse();
@@ -96,7 +95,7 @@ export const Slider = ({ defaultValue, value, min = 0, max = HUNDRED, step = 1,
96
95
  setIsDragging(false);
97
96
  previouslyDragged.current = true;
98
97
  });
99
- const handleMouseMove = useEventCallback(({ pageX }) => {
98
+ const handleMouseMove = useEffectEvent(({ pageX }) => {
100
99
  const nextValues = adjustValues(validValues, ref, draggedIndex, pageX, max, min, validStep);
101
100
  if (nextValues[0] > nextValues[1]) {
102
101
  nextValues.reverse();
@@ -120,7 +119,7 @@ export const Slider = ({ defaultValue, value, min = 0, max = HUNDRED, step = 1,
120
119
  window.removeEventListener('mousemove', handleMouseMove);
121
120
  window.removeEventListener('mouseup', handleMouseUp);
122
121
  };
123
- }, [isDragging, disabled, handleMouseMove, handleMouseUp]);
122
+ }, [isDragging, disabled]);
124
123
  return (<div ref={ref} role='presentation' // contains interactive elements
125
124
  className={classNames(styles.slider, className, {
126
125
  [styles.disabled]: disabled,
@@ -2,6 +2,7 @@ import { type HTMLAttributes, type ReactNode } from 'react';
2
2
  import * as React from 'react';
3
3
  export declare const FOCUSABLE_ELEMENTS = "input, button, select, textarea, a[href], *[tabindex]:not([data-trap-button]):not([data-scrollable-container])";
4
4
  export interface TabTrapProps extends HTMLAttributes<HTMLElement> {
5
+ ref?: React.Ref<TabTrapObject>;
5
6
  children: ReactNode;
6
7
  trapDisabled?: boolean;
7
8
  autoFocusFirst?: boolean;
@@ -11,8 +12,7 @@ export interface TabTrapProps extends HTMLAttributes<HTMLElement> {
11
12
  /**
12
13
  * @name TabTrap
13
14
  */
14
- interface TabTrap {
15
+ export interface TabTrapObject {
15
16
  node: HTMLElement | null;
16
17
  }
17
- declare const TabTrap: React.ForwardRefExoticComponent<TabTrapProps & React.RefAttributes<TabTrap>>;
18
- export default TabTrap;
18
+ export default function TabTrap({ ref, children, trapDisabled, autoFocusFirst, focusBackOnClose, focusBackOnExit, ...restProps }: TabTrapProps): React.JSX.Element;
@@ -1,10 +1,9 @@
1
- import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, } from 'react';
1
+ import { useCallback, useEffect, useImperativeHandle, useRef } from 'react';
2
2
  import * as React from 'react';
3
3
  import { isNodeInVisiblePartOfPage } from '../global/dom';
4
4
  import styles from './tab-trap.css';
5
5
  export const FOCUSABLE_ELEMENTS = 'input, button, select, textarea, a[href], *[tabindex]:not([data-trap-button]):not([data-scrollable-container])';
6
- // eslint-disable-next-line no-shadow
7
- const TabTrap = forwardRef(function TabTrap({ children, trapDisabled = false, autoFocusFirst = true, focusBackOnClose = true, focusBackOnExit = false, ...restProps }, ref) {
6
+ export default function TabTrap({ ref, children, trapDisabled = false, autoFocusFirst = true, focusBackOnClose = true, focusBackOnExit = false, ...restProps }) {
8
7
  const nodeRef = useRef(null);
9
8
  const trapButtonNodeRef = useRef(null);
10
9
  const previousFocusedNodeRef = useRef(null);
@@ -121,5 +120,4 @@ const TabTrap = forwardRef(function TabTrap({ children, trapDisabled = false, au
121
120
  // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
122
121
  tabIndex={0} onFocus={restoreFocusOrFocusFirst} data-trap-button/>
123
122
  </div>);
124
- });
125
- export default TabTrap;
123
+ }
@@ -1,25 +1,49 @@
1
- import { type ComponentPropsWithoutRef } from 'react';
1
+ import { type ComponentPropsWithRef } from 'react';
2
2
  export interface DefaultItemRendererProps {
3
3
  /**
4
- * Installed on the `<tr>` element
4
+ * The index of the `data` item to render.
5
5
  */
6
- ref?: React.RefObject<HTMLTableRowElement | null>;
6
+ index: number;
7
7
  /**
8
- * The index of the `data` item to render
8
+ * If `true`, the row will be focusable with up/down arrow keys.
9
+ * Focus is implemented using the
10
+ * ["roving tabindex"](https://developer.mozilla.org/en-US/docs/Web/Accessibility/Guides/Keyboard-navigable_JavaScript_widgets#technique_1_roving_tabindex)
11
+ * technique, that is, only the focused row has `tabIndex={0}`.
9
12
  */
10
- index: number;
13
+ keyboardFocusable?: boolean;
11
14
  /**
12
- * Changes the highlight on hover and applies the pointer cursor.
13
- * Note that `false` doesn't mean it cannot handle `onClick`.
15
+ * Changes the background on hover and applies the pointer cursor.
16
+ * Note that `false` does not mean the row cannot handle `onClick`.
14
17
  */
15
18
  clickable?: boolean;
16
19
  /**
17
- * A level of a nested item. Results in an indent for columns with `indent: true`.
18
- * 0, negative and not set mean no indent.
20
+ * If `true`, the row is highlighted as selected with a different background color.
21
+ */
22
+ selected?: boolean;
23
+ /**
24
+ * The nesting level of an item. Applies an indent for columns with
25
+ * `Column.indent` set to `true`. `0`, negative values, and an unset value
26
+ * mean no indent.
19
27
  */
20
28
  level?: number;
29
+ /**
30
+ * When set to `true`, does not control item virtualization.
31
+ * Useful when you include `DefaultItemRenderer` as a part of a custom row renderer,
32
+ * and track the visibility yourself.
33
+ */
34
+ noItemVirtualization?: boolean;
21
35
  }
22
36
  /**
23
- * @see TableProps.renderItem
37
+ * Standard component for rendering a table row.
38
+ *
39
+ * Renders an item using the table's column definitions and lets you
40
+ * configure item-scoped behavior such as selection, keyboard navigation,
41
+ * event handlers, `className`, and `ref`.
42
+ *
43
+ * Note that row-level click and keyboard handlers are not discoverable
44
+ * by assistive technologies. Make sure that any functionality relying on
45
+ * them (such as selection or expand/collapse) is also available through
46
+ * accessible controls, such as checkboxes or buttons with accessible
47
+ * labels.
24
48
  */
25
- export declare function DefaultItemRenderer<T>({ ref: userRef, index, clickable, level, className, onKeyDown, onBlur, ...restProps }: DefaultItemRendererProps & ComponentPropsWithoutRef<'tr'>): import("react").JSX.Element;
49
+ export declare function DefaultItemRenderer<T>({ index, keyboardFocusable, clickable, selected, level, noItemVirtualization, ref: userRef, className, ...restProps }: DefaultItemRendererProps & ComponentPropsWithRef<'tr'>): import("react").JSX.Element | null;
@@ -1,61 +1,61 @@
1
- import { useContext, useEffect, useRef } from 'react';
1
+ import { use, useCallback, useRef } from 'react';
2
2
  import classNames from 'classnames';
3
- import { CollapseItemIntoSpacerContext, TablePropsContext } from './table-const';
4
- import { useIsIntersectingListener } from '../global/intersection-observer-context';
5
- import { TableCell, TableRow } from './table-base';
3
+ import { ColumnAnimationContext, TablePropsContext } from './table-const';
4
+ import { useComposedRef } from '../global/compose-refs';
5
+ import { useItemVirtualization } from './item-virtualization';
6
+ import { TableCell, TableRow } from './table-primitives';
6
7
  import styles from './table.css';
7
- const INDENT_SIZE = 24;
8
8
  /**
9
- * @see TableProps.renderItem
9
+ * Standard component for rendering a table row.
10
+ *
11
+ * Renders an item using the table's column definitions and lets you
12
+ * configure item-scoped behavior such as selection, keyboard navigation,
13
+ * event handlers, `className`, and `ref`.
14
+ *
15
+ * Note that row-level click and keyboard handlers are not discoverable
16
+ * by assistive technologies. Make sure that any functionality relying on
17
+ * them (such as selection or expand/collapse) is also available through
18
+ * accessible controls, such as checkboxes or buttons with accessible
19
+ * labels.
10
20
  */
11
- export function DefaultItemRenderer({ ref: userRef, index, clickable, level, className, onKeyDown, onBlur, ...restProps }) {
12
- const selfRef = useRef(null);
13
- const ref = userRef ?? selfRef;
14
- const collapseItemIntoSpacer = useContext(CollapseItemIntoSpacerContext);
15
- useIsIntersectingListener(ref, isIntersecting => {
16
- if (ref.current && !isIntersecting) {
17
- collapseItemIntoSpacer(ref.current.getBoundingClientRect().height);
18
- }
21
+ export function DefaultItemRenderer({ index, keyboardFocusable, clickable, selected, level, noItemVirtualization, ref: userRef, className, ...restProps }) {
22
+ const localRef = useRef(null);
23
+ const composedRef = useComposedRef(userRef, localRef);
24
+ useItemVirtualization({
25
+ index,
26
+ refs: localRef,
27
+ onIntersectionChange: useCallback(([isIntersecting], _i, [element]) => isIntersecting === false &&
28
+ !noItemVirtualization &&
29
+ element?.isConnected &&
30
+ !element.contains(document.activeElement) &&
31
+ !element.previousElementSibling?.contains(document.activeElement) &&
32
+ !element.nextElementSibling?.contains(document.activeElement)
33
+ ? element.getBoundingClientRect().height
34
+ : undefined, [noItemVirtualization]),
19
35
  });
20
- const { data, columns, selection, isItemKeyboardFocusable, onItemFocus } = useContext(TablePropsContext);
21
- const item = data[index];
22
- const selected = selection?.isSelected(item);
23
- function handleKeyDown(e) {
24
- onKeyDown?.(e);
25
- if (!e.defaultPrevented && (e.key === 'ArrowUp' || e.key === 'ArrowDown')) {
26
- const step = e.key === 'ArrowUp' ? -1 : 1;
27
- // eslint-disable-next-line yoda
28
- for (let i = index + step; 0 <= i && i < data.length; i += step) {
29
- if (isItemKeyboardFocusable?.(data[i], i, data)) {
30
- onItemFocus?.(data[i], i, data);
31
- break;
32
- }
33
- }
34
- }
35
- }
36
- const focused = selection?.isFocused(item);
37
- useEffect(() => {
38
- if (focused)
39
- ref.current?.focus();
40
- }, [focused, ref]);
41
- function handleBlur(e) {
42
- onBlur?.(e);
43
- if (!e.defaultPrevented && focused) {
44
- onItemFocus?.(null, -1, data);
45
- }
36
+ const tableProps = use(TablePropsContext);
37
+ if (!tableProps) {
38
+ return null;
46
39
  }
47
- return (<TableRow ref={ref} className={classNames(className, clickable && styles.clickableRow, selected && styles.selectedRow)} onKeyDown={handleKeyDown} tabIndex={focused ? 0 : undefined} onBlur={focused ? handleBlur : undefined} {...restProps}>
48
- {columns.map((column, columnIndex) => (<TableCell key={column.key} className={column.tdClassName?.(item, index, data)} style={column.indent && level != null && level > 0 ? { paddingInlineStart: `${level * INDENT_SIZE}px` } : undefined}>
49
- {column.renderCell?.(item, index, data) ?? getDefaultCellValue(item, columnIndex)}
50
- </TableCell>))}
40
+ const animatedColumn = use(ColumnAnimationContext);
41
+ const { data, columns } = tableProps;
42
+ const item = data[index];
43
+ const indentSize = 24;
44
+ return (<TableRow ref={composedRef} keyboardFocusable={keyboardFocusable} className={classNames(className, clickable && styles.clickableRow, selected && styles.selectedRow)} {...restProps}>
45
+ {columns.map((column, columnIndex) => {
46
+ const { key, tdClassName, indent } = column;
47
+ return (<TableCell key={key} className={classNames(columnIndex === animatedColumn?.columnIndex && animatedColumn.cellClassName, typeof tdClassName === 'function' ? tdClassName(item, index, data) : tdClassName)} style={indent && level != null && level > 0 ? { paddingInlineStart: `${level * indentSize}px` } : undefined}>
48
+ {column.renderCell?.(item, index, data) ?? getDefaultCellValue(item, columnIndex, key)}
49
+ </TableCell>);
50
+ })}
51
51
  </TableRow>);
52
52
  }
53
- function getDefaultCellValue(item, columnIndex) {
53
+ function getDefaultCellValue(item, columnIndex, columnKey) {
54
54
  if (Array.isArray(item)) {
55
- return String(item[columnIndex] ?? '');
55
+ return String(item[columnIndex]);
56
56
  }
57
57
  if (item !== null && typeof item === 'object') {
58
- return String(Object.values(item)[columnIndex] ?? '');
58
+ return String(item[String(columnKey)]);
59
59
  }
60
60
  if (columnIndex === 0) {
61
61
  return String(item);
@@ -0,0 +1,16 @@
1
+ import { type RefObject } from 'react';
2
+ import type { Column } from '../table-props';
3
+ import type { ColumnAnimation } from '../table-const';
4
+ export interface ReorderSpec {
5
+ fromIndex: number;
6
+ insertionIndex: number;
7
+ }
8
+ export type ExpectColumnReorder = (reorderSpec: ReorderSpec) => void;
9
+ export declare function useColumnAnimation<T>({ disabled, tableRef, columns, }: {
10
+ disabled: boolean | undefined;
11
+ tableRef: RefObject<HTMLTableElement | null>;
12
+ columns: readonly Column<T>[];
13
+ }): {
14
+ columnAnimation: ColumnAnimation | null;
15
+ expectColumnReorder: ExpectColumnReorder;
16
+ };
@@ -0,0 +1,45 @@
1
+ import { useCallback, useEffect, useRef, useState } from 'react';
2
+ import { parseCssDuration } from '../../global/parse-css-duration';
3
+ import { requestAnimationFrameWithCleanup, setTimeoutWithCleanup } from '../../global/schedule-with-cleanup';
4
+ import styles from '../table.css';
5
+ const reorderExpectationTimeout = 1000;
6
+ export function useColumnAnimation({ disabled, tableRef, columns, }) {
7
+ const [columnAnimation, setColumnAnimation] = useState(null);
8
+ const pendingColumnReorder = useRef(null);
9
+ const expectColumnReorder = useCallback((reorderSpec) => {
10
+ if (disabled)
11
+ return;
12
+ const timerId = window.setTimeout(() => {
13
+ pendingColumnReorder.current = null;
14
+ }, reorderExpectationTimeout);
15
+ pendingColumnReorder.current = { ...reorderSpec, timerId, columns };
16
+ }, [disabled, columns]);
17
+ useEffect(() => {
18
+ return () => {
19
+ if (pendingColumnReorder.current) {
20
+ window.clearTimeout(pendingColumnReorder.current.timerId);
21
+ pendingColumnReorder.current = null;
22
+ }
23
+ };
24
+ }, []);
25
+ useEffect(() => {
26
+ const table = tableRef.current;
27
+ if (!table || !pendingColumnReorder.current || columns === pendingColumnReorder.current.columns)
28
+ return;
29
+ const { fromIndex, insertionIndex } = pendingColumnReorder.current;
30
+ pendingColumnReorder.current = null;
31
+ const columnIndex = fromIndex < insertionIndex ? insertionIndex - 1 : insertionIndex;
32
+ return requestAnimationFrameWithCleanup(() => setColumnAnimation(prev => prev == null ? { columnIndex, phase: 'initial', cellClassName: styles.animatedColumnInitial } : prev));
33
+ }, [columns, tableRef]);
34
+ useEffect(() => {
35
+ if (columnAnimation?.phase === 'initial') {
36
+ return requestAnimationFrameWithCleanup(() => setColumnAnimation(prev => prev === columnAnimation ? { ...prev, phase: 'fade-out', cellClassName: styles.animatedColumnFadeOut } : prev));
37
+ }
38
+ if (columnAnimation?.phase === 'fade-out') {
39
+ const fadeOutMs = parseCssDuration(window.getComputedStyle(tableRef.current).getPropertyValue('--animated-column-fade-out-duration'));
40
+ return setTimeoutWithCleanup(() => setColumnAnimation(prev => (prev === columnAnimation ? null : prev)), fadeOutMs);
41
+ }
42
+ return undefined;
43
+ }, [columnAnimation, tableRef]);
44
+ return { columnAnimation, expectColumnReorder };
45
+ }
@@ -0,0 +1,4 @@
1
+ import { type ExpectColumnReorder } from './column-animation';
2
+ export declare function TableHeader<T>({ expectColumnReorder }: {
3
+ expectColumnReorder: ExpectColumnReorder;
4
+ }): import("react").JSX.Element | null;