@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.
- package/babel.config.js +1 -1
- package/components/auth-dialog-service/auth-dialog-service.js +2 -2
- package/components/checkbox/checkbox.d.ts +1 -1
- package/components/collapse/collapse-content.js +2 -2
- package/components/collapse/collapse-control.js +2 -2
- package/components/collapse/collapse.js +2 -2
- package/components/collapsible-group/collapsible-group.css +138 -0
- package/components/collapsible-group/collapsible-group.d.ts +20 -0
- package/components/collapsible-group/collapsible-group.js +73 -0
- package/components/confirm-service/confirm-service.js +2 -2
- package/components/data-list/data-list.d.ts +1 -1
- package/components/data-list/data-list.mock.d.ts +1 -1
- package/components/data-list/item.d.ts +1 -1
- package/components/data-list/selection.d.ts +1 -1
- package/components/data-list/selection.js +1 -1
- package/components/date-picker/months.js +2 -2
- package/components/date-picker/use-scroll-behavior.js +5 -6
- package/components/date-picker/years.js +2 -2
- package/components/dialog/dialog.d.ts +2 -2
- package/components/dialog/dialog.js +2 -2
- package/components/dropdown-menu/dropdown-menu.d.ts +4 -4
- package/components/dropdown-menu/dropdown-menu.js +4 -4
- package/components/editable-heading/editable-heading.d.ts +1 -2
- package/components/editable-heading/editable-heading.js +18 -19
- package/components/expand/collapsible-group.css +23 -89
- package/components/expand/collapsible-group.d.ts +8 -16
- package/components/expand/collapsible-group.js +13 -72
- package/components/global/compose-refs.d.ts +2 -1
- package/components/global/compose-refs.js +24 -8
- package/components/global/create-stateful-context.js +5 -5
- package/components/global/focus-with-temporary-tabindex.d.ts +11 -0
- package/components/global/focus-with-temporary-tabindex.js +21 -0
- package/components/global/intersection-observer-context.d.ts +31 -11
- package/components/global/intersection-observer-context.js +47 -28
- package/components/global/is-within-interactive-element.d.ts +6 -0
- package/components/global/is-within-interactive-element.js +26 -0
- package/components/global/is-within-navigable-element.d.ts +6 -0
- package/components/global/is-within-navigable-element.js +27 -0
- package/components/global/parse-css-duration.d.ts +5 -0
- package/components/global/parse-css-duration.js +13 -0
- package/components/global/rerender-hoc.d.ts +4 -2
- package/components/global/rerender-hoc.js +4 -4
- package/components/global/schedule-with-cleanup.d.ts +12 -0
- package/components/global/schedule-with-cleanup.js +34 -0
- package/components/{legacy-table/selection.d.ts → global/table-selection.d.ts} +14 -14
- package/components/{legacy-table/selection.js → global/table-selection.js} +2 -2
- package/components/global/theme.d.ts +4 -3
- package/components/global/theme.js +8 -8
- package/components/i18n/i18n-context.js +1 -1
- package/components/input/input.d.ts +1 -1
- package/components/island/adaptive-island-hoc.js +4 -4
- package/components/island/content.d.ts +7 -2
- package/components/island/content.js +5 -5
- package/components/legacy-table/cell.js +1 -1
- package/components/legacy-table/header-cell.js +1 -1
- package/components/legacy-table/header.js +1 -1
- package/components/legacy-table/multitable.d.ts +1 -1
- package/components/legacy-table/row.d.ts +1 -1
- package/components/legacy-table/row.js +1 -1
- package/components/legacy-table/selection-adapter.d.ts +3 -3
- package/components/legacy-table/selection-shortcuts-hoc.d.ts +5 -5
- package/components/legacy-table/simple-table.d.ts +2 -2
- package/components/legacy-table/simple-table.js +3 -3
- package/components/legacy-table/smart-table.d.ts +5 -5
- package/components/legacy-table/smart-table.js +3 -3
- package/components/legacy-table/table.js +1 -1
- package/components/login-dialog/service.js +2 -2
- package/components/popup/popup.d.ts +2 -0
- package/components/popup/popup.js +2 -2
- package/components/popup/popup.target.d.ts +3 -2
- package/components/popup/popup.target.js +4 -6
- package/components/query-assist/query-assist.d.ts +3 -1
- package/components/query-assist/query-assist.js +2 -2
- package/components/radio/radio-item.d.ts +3 -3
- package/components/radio/radio-item.js +3 -4
- package/components/radio/radio.d.ts +2 -2
- package/components/radio/radio.js +1 -1
- package/components/select/select-popup.d.ts +1 -1
- package/components/select/select.d.ts +4 -2
- package/components/slider/slider.js +4 -5
- package/components/tab-trap/tab-trap.d.ts +3 -3
- package/components/tab-trap/tab-trap.js +3 -5
- package/components/table/default-item-renderer.d.ts +35 -11
- package/components/table/default-item-renderer.js +47 -47
- package/components/table/internal/column-animation.d.ts +16 -0
- package/components/table/internal/column-animation.js +45 -0
- package/components/table/internal/table-header.d.ts +4 -0
- package/components/table/internal/table-header.js +357 -0
- package/components/table/internal/virtual-items.d.ts +34 -0
- package/components/table/{table-virtualize.js → internal/virtual-items.js} +78 -44
- package/components/table/item-virtualization.d.ts +35 -0
- package/components/table/item-virtualization.js +28 -0
- package/components/table/table-const.d.ts +40 -6
- package/components/table/table-const.js +14 -5
- package/components/table/table-primitives.d.ts +21 -0
- package/components/table/table-primitives.js +25 -0
- package/components/table/table-props.d.ts +280 -0
- package/components/table/table-props.js +1 -0
- package/components/table/table.css +171 -66
- package/components/table/table.d.ts +205 -224
- package/components/table/table.js +298 -2
- package/components/tags-input/tags-input.d.ts +3 -1
- package/components/tooltip/tooltip.js +2 -2
- package/components/upload/upload.d.ts +4 -3
- package/components/upload/upload.js +3 -7
- package/components/user-agreement/service.js +2 -2
- package/components/util-stories.d.ts +26 -0
- package/components/util-stories.js +61 -0
- package/package.json +41 -41
- package/components/date-picker/use-intersection-observer.d.ts +0 -6
- package/components/date-picker/use-intersection-observer.js +0 -48
- package/components/global/composeRefs.d.ts +0 -6
- package/components/global/composeRefs.js +0 -7
- package/components/global/use-event-callback.d.ts +0 -1
- package/components/global/use-event-callback.js +0 -15
- package/components/table/table-base.d.ts +0 -24
- package/components/table/table-base.js +0 -79
- package/components/table/table-component.d.ts +0 -53
- package/components/table/table-component.js +0 -101
- package/components/table/table-virtualize.d.ts +0 -32
- /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:
|
|
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
|
|
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:
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
15
|
+
export interface TabTrapObject {
|
|
15
16
|
node: HTMLElement | null;
|
|
16
17
|
}
|
|
17
|
-
|
|
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 {
|
|
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
|
-
|
|
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
|
|
1
|
+
import { type ComponentPropsWithRef } from 'react';
|
|
2
2
|
export interface DefaultItemRendererProps {
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* The index of the `data` item to render.
|
|
5
5
|
*/
|
|
6
|
-
|
|
6
|
+
index: number;
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
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
|
-
|
|
13
|
+
keyboardFocusable?: boolean;
|
|
11
14
|
/**
|
|
12
|
-
* Changes the
|
|
13
|
-
* Note that `false`
|
|
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
|
-
*
|
|
18
|
-
|
|
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
|
-
*
|
|
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>({
|
|
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 {
|
|
1
|
+
import { use, useCallback, useRef } from 'react';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
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
|
-
*
|
|
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({
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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(
|
|
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
|
+
}
|