@jetbrains/ring-ui 7.0.115 → 8.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/data-list/data-list.d.ts +4 -4
- package/components/data-list/data-list.js +2 -2
- 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/month.d.ts +0 -2
- package/components/date-picker/month.js +5 -5
- package/components/date-picker/months.js +8 -7
- package/components/date-picker/years.js +11 -10
- package/components/global/intersection-observer-context.d.ts +26 -0
- package/components/global/intersection-observer-context.js +72 -0
- package/components/{table → legacy-table}/selection.d.ts +2 -2
- package/components/{table → legacy-table}/selection.js +1 -1
- package/components/legacy-table/table.css +260 -0
- package/components/legacy-table/table.d.ts +109 -0
- package/components/legacy-table/table.js +191 -0
- package/components/table/default-item-renderer.d.ts +25 -0
- package/components/table/default-item-renderer.js +64 -0
- package/components/table/table-base.d.ts +24 -0
- package/components/table/table-base.js +79 -0
- package/components/table/table-component.d.ts +53 -0
- package/components/table/table-component.js +101 -0
- package/components/table/table-const.d.ts +8 -0
- package/components/table/table-const.js +8 -0
- package/components/table/table-virtualize.d.ts +32 -0
- package/components/table/table-virtualize.js +150 -0
- package/components/table/table.css +76 -199
- package/components/table/table.d.ts +221 -104
- package/components/table/table.js +2 -191
- package/package.json +1 -1
- /package/components/{table → legacy-table}/cell.d.ts +0 -0
- /package/components/{table → legacy-table}/cell.js +0 -0
- /package/components/{table → legacy-table}/disable-hover-hoc.d.ts +0 -0
- /package/components/{table → legacy-table}/disable-hover-hoc.js +0 -0
- /package/components/{table → legacy-table}/header-cell.d.ts +0 -0
- /package/components/{table → legacy-table}/header-cell.js +0 -0
- /package/components/{table → legacy-table}/header.d.ts +0 -0
- /package/components/{table → legacy-table}/header.js +0 -0
- /package/components/{table → legacy-table}/multitable.d.ts +0 -0
- /package/components/{table → legacy-table}/multitable.js +0 -0
- /package/components/{table → legacy-table}/row-with-focus-sensor.d.ts +0 -0
- /package/components/{table → legacy-table}/row-with-focus-sensor.js +0 -0
- /package/components/{table → legacy-table}/row.d.ts +0 -0
- /package/components/{table → legacy-table}/row.js +0 -0
- /package/components/{table → legacy-table}/selection-adapter.d.ts +0 -0
- /package/components/{table → legacy-table}/selection-adapter.js +0 -0
- /package/components/{table → legacy-table}/selection-shortcuts-hoc.d.ts +0 -0
- /package/components/{table → legacy-table}/selection-shortcuts-hoc.js +0 -0
- /package/components/{table → legacy-table}/simple-table.d.ts +0 -0
- /package/components/{table → legacy-table}/simple-table.js +0 -0
- /package/components/{table → legacy-table}/smart-table.d.ts +0 -0
- /package/components/{table → legacy-table}/smart-table.js +0 -0
- /package/components/{table → legacy-table}/table.examples2.json +0 -0
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { Component } from 'react';
|
|
5
5
|
import { type FocusSensorOuterProps } from '../global/focus-sensor-hoc';
|
|
6
|
-
import { type SelectionShortcutsAddProps, type SelectionShortcutsOuterProps } from '../table/selection-shortcuts-hoc';
|
|
7
|
-
import { type DisableHoverAddProps } from '../table/disable-hover-hoc';
|
|
8
|
-
import { type SelectionItem } from '../table/selection';
|
|
6
|
+
import { type SelectionShortcutsAddProps, type SelectionShortcutsOuterProps } from '../legacy-table/selection-shortcuts-hoc';
|
|
7
|
+
import { type DisableHoverAddProps } from '../legacy-table/disable-hover-hoc';
|
|
8
|
+
import { type SelectionItem } from '../legacy-table/selection';
|
|
9
9
|
import { type FormattedItem, moreLessButtonStates } from './item';
|
|
10
10
|
export interface DataListBaseProps<T extends SelectionItem> {
|
|
11
11
|
data: readonly T[];
|
|
@@ -20,7 +20,7 @@ export interface DataListBaseProps<T extends SelectionItem> {
|
|
|
20
20
|
type FocusableProps<T extends SelectionItem> = DataListBaseProps<T> & DisableHoverAddProps & FocusSensorOuterProps<HTMLDivElement> & SelectionShortcutsAddProps<T>;
|
|
21
21
|
export type DataListContainerProps<T extends SelectionItem> = DataListBaseProps<T> & FocusSensorOuterProps<HTMLDivElement> & SelectionShortcutsOuterProps<T>;
|
|
22
22
|
export default class DataListContainer<T extends SelectionItem> extends Component<DataListContainerProps<T>> {
|
|
23
|
-
DataList: import("react").ComponentClass<import("../table/disable-hover-hoc").DisableHoverProps<import("../table/selection-shortcuts-hoc").SelectionShortcutsProps<T, FocusableProps<T>>>, any>;
|
|
23
|
+
DataList: import("react").ComponentClass<import("../legacy-table/disable-hover-hoc").DisableHoverProps<import("../legacy-table/selection-shortcuts-hoc").SelectionShortcutsProps<T, FocusableProps<T>>>, any>;
|
|
24
24
|
render(): import("react").JSX.Element;
|
|
25
25
|
}
|
|
26
26
|
export {};
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
import { PureComponent, Component } from 'react';
|
|
5
5
|
import classNames from 'classnames';
|
|
6
6
|
import focusSensorHOC from '../global/focus-sensor-hoc';
|
|
7
|
-
import selectionShortcutsHOC from '../table/selection-shortcuts-hoc';
|
|
8
|
-
import disableHoverHOC from '../table/disable-hover-hoc';
|
|
7
|
+
import selectionShortcutsHOC from '../legacy-table/selection-shortcuts-hoc';
|
|
8
|
+
import disableHoverHOC from '../legacy-table/disable-hover-hoc';
|
|
9
9
|
import getUID from '../global/get-uid';
|
|
10
10
|
import Shortcuts from '../shortcuts/shortcuts';
|
|
11
11
|
import Loader from '../loader/loader';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PureComponent, type ReactNode } from 'react';
|
|
2
|
-
import { type SelectionItem } from '../table/selection';
|
|
2
|
+
import { type SelectionItem } from '../legacy-table/selection';
|
|
3
3
|
import type Selection from './selection';
|
|
4
4
|
export declare enum moreLessButtonStates {
|
|
5
5
|
UNUSED = 0,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import TableSelection, { type CloneWithConfig, type SelectionItem, type TableSelectionConfig } from '../table/selection';
|
|
1
|
+
import TableSelection, { type CloneWithConfig, type SelectionItem, type TableSelectionConfig } from '../legacy-table/selection';
|
|
2
2
|
interface DataListSelectionConfig<T extends SelectionItem> extends TableSelectionConfig<T> {
|
|
3
3
|
partialSelected?: Set<T> | undefined;
|
|
4
4
|
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { type Locale } from 'date-fns';
|
|
2
2
|
import { type MonthsProps } from './consts';
|
|
3
|
-
import { type IntersectionObserverHandle } from './use-intersection-observer';
|
|
4
3
|
export interface MonthProps extends MonthsProps {
|
|
5
4
|
month: Date;
|
|
6
|
-
intersectionObserverHandle: IntersectionObserverHandle | null;
|
|
7
5
|
}
|
|
8
6
|
export default function Month(props: MonthProps): import("react").JSX.Element;
|
|
9
7
|
export declare function getMonthHeight(monthStart: Date | number, locale: Locale | undefined): number;
|
|
@@ -4,14 +4,14 @@ import { getDaysInMonth, setDate } from 'date-fns';
|
|
|
4
4
|
import { useRef } from 'react';
|
|
5
5
|
import Day from './day';
|
|
6
6
|
import units, { WEEK, getWeekStartsOn } from './consts';
|
|
7
|
-
import {
|
|
7
|
+
import { useIsIntersecting } from '../global/intersection-observer-context';
|
|
8
8
|
import styles from './date-picker.css';
|
|
9
9
|
export default function Month(props) {
|
|
10
|
-
const { month, locale
|
|
10
|
+
const { month, locale } = props;
|
|
11
11
|
const containerRef = useRef(null);
|
|
12
|
-
const
|
|
13
|
-
return (<div className={styles.month} ref={containerRef} style={
|
|
14
|
-
{
|
|
12
|
+
const isIntersecting = useIsIntersecting(containerRef);
|
|
13
|
+
return (<div className={styles.month} ref={containerRef} style={isIntersecting ? {} : { height: getMonthHeight(month, locale) }}>
|
|
14
|
+
{isIntersecting && (<>
|
|
15
15
|
<span className={styles.monthTitle}>{format(month, 'LLLL', { locale })}</span>
|
|
16
16
|
|
|
17
17
|
{Array.from({ length: getPaddingCellsNum(month, locale) }, (_, i) => (<Day {...props} day={new Date(0)} empty key={`e_${i}`}/>))}
|
|
@@ -5,7 +5,7 @@ import units from './consts';
|
|
|
5
5
|
import { ScrollArith } from './scroll-arith';
|
|
6
6
|
import { useScrollBehavior } from './use-scroll-behavior';
|
|
7
7
|
import scheduleRAF from '../global/schedule-raf';
|
|
8
|
-
import {
|
|
8
|
+
import { useIntersectionObserverHandle, IntersectionObserverContext } from '../global/intersection-observer-context';
|
|
9
9
|
import styles from './date-picker.css';
|
|
10
10
|
function getMonthHeightWithMargin(date, locale) {
|
|
11
11
|
return units.unit * 2 + getMonthHeight(date, locale);
|
|
@@ -23,14 +23,15 @@ const scheduleScroll = scheduleRAF();
|
|
|
23
23
|
*
|
|
24
24
|
* To avoid an unpainted gap at the viewport boundary, the next month must be reported
|
|
25
25
|
* as visible slightly before it actually enters the viewport. We achieve this by
|
|
26
|
-
* extending the IntersectionObserver
|
|
26
|
+
* extending the IntersectionObserver rootMargin.
|
|
27
27
|
*/
|
|
28
|
-
const
|
|
28
|
+
const intersectionObserverRootMargin = units.cellSize * 2;
|
|
29
29
|
export default function Months(props) {
|
|
30
30
|
const { scrollDate, setScrollDate, locale } = props;
|
|
31
31
|
const { containerRef, items } = useScrollBehavior(scrollDate, setScrollDate, locale, 'monthsScroll', scrollArith, scheduleScroll);
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
return (<IntersectionObserverContext.Provider value={useIntersectionObserverHandle(containerRef, intersectionObserverRootMargin)}>
|
|
33
|
+
<div className={styles.months} ref={containerRef} data-test='ring-date-popup--months'>
|
|
34
|
+
{items.map(month => (<Month {...props} month={month} key={+month}/>))}
|
|
35
|
+
</div>
|
|
36
|
+
</IntersectionObserverContext.Provider>);
|
|
36
37
|
}
|
|
@@ -12,7 +12,7 @@ import { ScrollArith } from './scroll-arith';
|
|
|
12
12
|
import { useScrollBehavior } from './use-scroll-behavior';
|
|
13
13
|
import { animateDate } from './animate-date';
|
|
14
14
|
import scheduleRAF from '../global/schedule-raf';
|
|
15
|
-
import {
|
|
15
|
+
import { IntersectionObserverContext, useIntersectionObserverHandle, useIsIntersecting, } from '../global/intersection-observer-context';
|
|
16
16
|
import styles from './date-picker.css';
|
|
17
17
|
const { yearHeight } = units;
|
|
18
18
|
const scrollArith = new ScrollArith({
|
|
@@ -25,7 +25,7 @@ const scheduleScroll = scheduleRAF();
|
|
|
25
25
|
/**
|
|
26
26
|
* Reduces "empty" years during fast scrolling.
|
|
27
27
|
*/
|
|
28
|
-
const
|
|
28
|
+
const intersectionObserverRootMargin = units.calHeight / 2;
|
|
29
29
|
export default function Years({ scrollDate, setScrollDate }) {
|
|
30
30
|
const [localScrollDate, setLocalScrollDate] = useState(scrollDate);
|
|
31
31
|
const syncCleanupRef = useRef(null);
|
|
@@ -87,15 +87,16 @@ export default function Years({ scrollDate, setScrollDate }) {
|
|
|
87
87
|
}, yearsAnimationDuration);
|
|
88
88
|
}, [localScrollDate.date, setScrollDate]);
|
|
89
89
|
const { containerRef, items } = useScrollBehavior(localScrollDate, syncCalendarScrollDate, undefined, 'yearsScroll', scrollArith, scheduleScroll);
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
return (<IntersectionObserverContext.Provider value={useIntersectionObserverHandle(containerRef, intersectionObserverRootMargin)}>
|
|
91
|
+
<div className={styles.years} ref={containerRef} data-test='ring-date-popup--years'>
|
|
92
|
+
{items.map(year => (<Year year={year} scrollDate={localScrollDate.date} handleYearClick={handleYearClick} key={+year}/>))}
|
|
93
|
+
</div>
|
|
94
|
+
</IntersectionObserverContext.Provider>);
|
|
94
95
|
}
|
|
95
|
-
function Year({ year, scrollDate, handleYearClick,
|
|
96
|
+
function Year({ year, scrollDate, handleYearClick, }) {
|
|
96
97
|
const buttonRef = useRef(null);
|
|
97
|
-
const
|
|
98
|
-
return (<button type='button' ref={buttonRef} key={+year} disabled={!
|
|
99
|
-
{
|
|
98
|
+
const isIntersecting = useIsIntersecting(buttonRef);
|
|
99
|
+
return (<button type='button' ref={buttonRef} key={+year} disabled={!isIntersecting} className={classNames(styles.year, isIntersecting && isSameYear(year, scrollDate) && styles.currentYear, isIntersecting && isThisYear(year) && styles.today)} onClick={isIntersecting ? () => handleYearClick(year) : undefined}>
|
|
100
|
+
{isIntersecting ? format(year, 'yyyy') : '\u00A0'}
|
|
100
101
|
</button>);
|
|
101
102
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type RefObject } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Usage:
|
|
4
|
+
*
|
|
5
|
+
* ```tsx
|
|
6
|
+
* <IntersectionObserverContext.Provider value={useIntersectionObserverHandle()}>
|
|
7
|
+
* <YourComponent />
|
|
8
|
+
* </IntersectionObserverContext.Provider>
|
|
9
|
+
*
|
|
10
|
+
* function YourComponent() {
|
|
11
|
+
* // Contains the current isIntersecting value
|
|
12
|
+
* const isIntersecting = useIsIntersecting(elementRef);
|
|
13
|
+
* // Or, to get updates instead:
|
|
14
|
+
* useIsIntersectingListener(elementRef, newIsIntersecting => {
|
|
15
|
+
* // ...
|
|
16
|
+
* })
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare const IntersectionObserverContext: import("react").Context<IntersectionObserverHandle | null>;
|
|
21
|
+
export declare function useIntersectionObserverHandle(rootRef?: RefObject<HTMLElement | null>, rootMargin?: number, scrollMargin?: number): IntersectionObserverHandle | null;
|
|
22
|
+
export interface IntersectionObserverHandle {
|
|
23
|
+
observe(element: Element, setIsIntersecting: (isIntersecting: boolean) => void): () => void;
|
|
24
|
+
}
|
|
25
|
+
export declare function useIsIntersecting(elementRef: RefObject<Element | null>): boolean;
|
|
26
|
+
export declare function useIsIntersectingListener(elementRef: RefObject<Element | null>, onChange: (isIntersecting: boolean) => void): void;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { createContext, useContext, useEffect, useState } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Usage:
|
|
4
|
+
*
|
|
5
|
+
* ```tsx
|
|
6
|
+
* <IntersectionObserverContext.Provider value={useIntersectionObserverHandle()}>
|
|
7
|
+
* <YourComponent />
|
|
8
|
+
* </IntersectionObserverContext.Provider>
|
|
9
|
+
*
|
|
10
|
+
* function YourComponent() {
|
|
11
|
+
* // Contains the current isIntersecting value
|
|
12
|
+
* const isIntersecting = useIsIntersecting(elementRef);
|
|
13
|
+
* // Or, to get updates instead:
|
|
14
|
+
* useIsIntersectingListener(elementRef, newIsIntersecting => {
|
|
15
|
+
* // ...
|
|
16
|
+
* })
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export const IntersectionObserverContext = createContext(null);
|
|
21
|
+
export function useIntersectionObserverHandle(rootRef, rootMargin, scrollMargin) {
|
|
22
|
+
const [handle, setHandle] = useState(null);
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
const root = rootRef?.current;
|
|
25
|
+
const elementToOnChange = new Map();
|
|
26
|
+
const observer = new IntersectionObserver(entries => {
|
|
27
|
+
for (const entry of entries) {
|
|
28
|
+
const onChange = elementToOnChange.get(entry.target);
|
|
29
|
+
onChange?.(entry.isIntersecting);
|
|
30
|
+
}
|
|
31
|
+
}, {
|
|
32
|
+
root,
|
|
33
|
+
rootMargin: rootMargin != null ? `${rootMargin}px` : undefined,
|
|
34
|
+
scrollMargin: scrollMargin != null ? `${scrollMargin}px` : undefined,
|
|
35
|
+
});
|
|
36
|
+
setHandle({
|
|
37
|
+
observe(element, onChange) {
|
|
38
|
+
elementToOnChange.set(element, onChange);
|
|
39
|
+
observer.observe(element);
|
|
40
|
+
return () => {
|
|
41
|
+
elementToOnChange.delete(element);
|
|
42
|
+
observer.unobserve(element);
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
return () => {
|
|
47
|
+
observer.disconnect();
|
|
48
|
+
setHandle(null);
|
|
49
|
+
};
|
|
50
|
+
}, [rootRef, rootMargin, scrollMargin]);
|
|
51
|
+
return handle;
|
|
52
|
+
}
|
|
53
|
+
export function useIsIntersecting(elementRef) {
|
|
54
|
+
const handle = useContext(IntersectionObserverContext);
|
|
55
|
+
const [isIntersecting, setIsIntersecting] = useState(false);
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
const element = elementRef.current;
|
|
58
|
+
if (!element || !handle)
|
|
59
|
+
return;
|
|
60
|
+
return handle.observe(element, setIsIntersecting);
|
|
61
|
+
}, [handle, elementRef, setIsIntersecting]);
|
|
62
|
+
return isIntersecting;
|
|
63
|
+
}
|
|
64
|
+
export function useIsIntersectingListener(elementRef, onChange) {
|
|
65
|
+
const handle = useContext(IntersectionObserverContext);
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
const element = elementRef.current;
|
|
68
|
+
if (!element || !handle)
|
|
69
|
+
return;
|
|
70
|
+
return handle.observe(element, onChange);
|
|
71
|
+
}, [handle, elementRef, onChange]);
|
|
72
|
+
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
export interface SelectionItem {
|
|
5
5
|
id: string | number;
|
|
6
6
|
}
|
|
7
|
-
export interface TableSelectionConfig<T
|
|
7
|
+
export interface TableSelectionConfig<T> {
|
|
8
8
|
data?: readonly T[] | undefined;
|
|
9
9
|
selected?: Set<T> | undefined;
|
|
10
10
|
focused?: T | null | undefined;
|
|
@@ -17,7 +17,7 @@ export interface CloneWithConfig<T> {
|
|
|
17
17
|
selected?: Set<T> | readonly T[] | null | undefined;
|
|
18
18
|
focused?: T | null | undefined;
|
|
19
19
|
}
|
|
20
|
-
export default class Selection<T
|
|
20
|
+
export default class Selection<T> {
|
|
21
21
|
protected _rawData: readonly T[];
|
|
22
22
|
protected _getChildren: (item: T) => readonly T[];
|
|
23
23
|
protected _data: Set<T>;
|
|
@@ -11,7 +11,7 @@ export default class Selection {
|
|
|
11
11
|
_isItemSelectable;
|
|
12
12
|
constructor({ data = [], selected = new Set(), focused = null, getKey = (item) => {
|
|
13
13
|
// Default behavior stays backward compatible: use item's "id" if present
|
|
14
|
-
if ('id' in item) {
|
|
14
|
+
if (item && typeof item === 'object' && 'id' in item) {
|
|
15
15
|
return item.id;
|
|
16
16
|
}
|
|
17
17
|
// If there's no id provided on item and no getKey supplied, fail fast with a clear message
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
@import '../global/variables.css';
|
|
2
|
+
|
|
3
|
+
.tableWrapper {
|
|
4
|
+
--ring-table-compensate: 2px;
|
|
5
|
+
--ring-table-compensated: calc(calc(4 * var(--ring-unit)) - var(--ring-table-compensate));
|
|
6
|
+
--ring-table-top: -3px;
|
|
7
|
+
|
|
8
|
+
position: relative;
|
|
9
|
+
font-variant-numeric: var(--ring-font-variant-numeric);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.table {
|
|
13
|
+
width: 100%;
|
|
14
|
+
|
|
15
|
+
border-spacing: 0;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.userSelectNone {
|
|
19
|
+
user-select: none;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.headerCell {
|
|
23
|
+
composes: font-smaller-lower from '../global/global.css';
|
|
24
|
+
|
|
25
|
+
box-sizing: border-box;
|
|
26
|
+
height: calc(var(--ring-unit) * 3);
|
|
27
|
+
padding-right: calc(var(--ring-unit) * 5);
|
|
28
|
+
|
|
29
|
+
text-align: left;
|
|
30
|
+
white-space: nowrap;
|
|
31
|
+
|
|
32
|
+
color: var(--ring-secondary-color);
|
|
33
|
+
|
|
34
|
+
font-weight: normal;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.headerCell:first-child {
|
|
38
|
+
padding-left: calc(var(--ring-unit) * 4);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.headerCell:last-child {
|
|
42
|
+
width: 100%;
|
|
43
|
+
padding-right: calc(var(--ring-unit) * 4);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.headerCell:first-child:only-child {
|
|
47
|
+
width: initial;
|
|
48
|
+
max-width: none;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.headerCell.headerCellSorted {
|
|
52
|
+
font-weight: var(--ring-font-weight-bold);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.headerCell.headerCellSortable {
|
|
56
|
+
cursor: pointer;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.headerCell .sorter {
|
|
60
|
+
position: absolute;
|
|
61
|
+
top: 5px;
|
|
62
|
+
|
|
63
|
+
display: none;
|
|
64
|
+
|
|
65
|
+
margin-left: 5px;
|
|
66
|
+
|
|
67
|
+
user-select: none;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.headerCell.headerCellSortable .sorter {
|
|
71
|
+
display: inline-block;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.sortedUp .icon {
|
|
75
|
+
transform: rotate(180deg);
|
|
76
|
+
transform-origin: center 44%;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.caption {
|
|
80
|
+
padding-top: var(--ring-unit);
|
|
81
|
+
padding-bottom: 6px;
|
|
82
|
+
|
|
83
|
+
color: var(--ring-text-color);
|
|
84
|
+
border-bottom: 0;
|
|
85
|
+
|
|
86
|
+
font-size: var(--ring-font-size);
|
|
87
|
+
font-weight: var(--ring-font-weight-bold);
|
|
88
|
+
line-height: var(--ring-line-height-lower);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.tableHead::after {
|
|
92
|
+
position: absolute;
|
|
93
|
+
|
|
94
|
+
width: 100%;
|
|
95
|
+
|
|
96
|
+
height: 1px;
|
|
97
|
+
|
|
98
|
+
content: '';
|
|
99
|
+
|
|
100
|
+
background-color: var(--ring-line-color);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.subHeaderSticky {
|
|
104
|
+
position: sticky;
|
|
105
|
+
|
|
106
|
+
z-index: var(--ring-fixed-z-index);
|
|
107
|
+
top: 0;
|
|
108
|
+
|
|
109
|
+
background-color: rgba(var(--ring-content-background-components), 0.9);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.row {
|
|
113
|
+
outline: none;
|
|
114
|
+
|
|
115
|
+
line-height: var(--ring-table-compensated);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/* stylelint-disable-next-line selector-max-specificity */
|
|
119
|
+
.table:not(.disabledHover) .row:hover {
|
|
120
|
+
background-color: var(--ring-hover-background-color);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.rowSelected {
|
|
124
|
+
background-color: var(--ring-selected-background-color);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.rowFocused {
|
|
128
|
+
background-color: var(--ring-hover-background-color);
|
|
129
|
+
}
|
|
130
|
+
/* stylelint-disable-next-line selector-max-specificity */
|
|
131
|
+
.rowFocused .cell:nth-child(1) {
|
|
132
|
+
box-shadow: inset 2px 0 var(--ring-main-color);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.loadingOverlay {
|
|
136
|
+
position: absolute;
|
|
137
|
+
top: 0;
|
|
138
|
+
right: 0;
|
|
139
|
+
bottom: 0;
|
|
140
|
+
left: 0;
|
|
141
|
+
|
|
142
|
+
display: flex;
|
|
143
|
+
align-items: center;
|
|
144
|
+
justify-content: center;
|
|
145
|
+
|
|
146
|
+
background-color: var(--ring-table-loader-background-color);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.cell {
|
|
150
|
+
composes: ellipsis from '../global/global.css';
|
|
151
|
+
|
|
152
|
+
box-sizing: content-box;
|
|
153
|
+
|
|
154
|
+
min-width: 0;
|
|
155
|
+
|
|
156
|
+
height: calc(4 * var(--ring-unit));
|
|
157
|
+
padding: 0;
|
|
158
|
+
padding-right: calc(var(--ring-unit) * 5);
|
|
159
|
+
|
|
160
|
+
color: var(--ring-text-color);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.cell:first-child {
|
|
164
|
+
padding-left: calc(var(--ring-unit) * 4);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.cell:last-child {
|
|
168
|
+
width: 100%;
|
|
169
|
+
|
|
170
|
+
/* Markup hack, allows cell to have content which is wider than cell and collapses it */
|
|
171
|
+
|
|
172
|
+
max-width: 0;
|
|
173
|
+
padding-right: calc(var(--ring-unit) * 4);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.wideFirstColumn .cell:first-child {
|
|
177
|
+
min-width: calc(var(--ring-unit) * 37);
|
|
178
|
+
max-width: calc(var(--ring-unit) * 77);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.cell:first-child:only-child {
|
|
182
|
+
width: initial;
|
|
183
|
+
max-width: none;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.cellUnlimited {
|
|
187
|
+
width: 100%;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.cellRight {
|
|
191
|
+
text-align: right;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.metaColumn {
|
|
195
|
+
position: relative;
|
|
196
|
+
|
|
197
|
+
float: left;
|
|
198
|
+
|
|
199
|
+
height: 16px;
|
|
200
|
+
padding-right: var(--ring-table-compensate);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.metaColumn.headerMetaColumn {
|
|
204
|
+
padding-top: 1px;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.dragHandle {
|
|
208
|
+
top: var(--ring-table-top);
|
|
209
|
+
left: calc(-2 * var(--ring-unit));
|
|
210
|
+
|
|
211
|
+
cursor: grab;
|
|
212
|
+
|
|
213
|
+
opacity: 0;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/* override button */
|
|
217
|
+
.dragHandle.dragHandle {
|
|
218
|
+
position: absolute;
|
|
219
|
+
|
|
220
|
+
height: calc(calc(4 * var(--ring-unit)) - var(--ring-table-top));
|
|
221
|
+
padding: 0;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.dragHandle.visibleDragHandle,
|
|
225
|
+
.row:hover .dragHandle {
|
|
226
|
+
opacity: 1;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.rowCollapseExpandButton {
|
|
230
|
+
padding-right: calc(var(--ring-unit) / 2);
|
|
231
|
+
padding-left: 7px;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.draggingRow {
|
|
235
|
+
z-index: var(--ring-overlay-z-index);
|
|
236
|
+
|
|
237
|
+
background-color: var(--ring-hover-background-color);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.draggingRow .dragHandle {
|
|
241
|
+
cursor: grabbing;
|
|
242
|
+
|
|
243
|
+
opacity: 1;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.draggingRow .dragHandle svg {
|
|
247
|
+
color: var(--ring-main-color);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.draggingTable {
|
|
251
|
+
z-index: var(--ring-overlay-z-index);
|
|
252
|
+
|
|
253
|
+
border-spacing: 0;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.tableMessage {
|
|
257
|
+
padding: calc(var(--ring-unit) * 2) calc(var(--ring-unit) * 4);
|
|
258
|
+
|
|
259
|
+
color: var(--ring-secondary-color);
|
|
260
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name Table
|
|
3
|
+
*/
|
|
4
|
+
import { Component, PureComponent, type ReactNode, type SyntheticEvent } from 'react';
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
import { type OnChangeMeta } from 'react-movable/lib/types';
|
|
7
|
+
import { type FocusSensorAddProps, type FocusSensorProps } from '../global/focus-sensor-hoc';
|
|
8
|
+
import { type SelectionShortcutsAddProps, type SelectionShortcutsProps } from './selection-shortcuts-hoc';
|
|
9
|
+
import { type DisableHoverAddProps, type DisableHoverProps } from './disable-hover-hoc';
|
|
10
|
+
import Row from './row-with-focus-sensor';
|
|
11
|
+
import { type Column, type SortParams } from './header-cell';
|
|
12
|
+
export interface ReorderParams<T> {
|
|
13
|
+
data: T[];
|
|
14
|
+
oldIndex: number;
|
|
15
|
+
newIndex: number;
|
|
16
|
+
}
|
|
17
|
+
export interface TableProps<T extends object> extends FocusSensorAddProps<HTMLTableRowElement>, SelectionShortcutsAddProps<T>, DisableHoverAddProps {
|
|
18
|
+
data: readonly T[];
|
|
19
|
+
columns: readonly Column<T>[] | ((item: T | null) => readonly Column<T>[]);
|
|
20
|
+
isItemSelectable: (item: T) => boolean;
|
|
21
|
+
loading: boolean;
|
|
22
|
+
onSort: (params: SortParams) => void;
|
|
23
|
+
onReorder: (params: ReorderParams<T>) => void;
|
|
24
|
+
getItemKey: (item: T) => string | number;
|
|
25
|
+
sortKey: string;
|
|
26
|
+
sortOrder: boolean;
|
|
27
|
+
draggable: boolean;
|
|
28
|
+
alwaysShowDragHandle: boolean;
|
|
29
|
+
dragHandleTitle?: string;
|
|
30
|
+
stickyHeader: boolean;
|
|
31
|
+
wideFirstColumn: boolean;
|
|
32
|
+
getItemLevel: (item: T) => number;
|
|
33
|
+
getItemClassName: (item: T) => string | null | undefined;
|
|
34
|
+
getMetaColumnClassName: (item: T) => string | null | undefined;
|
|
35
|
+
getItemDataTest: (item: T) => string | null | undefined;
|
|
36
|
+
isItemCollapsible: (item: T) => boolean;
|
|
37
|
+
isParentCollapsible: (item: T) => boolean;
|
|
38
|
+
isItemCollapsed: (item: T) => boolean;
|
|
39
|
+
onItemCollapse: (item: T) => void;
|
|
40
|
+
onItemExpand: (item: T) => void;
|
|
41
|
+
onItemDoubleClick: (item: T) => void;
|
|
42
|
+
onItemClick: (item: T, e: React.MouseEvent<HTMLTableRowElement>) => void;
|
|
43
|
+
remoteSelection: boolean;
|
|
44
|
+
isDisabledSelectionVisible: (item: T) => boolean;
|
|
45
|
+
getCheckboxTooltip: (item: T) => string | undefined;
|
|
46
|
+
className?: string | null | undefined;
|
|
47
|
+
wrapperClassName?: string | null | undefined;
|
|
48
|
+
headerClassName?: string | null | undefined;
|
|
49
|
+
cellClassName?: string | null | undefined;
|
|
50
|
+
loaderClassName?: string | undefined;
|
|
51
|
+
caption?: string | null | undefined;
|
|
52
|
+
stickyHeaderOffset?: string | undefined;
|
|
53
|
+
renderEmpty?: (() => ReactNode) | null | undefined;
|
|
54
|
+
RowComponent: typeof Row;
|
|
55
|
+
renderLoader?: ((loaderClassName?: string) => ReactNode) | null | undefined;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Interactive table with selection and keyboard navigation support.
|
|
59
|
+
*/
|
|
60
|
+
export declare class Table<T extends object> extends PureComponent<TableProps<T>> {
|
|
61
|
+
static defaultProps: {
|
|
62
|
+
isItemSelectable: () => boolean;
|
|
63
|
+
loading: boolean;
|
|
64
|
+
onSort: () => void;
|
|
65
|
+
onReorder: () => void;
|
|
66
|
+
getItemKey: (item: object) => string | number;
|
|
67
|
+
sortKey: string;
|
|
68
|
+
sortOrder: boolean;
|
|
69
|
+
draggable: boolean;
|
|
70
|
+
alwaysShowDragHandle: boolean;
|
|
71
|
+
stickyHeader: boolean;
|
|
72
|
+
getItemLevel: () => number;
|
|
73
|
+
getItemClassName: () => null;
|
|
74
|
+
getMetaColumnClassName: () => null;
|
|
75
|
+
getItemDataTest: () => null;
|
|
76
|
+
isItemCollapsible: () => boolean;
|
|
77
|
+
isParentCollapsible: () => boolean;
|
|
78
|
+
isItemCollapsed: () => boolean;
|
|
79
|
+
onItemCollapse: () => void;
|
|
80
|
+
onItemExpand: () => void;
|
|
81
|
+
onItemDoubleClick: () => void;
|
|
82
|
+
onItemClick: () => void;
|
|
83
|
+
remoteSelection: boolean;
|
|
84
|
+
isDisabledSelectionVisible: () => boolean;
|
|
85
|
+
getCheckboxTooltip: () => undefined;
|
|
86
|
+
RowComponent: typeof Row;
|
|
87
|
+
wideFirstColumn: boolean;
|
|
88
|
+
};
|
|
89
|
+
state: {
|
|
90
|
+
shortcutsScope: string;
|
|
91
|
+
userSelectNone: boolean;
|
|
92
|
+
};
|
|
93
|
+
componentDidMount(): void;
|
|
94
|
+
componentDidUpdate({ data, selection, onSelect, selectable, remoteSelection }: TableProps<T>): void;
|
|
95
|
+
componentWillUnmount(): void;
|
|
96
|
+
onMouseDown: (e: React.MouseEvent) => void;
|
|
97
|
+
onMouseUp: () => void;
|
|
98
|
+
onRowFocus: (row: T) => void;
|
|
99
|
+
onRowSelect: (row: T, selected: boolean) => void;
|
|
100
|
+
onSortEnd: ({ oldIndex, newIndex }: OnChangeMeta) => void;
|
|
101
|
+
onCheckboxChange: (e: SyntheticEvent<HTMLInputElement>) => void;
|
|
102
|
+
restoreFocusWithoutScroll: () => void;
|
|
103
|
+
render(): React.JSX.Element;
|
|
104
|
+
}
|
|
105
|
+
export type TableAttrs<T extends object> = DisableHoverProps<SelectionShortcutsProps<T, FocusSensorProps<TableProps<T>, HTMLTableRowElement, typeof Table>>>;
|
|
106
|
+
export default class TableContainer<T extends object> extends Component<TableAttrs<T>> {
|
|
107
|
+
Table: React.ComponentClass<DisableHoverProps<SelectionShortcutsProps<T, FocusSensorProps<TableProps<T>, HTMLTableRowElement, typeof Table>>>, any>;
|
|
108
|
+
render(): React.JSX.Element;
|
|
109
|
+
}
|