@itwin/itwinui-react 3.15.5 → 3.16.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.
- package/CHANGELOG.md +23 -0
- package/DEV-cjs/core/Breadcrumbs/Breadcrumbs.js +2 -2
- package/DEV-cjs/core/Checkbox/Checkbox.js +4 -6
- package/DEV-cjs/core/ComboBox/ComboBox.js +10 -6
- package/DEV-cjs/core/DatePicker/DatePicker.js +9 -1
- package/DEV-cjs/core/Dialog/Dialog.js +1 -1
- package/DEV-cjs/core/Panels/Panels.js +319 -0
- package/DEV-cjs/core/Panels/helpers.js +62 -0
- package/DEV-cjs/core/Radio/Radio.js +4 -6
- package/DEV-cjs/core/RadioTiles/RadioTileGroup.js +9 -2
- package/DEV-cjs/core/Select/SelectTag.js +9 -11
- package/DEV-cjs/core/Select/SelectTagContainer.js +2 -2
- package/DEV-cjs/core/Stepper/Stepper.js +1 -0
- package/DEV-cjs/core/Stepper/StepperStep.js +2 -1
- package/DEV-cjs/core/Table/Table.js +3 -4
- package/DEV-cjs/core/Table/TablePaginator.js +15 -3
- package/DEV-cjs/core/Table/actionHandlers/selectHandler.js +10 -7
- package/DEV-cjs/core/Table/columns/selectionColumn.js +6 -1
- package/DEV-cjs/core/Tree/Tree.js +1 -0
- package/DEV-cjs/index.js +4 -0
- package/DEV-cjs/styles.js +1 -1
- package/DEV-cjs/utils/components/MiddleTextTruncation.js +22 -4
- package/DEV-cjs/utils/components/OverflowContainer.js +170 -27
- package/DEV-cjs/utils/hooks/index.js +1 -1
- package/DEV-cjs/utils/hooks/useInstance.js +38 -0
- package/DEV-esm/core/Breadcrumbs/Breadcrumbs.js +2 -2
- package/DEV-esm/core/Checkbox/Checkbox.js +5 -10
- package/DEV-esm/core/ComboBox/ComboBox.js +10 -6
- package/DEV-esm/core/DatePicker/DatePicker.js +11 -1
- package/DEV-esm/core/Dialog/Dialog.js +1 -1
- package/DEV-esm/core/Panels/Panels.js +301 -0
- package/DEV-esm/core/Panels/helpers.js +42 -0
- package/DEV-esm/core/Radio/Radio.js +4 -9
- package/DEV-esm/core/RadioTiles/RadioTileGroup.js +8 -2
- package/DEV-esm/core/Select/SelectTag.js +9 -11
- package/DEV-esm/core/Select/SelectTagContainer.js +2 -2
- package/DEV-esm/core/Stepper/Stepper.js +1 -0
- package/DEV-esm/core/Stepper/StepperStep.js +2 -1
- package/DEV-esm/core/Table/Table.js +1 -5
- package/DEV-esm/core/Table/TablePaginator.js +16 -3
- package/DEV-esm/core/Table/actionHandlers/selectHandler.js +10 -7
- package/DEV-esm/core/Table/columns/selectionColumn.js +6 -1
- package/DEV-esm/core/Tree/Tree.js +1 -0
- package/DEV-esm/index.js +1 -0
- package/DEV-esm/styles.js +1 -1
- package/DEV-esm/utils/components/MiddleTextTruncation.js +22 -4
- package/DEV-esm/utils/components/OverflowContainer.js +143 -4
- package/DEV-esm/utils/hooks/index.js +1 -1
- package/DEV-esm/utils/hooks/useInstance.js +18 -0
- package/cjs/core/Breadcrumbs/Breadcrumbs.js +2 -2
- package/cjs/core/Checkbox/Checkbox.js +4 -6
- package/cjs/core/ComboBox/ComboBox.d.ts +13 -0
- package/cjs/core/ComboBox/ComboBox.js +10 -6
- package/cjs/core/DatePicker/DatePicker.d.ts +2 -2
- package/cjs/core/DatePicker/DatePicker.js +2 -1
- package/cjs/core/Dialog/Dialog.js +1 -1
- package/cjs/core/Dialog/DialogContext.d.ts +6 -2
- package/cjs/core/Panels/Panels.d.ts +174 -0
- package/cjs/core/Panels/Panels.js +312 -0
- package/cjs/core/Panels/helpers.d.ts +23 -0
- package/cjs/core/Panels/helpers.js +61 -0
- package/cjs/core/Radio/Radio.js +4 -6
- package/cjs/core/RadioTiles/RadioTileGroup.d.ts +3 -1
- package/cjs/core/RadioTiles/RadioTileGroup.js +9 -2
- package/cjs/core/Select/SelectTag.d.ts +3 -1
- package/cjs/core/Select/SelectTag.js +9 -11
- package/cjs/core/Select/SelectTagContainer.js +2 -2
- package/cjs/core/Stepper/Stepper.d.ts +4 -0
- package/cjs/core/Stepper/Stepper.js +1 -0
- package/cjs/core/Stepper/StepperStep.d.ts +4 -0
- package/cjs/core/Stepper/StepperStep.js +2 -1
- package/cjs/core/Table/Table.d.ts +1 -0
- package/cjs/core/Table/Table.js +3 -4
- package/cjs/core/Table/TablePaginator.js +15 -3
- package/cjs/core/Table/actionHandlers/selectHandler.js +10 -7
- package/cjs/core/Table/columns/selectionColumn.js +6 -1
- package/cjs/core/Tree/Tree.js +1 -0
- package/cjs/index.d.ts +1 -0
- package/cjs/index.js +4 -0
- package/cjs/styles.js +1 -1
- package/cjs/utils/components/MiddleTextTruncation.d.ts +5 -7
- package/cjs/utils/components/MiddleTextTruncation.js +22 -4
- package/cjs/utils/components/OverflowContainer.d.ts +1 -0
- package/cjs/utils/components/OverflowContainer.js +170 -27
- package/cjs/utils/hooks/index.d.ts +1 -1
- package/cjs/utils/hooks/index.js +1 -1
- package/cjs/utils/hooks/useInstance.d.ts +22 -0
- package/cjs/utils/hooks/useInstance.js +38 -0
- package/esm/core/Breadcrumbs/Breadcrumbs.js +2 -2
- package/esm/core/Checkbox/Checkbox.js +5 -10
- package/esm/core/ComboBox/ComboBox.d.ts +13 -0
- package/esm/core/ComboBox/ComboBox.js +10 -6
- package/esm/core/DatePicker/DatePicker.d.ts +2 -2
- package/esm/core/DatePicker/DatePicker.js +4 -1
- package/esm/core/Dialog/Dialog.js +1 -1
- package/esm/core/Dialog/DialogContext.d.ts +6 -2
- package/esm/core/Panels/Panels.d.ts +174 -0
- package/esm/core/Panels/Panels.js +294 -0
- package/esm/core/Panels/helpers.d.ts +23 -0
- package/esm/core/Panels/helpers.js +41 -0
- package/esm/core/Radio/Radio.js +4 -9
- package/esm/core/RadioTiles/RadioTileGroup.d.ts +3 -1
- package/esm/core/RadioTiles/RadioTileGroup.js +8 -2
- package/esm/core/Select/SelectTag.d.ts +3 -1
- package/esm/core/Select/SelectTag.js +9 -11
- package/esm/core/Select/SelectTagContainer.js +2 -2
- package/esm/core/Stepper/Stepper.d.ts +4 -0
- package/esm/core/Stepper/Stepper.js +1 -0
- package/esm/core/Stepper/StepperStep.d.ts +4 -0
- package/esm/core/Stepper/StepperStep.js +2 -1
- package/esm/core/Table/Table.d.ts +1 -0
- package/esm/core/Table/Table.js +1 -5
- package/esm/core/Table/TablePaginator.js +16 -3
- package/esm/core/Table/actionHandlers/selectHandler.js +10 -7
- package/esm/core/Table/columns/selectionColumn.js +6 -1
- package/esm/core/Tree/Tree.js +1 -0
- package/esm/index.d.ts +1 -0
- package/esm/index.js +1 -0
- package/esm/styles.js +1 -1
- package/esm/utils/components/MiddleTextTruncation.d.ts +5 -7
- package/esm/utils/components/MiddleTextTruncation.js +22 -4
- package/esm/utils/components/OverflowContainer.d.ts +1 -0
- package/esm/utils/components/OverflowContainer.js +143 -4
- package/esm/utils/hooks/index.d.ts +1 -1
- package/esm/utils/hooks/index.js +1 -1
- package/esm/utils/hooks/useInstance.d.ts +22 -0
- package/esm/utils/hooks/useInstance.js +18 -0
- package/package.json +2 -2
- package/styles.css +8 -8
- package/DEV-cjs/utils/hooks/useOverflow.js +0 -76
- package/DEV-esm/utils/hooks/useOverflow.js +0 -63
- package/cjs/utils/hooks/useOverflow.d.ts +0 -23
- package/cjs/utils/hooks/useOverflow.js +0 -76
- package/esm/utils/hooks/useOverflow.d.ts +0 -23
- package/esm/utils/hooks/useOverflow.js +0 -63
|
@@ -29,6 +29,10 @@ export type StepperStepProps = {
|
|
|
29
29
|
* A tooltip giving detailed description to this step.
|
|
30
30
|
*/
|
|
31
31
|
description?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Custom content displayed in the step's circle.
|
|
34
|
+
*/
|
|
35
|
+
stepContent?: () => React.ReactNode;
|
|
32
36
|
/**
|
|
33
37
|
* Allows props to be passed for stepper step.
|
|
34
38
|
*/
|
|
@@ -17,6 +17,7 @@ export const StepperStep = React.forwardRef((props, forwardedRef) => {
|
|
|
17
17
|
trackContentProps,
|
|
18
18
|
circleProps,
|
|
19
19
|
nameProps,
|
|
20
|
+
stepContent,
|
|
20
21
|
...rest
|
|
21
22
|
} = props;
|
|
22
23
|
let isPast = currentStepNumber > index;
|
|
@@ -74,7 +75,7 @@ export const StepperStep = React.forwardRef((props, forwardedRef) => {
|
|
|
74
75
|
...circleProps,
|
|
75
76
|
className: cx('iui-stepper-circle', circleProps?.className),
|
|
76
77
|
},
|
|
77
|
-
index + 1,
|
|
78
|
+
stepContent ? stepContent() : index + 1,
|
|
78
79
|
),
|
|
79
80
|
),
|
|
80
81
|
'default' === type &&
|
|
@@ -3,6 +3,7 @@ import type { CellProps, TableOptions, Row, TableState } from '../../react-table
|
|
|
3
3
|
import type { CommonProps } from '../../utils/index.js';
|
|
4
4
|
import type { TableFilterValue } from './filters/index.js';
|
|
5
5
|
export declare const tableResizeStartAction = "tableResizeStart";
|
|
6
|
+
export declare const iuiId: unique symbol;
|
|
6
7
|
export type TablePaginatorRendererProps = {
|
|
7
8
|
/**
|
|
8
9
|
* The zero-based index of the current page.
|
package/esm/core/Table/Table.js
CHANGED
|
@@ -53,7 +53,7 @@ let singleRowSelectedAction = 'singleRowSelected';
|
|
|
53
53
|
let shiftRowSelectedAction = 'shiftRowSelected';
|
|
54
54
|
export const tableResizeStartAction = 'tableResizeStart';
|
|
55
55
|
let tableResizeEndAction = 'tableResizeEnd';
|
|
56
|
-
|
|
56
|
+
export const iuiId = Symbol('iui-id');
|
|
57
57
|
let flattenColumns = (columns) => {
|
|
58
58
|
let flatColumns = [];
|
|
59
59
|
columns.forEach((column) => {
|
|
@@ -657,11 +657,7 @@ export const Table = (props) => {
|
|
|
657
657
|
},
|
|
658
658
|
bodyProps?.className,
|
|
659
659
|
),
|
|
660
|
-
style: {
|
|
661
|
-
outline: 0,
|
|
662
|
-
},
|
|
663
660
|
}),
|
|
664
|
-
tabIndex: -1,
|
|
665
661
|
'aria-multiselectable':
|
|
666
662
|
(isSelectable && 'multi' === selectionMode) || void 0,
|
|
667
663
|
},
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
SvgChevronRight,
|
|
14
14
|
Box,
|
|
15
15
|
OverflowContainer,
|
|
16
|
+
useLayoutEffect,
|
|
16
17
|
} from '../../utils/index.js';
|
|
17
18
|
import { styles } from '../../styles.js';
|
|
18
19
|
let defaultLocalization = {
|
|
@@ -56,7 +57,7 @@ export const TablePaginator = (props) => {
|
|
|
56
57
|
);
|
|
57
58
|
let pageListRef = React.useRef(null);
|
|
58
59
|
let [focusedIndex, setFocusedIndex] = React.useState(currentPage);
|
|
59
|
-
|
|
60
|
+
useLayoutEffect(() => {
|
|
60
61
|
setFocusedIndex(currentPage);
|
|
61
62
|
}, [currentPage]);
|
|
62
63
|
let needFocus = React.useRef(false);
|
|
@@ -178,6 +179,7 @@ export const TablePaginator = (props) => {
|
|
|
178
179
|
: React.createElement(TablePaginatorPageButtons, {
|
|
179
180
|
size: size,
|
|
180
181
|
focusedIndex: focusedIndex,
|
|
182
|
+
setFocusedIndex: setFocusedIndex,
|
|
181
183
|
totalPagesCount: totalPagesCount,
|
|
182
184
|
onPageChange: onPageChange,
|
|
183
185
|
currentPage: currentPage,
|
|
@@ -251,6 +253,7 @@ export const TablePaginator = (props) => {
|
|
|
251
253
|
let TablePaginatorPageButtons = (props) => {
|
|
252
254
|
let {
|
|
253
255
|
focusedIndex,
|
|
256
|
+
setFocusedIndex,
|
|
254
257
|
totalPagesCount,
|
|
255
258
|
onPageChange,
|
|
256
259
|
currentPage,
|
|
@@ -270,14 +273,24 @@ let TablePaginatorPageButtons = (props) => {
|
|
|
270
273
|
styleType: 'borderless',
|
|
271
274
|
size: buttonSize,
|
|
272
275
|
'data-iui-active': index === currentPage,
|
|
273
|
-
onClick: () =>
|
|
276
|
+
onClick: () => {
|
|
277
|
+
setFocusedIndex(index);
|
|
278
|
+
onPageChange(index);
|
|
279
|
+
},
|
|
274
280
|
'aria-current': index === currentPage,
|
|
275
281
|
'aria-label': localization.goToPageLabel?.(index + 1),
|
|
276
282
|
tabIndex: tabIndex,
|
|
277
283
|
},
|
|
278
284
|
index + 1,
|
|
279
285
|
),
|
|
280
|
-
[
|
|
286
|
+
[
|
|
287
|
+
focusedIndex,
|
|
288
|
+
buttonSize,
|
|
289
|
+
currentPage,
|
|
290
|
+
localization,
|
|
291
|
+
setFocusedIndex,
|
|
292
|
+
onPageChange,
|
|
293
|
+
],
|
|
281
294
|
);
|
|
282
295
|
let pageList = React.useMemo(
|
|
283
296
|
() =>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { iuiId } from '../Table.js';
|
|
1
2
|
let onSelectHandler = (newState, instance, onSelect, isRowDisabled) => {
|
|
2
3
|
if (!instance?.rows.length) {
|
|
3
4
|
onSelect?.([], newState);
|
|
@@ -7,14 +8,16 @@ let onSelectHandler = (newState, instance, onSelect, isRowDisabled) => {
|
|
|
7
8
|
let handleRow = (row) => {
|
|
8
9
|
if (isRowDisabled?.(row.original)) return false;
|
|
9
10
|
let isAllSubSelected = true;
|
|
10
|
-
row.initialSubRows
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
if (row.initialSubRows[0]?.original[iuiId] === void 0)
|
|
12
|
+
row.initialSubRows.forEach((subRow) => {
|
|
13
|
+
let result = handleRow(subRow);
|
|
14
|
+
if (!result) isAllSubSelected = false;
|
|
15
|
+
});
|
|
14
16
|
if (
|
|
15
|
-
|
|
16
|
-
(!
|
|
17
|
-
|
|
17
|
+
newState.selectedRowIds[row.id] &&
|
|
18
|
+
(!instance.selectSubRows ||
|
|
19
|
+
!row.initialSubRows.length ||
|
|
20
|
+
isAllSubSelected)
|
|
18
21
|
)
|
|
19
22
|
newSelectedRowIds[row.id] = true;
|
|
20
23
|
return !!newSelectedRowIds[row.id];
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { Checkbox } from '../../Checkbox/Checkbox.js';
|
|
3
3
|
import { DefaultCell } from '../cells/index.js';
|
|
4
|
+
import { iuiId } from '../Table.js';
|
|
4
5
|
export const SELECTION_CELL_ID = 'iui-table-checkbox-selector';
|
|
5
6
|
export const SelectionColumn = (props = {}) => {
|
|
6
7
|
let { isDisabled, density } = props;
|
|
@@ -50,7 +51,11 @@ export const SelectionColumn = (props = {}) => {
|
|
|
50
51
|
disabled: isDisabled?.(row.original),
|
|
51
52
|
onClick: (e) => e.stopPropagation(),
|
|
52
53
|
onChange: () => {
|
|
53
|
-
if (
|
|
54
|
+
if (
|
|
55
|
+
row.subRows.length > 0 &&
|
|
56
|
+
selectSubRows &&
|
|
57
|
+
void 0 === row.initialSubRows[0].original[iuiId]
|
|
58
|
+
)
|
|
54
59
|
row.toggleRowSelected(
|
|
55
60
|
!row.subRows.every(
|
|
56
61
|
(subRow) => subRow.isSelected || isDisabled?.(subRow.original),
|
package/esm/core/Tree/Tree.js
CHANGED
package/esm/index.d.ts
CHANGED
|
@@ -62,6 +62,7 @@ export { ModalContent } from './core/Modal/ModalContent.js';
|
|
|
62
62
|
export { ModalButtonBar } from './core/Modal/ModalButtonBar.js';
|
|
63
63
|
export { NotificationMarker } from './core/NotificationMarker/NotificationMarker.js';
|
|
64
64
|
export { Overlay } from './core/Overlay/Overlay.js';
|
|
65
|
+
export { Panels as unstable_Panels } from './core/Panels/Panels.js';
|
|
65
66
|
export { ProgressLinear } from './core/ProgressIndicators/ProgressLinear.js';
|
|
66
67
|
export { ProgressRadial } from './core/ProgressIndicators/ProgressRadial.js';
|
|
67
68
|
export { Radio } from './core/Radio/Radio.js';
|
package/esm/index.js
CHANGED
|
@@ -64,6 +64,7 @@ export { ModalContent } from './core/Modal/ModalContent.js';
|
|
|
64
64
|
export { ModalButtonBar } from './core/Modal/ModalButtonBar.js';
|
|
65
65
|
export { NotificationMarker } from './core/NotificationMarker/NotificationMarker.js';
|
|
66
66
|
export { Overlay } from './core/Overlay/Overlay.js';
|
|
67
|
+
export { Panels as unstable_Panels } from './core/Panels/Panels.js';
|
|
67
68
|
export { ProgressLinear } from './core/ProgressIndicators/ProgressLinear.js';
|
|
68
69
|
export { ProgressRadial } from './core/ProgressIndicators/ProgressRadial.js';
|
|
69
70
|
export { Radio } from './core/Radio/Radio.js';
|
package/esm/styles.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import type {
|
|
3
|
-
|
|
2
|
+
import type { PolymorphicForwardRefComponent } from '../props.js';
|
|
3
|
+
type MiddleTextTruncationProps = {
|
|
4
4
|
/**
|
|
5
5
|
* Text to truncate.
|
|
6
6
|
*/
|
|
@@ -14,7 +14,7 @@ export type MiddleTextTruncationProps = {
|
|
|
14
14
|
* Custom renderer for the truncated text.
|
|
15
15
|
*/
|
|
16
16
|
textRenderer?: (truncatedText: string, originalText: string) => React.ReactNode;
|
|
17
|
-
}
|
|
17
|
+
};
|
|
18
18
|
/**
|
|
19
19
|
* Truncates text with the ellipsis in the middle,
|
|
20
20
|
* leaving defined number of chars at the end.
|
|
@@ -31,7 +31,5 @@ export type MiddleTextTruncationProps = {
|
|
|
31
31
|
* )}
|
|
32
32
|
* />
|
|
33
33
|
*/
|
|
34
|
-
export declare const MiddleTextTruncation:
|
|
35
|
-
|
|
36
|
-
displayName: string;
|
|
37
|
-
};
|
|
34
|
+
export declare const MiddleTextTruncation: PolymorphicForwardRefComponent<"span", MiddleTextTruncationProps>;
|
|
35
|
+
export {};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { OverflowContainer } from './OverflowContainer.js';
|
|
3
|
+
import { VisuallyHidden } from '../../core/VisuallyHidden/VisuallyHidden.js';
|
|
4
|
+
import { ShadowRoot } from './ShadowRoot.js';
|
|
3
5
|
let ELLIPSIS_CHAR = '…';
|
|
4
|
-
export const MiddleTextTruncation = (props) => {
|
|
5
|
-
let { text, style, ...rest } = props;
|
|
6
|
+
export const MiddleTextTruncation = React.forwardRef((props, forwardedRef) => {
|
|
7
|
+
let { text, endCharsCount, textRenderer, style, ...rest } = props;
|
|
6
8
|
return React.createElement(
|
|
7
9
|
OverflowContainer,
|
|
8
10
|
{
|
|
@@ -16,10 +18,26 @@ export const MiddleTextTruncation = (props) => {
|
|
|
16
18
|
},
|
|
17
19
|
itemsCount: text.length,
|
|
18
20
|
...rest,
|
|
21
|
+
ref: forwardedRef,
|
|
19
22
|
},
|
|
20
|
-
React.createElement(
|
|
23
|
+
React.createElement(
|
|
24
|
+
ShadowRoot,
|
|
25
|
+
null,
|
|
26
|
+
React.createElement(VisuallyHidden, null, text),
|
|
27
|
+
React.createElement('slot', {
|
|
28
|
+
'aria-hidden': true,
|
|
29
|
+
style: {
|
|
30
|
+
pointerEvents: 'none',
|
|
31
|
+
},
|
|
32
|
+
}),
|
|
33
|
+
),
|
|
34
|
+
React.createElement(MiddleTextTruncationContent, {
|
|
35
|
+
text: text,
|
|
36
|
+
endCharsCount: endCharsCount,
|
|
37
|
+
textRenderer: textRenderer,
|
|
38
|
+
}),
|
|
21
39
|
);
|
|
22
|
-
};
|
|
40
|
+
});
|
|
23
41
|
let MiddleTextTruncationContent = (props) => {
|
|
24
42
|
let { text, endCharsCount = 6, textRenderer } = props;
|
|
25
43
|
let { visibleCount } = OverflowContainer.useContext();
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { useMergedRefs } from '../hooks/useMergedRefs.js';
|
|
3
3
|
import { Box } from './Box.js';
|
|
4
|
-
import {
|
|
4
|
+
import { useLayoutEffect } from '../hooks/useIsomorphicLayoutEffect.js';
|
|
5
5
|
import { useSafeContext } from '../hooks/useSafeContext.js';
|
|
6
|
-
|
|
6
|
+
import { isUnitTest } from '../functions/dev.js';
|
|
7
|
+
import { useResizeObserver } from '../hooks/useResizeObserver.js';
|
|
8
|
+
let OverflowContainerMain = React.forwardRef((props, forwardedRef) => {
|
|
7
9
|
let { itemsCount, children, overflowOrientation, ...rest } = props;
|
|
8
10
|
let [containerRef, visibleCount] = useOverflow(
|
|
9
11
|
itemsCount,
|
|
10
|
-
false,
|
|
11
12
|
overflowOrientation,
|
|
12
13
|
);
|
|
13
14
|
let overflowContainerContextValue = React.useMemo(
|
|
@@ -25,7 +26,7 @@ let OverflowContainerComponent = React.forwardRef((props, ref) => {
|
|
|
25
26
|
React.createElement(
|
|
26
27
|
Box,
|
|
27
28
|
{
|
|
28
|
-
ref: useMergedRefs(
|
|
29
|
+
ref: useMergedRefs(forwardedRef, containerRef),
|
|
29
30
|
...rest,
|
|
30
31
|
},
|
|
31
32
|
children,
|
|
@@ -38,11 +39,149 @@ let OverflowContainerOverflowNode = (props) => {
|
|
|
38
39
|
let isOverflowing = visibleCount < itemsCount;
|
|
39
40
|
return isOverflowing ? children : null;
|
|
40
41
|
};
|
|
42
|
+
let OverflowContainerComponent = React.forwardRef((props, forwardedRef) => {
|
|
43
|
+
let { itemsCount, overflowOrientation = 'horizontal', ...rest } = props;
|
|
44
|
+
let [size, setSize] = React.useState(null);
|
|
45
|
+
let [resizeRef] = useResizeObserver(setSize);
|
|
46
|
+
let ref = useMergedRefs(resizeRef, forwardedRef);
|
|
47
|
+
let key = `${itemsCount}${
|
|
48
|
+
'vertical' === overflowOrientation ? size?.height : size?.width
|
|
49
|
+
}`;
|
|
50
|
+
return React.createElement(OverflowContainerMain, {
|
|
51
|
+
...rest,
|
|
52
|
+
key: key,
|
|
53
|
+
ref: ref,
|
|
54
|
+
itemsCount: itemsCount,
|
|
55
|
+
overflowOrientation: overflowOrientation,
|
|
56
|
+
});
|
|
57
|
+
});
|
|
41
58
|
export const OverflowContainer = Object.assign(OverflowContainerComponent, {
|
|
42
59
|
OverflowNode: OverflowContainerOverflowNode,
|
|
43
60
|
useContext: useOverflowContainerContext,
|
|
44
61
|
});
|
|
45
62
|
let OverflowContainerContext = React.createContext(void 0);
|
|
63
|
+
let useOverflow = (itemsCount, orientation = 'horizontal') => {
|
|
64
|
+
let [guessState, dispatch] = React.useReducer(
|
|
65
|
+
overflowGuessReducer,
|
|
66
|
+
{
|
|
67
|
+
itemsCount,
|
|
68
|
+
},
|
|
69
|
+
overflowGuessReducerInitialState,
|
|
70
|
+
);
|
|
71
|
+
let containerRef = React.useRef(null);
|
|
72
|
+
let isGuessing = React.useRef(false);
|
|
73
|
+
useLayoutEffect(() => {
|
|
74
|
+
let { minGuess, maxGuess, isStabilized, visibleCount } = guessState;
|
|
75
|
+
if (isStabilized) return;
|
|
76
|
+
guessVisibleCount();
|
|
77
|
+
function guessVisibleCount() {
|
|
78
|
+
if (isStabilized || isGuessing.current || isUnitTest) return;
|
|
79
|
+
try {
|
|
80
|
+
isGuessing.current = true;
|
|
81
|
+
if (null == containerRef.current) return;
|
|
82
|
+
let dimension = 'horizontal' === orientation ? 'Width' : 'Height';
|
|
83
|
+
let availableSize = containerRef.current[`offset${dimension}`];
|
|
84
|
+
let requiredSize = containerRef.current[`scroll${dimension}`];
|
|
85
|
+
let isOverflowing = availableSize < requiredSize;
|
|
86
|
+
if (
|
|
87
|
+
0 === itemsCount ||
|
|
88
|
+
(1 === visibleCount && isOverflowing) ||
|
|
89
|
+
(visibleCount === itemsCount && !isOverflowing) ||
|
|
90
|
+
(maxGuess - minGuess === 1 && visibleCount === minGuess)
|
|
91
|
+
) {
|
|
92
|
+
dispatch({
|
|
93
|
+
type: 'stabilize',
|
|
94
|
+
});
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (maxGuess === visibleCount && !isOverflowing) {
|
|
98
|
+
dispatch({
|
|
99
|
+
type: 'shiftGuessRangeForward',
|
|
100
|
+
});
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
isOverflowing
|
|
104
|
+
? dispatch({
|
|
105
|
+
type: 'decreaseMaxGuess',
|
|
106
|
+
currentState: guessState,
|
|
107
|
+
})
|
|
108
|
+
: dispatch({
|
|
109
|
+
type: 'increaseMinGuess',
|
|
110
|
+
currentState: guessState,
|
|
111
|
+
});
|
|
112
|
+
} finally {
|
|
113
|
+
isGuessing.current = false;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}, [guessState, itemsCount, orientation]);
|
|
117
|
+
return [containerRef, guessState.visibleCount];
|
|
118
|
+
};
|
|
119
|
+
let STARTING_MAX_ITEMS_COUNT = 32;
|
|
120
|
+
let overflowGuessReducerInitialState = ({ itemsCount }) => {
|
|
121
|
+
let initialVisibleCount = Math.min(itemsCount, STARTING_MAX_ITEMS_COUNT);
|
|
122
|
+
return isUnitTest
|
|
123
|
+
? {
|
|
124
|
+
isStabilized: true,
|
|
125
|
+
minGuess: null,
|
|
126
|
+
maxGuess: null,
|
|
127
|
+
itemsCount,
|
|
128
|
+
visibleCount: itemsCount,
|
|
129
|
+
}
|
|
130
|
+
: {
|
|
131
|
+
isStabilized: false,
|
|
132
|
+
minGuess: 0,
|
|
133
|
+
maxGuess: initialVisibleCount,
|
|
134
|
+
itemsCount,
|
|
135
|
+
visibleCount: initialVisibleCount,
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
let overflowGuessReducer = (state, action) => {
|
|
139
|
+
let getSafeVisibleCount = ({ visibleCount, itemsCount }) =>
|
|
140
|
+
Math.min(itemsCount, visibleCount);
|
|
141
|
+
switch (action.type) {
|
|
142
|
+
case 'decreaseMaxGuess':
|
|
143
|
+
case 'increaseMinGuess':
|
|
144
|
+
if (state.isStabilized) return state;
|
|
145
|
+
let newMinGuess = state.minGuess;
|
|
146
|
+
let newMaxGuess = state.maxGuess;
|
|
147
|
+
if ('decreaseMaxGuess' === action.type)
|
|
148
|
+
newMaxGuess = action.currentState.visibleCount;
|
|
149
|
+
else newMinGuess = action.currentState.visibleCount;
|
|
150
|
+
let newVisibleCount = Math.floor((newMinGuess + newMaxGuess) / 2);
|
|
151
|
+
return {
|
|
152
|
+
...state,
|
|
153
|
+
isStabilized: false,
|
|
154
|
+
minGuess: newMinGuess,
|
|
155
|
+
maxGuess: newMaxGuess,
|
|
156
|
+
visibleCount: getSafeVisibleCount({
|
|
157
|
+
visibleCount: newVisibleCount,
|
|
158
|
+
itemsCount: state.itemsCount,
|
|
159
|
+
}),
|
|
160
|
+
};
|
|
161
|
+
case 'shiftGuessRangeForward':
|
|
162
|
+
if (state.isStabilized) return state;
|
|
163
|
+
let doubleOfMaxGuess = 2 * state.maxGuess;
|
|
164
|
+
return {
|
|
165
|
+
...state,
|
|
166
|
+
isStabilized: false,
|
|
167
|
+
minGuess: state.maxGuess,
|
|
168
|
+
maxGuess: doubleOfMaxGuess,
|
|
169
|
+
visibleCount: getSafeVisibleCount({
|
|
170
|
+
visibleCount: doubleOfMaxGuess,
|
|
171
|
+
itemsCount: state.itemsCount,
|
|
172
|
+
}),
|
|
173
|
+
};
|
|
174
|
+
case 'stabilize':
|
|
175
|
+
return {
|
|
176
|
+
...state,
|
|
177
|
+
isStabilized: true,
|
|
178
|
+
minGuess: null,
|
|
179
|
+
maxGuess: null,
|
|
180
|
+
};
|
|
181
|
+
default:
|
|
182
|
+
return state;
|
|
183
|
+
}
|
|
184
|
+
};
|
|
46
185
|
function useOverflowContainerContext() {
|
|
47
186
|
let overflowContainerContext = useSafeContext(OverflowContainerContext);
|
|
48
187
|
return overflowContainerContext;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export * from './useEventListener.js';
|
|
2
2
|
export * from './useMergedRefs.js';
|
|
3
|
-
export * from './useOverflow.js';
|
|
4
3
|
export * from './useResizeObserver.js';
|
|
5
4
|
export * from './useContainerWidth.js';
|
|
6
5
|
export * from './useGlobals.js';
|
|
@@ -14,4 +13,5 @@ export * from './useId.js';
|
|
|
14
13
|
export * from './useControlledState.js';
|
|
15
14
|
export * from './useSyncExternalStore.js';
|
|
16
15
|
export * from './useVirtualScroll.js';
|
|
16
|
+
export * from './useInstance.js';
|
|
17
17
|
export * from './useWarningLogger.js';
|
package/esm/utils/hooks/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export * from './useEventListener.js';
|
|
2
2
|
export * from './useMergedRefs.js';
|
|
3
|
-
export * from './useOverflow.js';
|
|
4
3
|
export * from './useResizeObserver.js';
|
|
5
4
|
export * from './useContainerWidth.js';
|
|
6
5
|
export * from './useGlobals.js';
|
|
@@ -14,4 +13,5 @@ export * from './useId.js';
|
|
|
14
13
|
export * from './useControlledState.js';
|
|
15
14
|
export * from './useSyncExternalStore.js';
|
|
16
15
|
export * from './useVirtualScroll.js';
|
|
16
|
+
export * from './useInstance.js';
|
|
17
17
|
export * from './useWarningLogger.js';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
declare class Instance {
|
|
2
|
+
}
|
|
3
|
+
export declare const useInstance: () => Instance;
|
|
4
|
+
/**
|
|
5
|
+
* Synchronizes the instance with the provided properties.
|
|
6
|
+
*
|
|
7
|
+
* @param instance Instance created by `useInstance`.
|
|
8
|
+
* @param properties Memoized object containing properties to be synchronized.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* const instance = useInstance();
|
|
12
|
+
*
|
|
13
|
+
* const properties = React.useMemo(() => ({
|
|
14
|
+
* show: () => console.log('show'),
|
|
15
|
+
* }), []);
|
|
16
|
+
*
|
|
17
|
+
* useSynchronizeInstance(instance, properties);
|
|
18
|
+
*
|
|
19
|
+
* instance.show(); // logs 'show'
|
|
20
|
+
*/
|
|
21
|
+
export declare const useSynchronizeInstance: <T>(instance: T, properties: T) => T;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useSyncExternalStore } from './useSyncExternalStore.js';
|
|
3
|
+
class Instance {}
|
|
4
|
+
export const useInstance = () => React.useMemo(() => new Instance(), []);
|
|
5
|
+
export const useSynchronizeInstance = (instance, properties) => {
|
|
6
|
+
let synchronize = React.useCallback(() => {
|
|
7
|
+
if (!(instance instanceof Instance)) return () => {};
|
|
8
|
+
Object.assign(instance, properties);
|
|
9
|
+
return () => {
|
|
10
|
+
for (let key in properties) delete instance[key];
|
|
11
|
+
};
|
|
12
|
+
}, [instance, properties]);
|
|
13
|
+
return useSyncExternalStore(
|
|
14
|
+
synchronize,
|
|
15
|
+
() => instance,
|
|
16
|
+
() => instance,
|
|
17
|
+
);
|
|
18
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@itwin/itwinui-react",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.16.0",
|
|
4
4
|
"author": "Bentley Systems",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"react-transition-group": "^4.4.5"
|
|
90
90
|
},
|
|
91
91
|
"devDependencies": {
|
|
92
|
-
"@swc/cli": "^0.
|
|
92
|
+
"@swc/cli": "^0.5.1",
|
|
93
93
|
"@swc/core": "^1.5.28",
|
|
94
94
|
"@testing-library/jest-dom": "^6.3.0",
|
|
95
95
|
"@testing-library/react": "^13.2.0",
|