@itwin/itwinui-react 3.10.0 → 3.11.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 +30 -0
- package/cjs/core/Alert/Alert.d.ts +1 -1
- package/cjs/core/Buttons/Button.d.ts +4 -0
- package/cjs/core/Buttons/Button.js +6 -4
- package/cjs/core/Carousel/Carousel.d.ts +2 -2
- package/cjs/core/Carousel/CarouselNavigation.d.ts +2 -2
- package/cjs/core/ComboBox/ComboBoxInput.js +2 -4
- package/cjs/core/ComboBox/ComboBoxMenu.js +7 -3
- package/cjs/core/ExpandableBlock/ExpandableBlock.d.ts +1 -1
- package/cjs/core/InputWithDecorations/InputWithDecorations.d.ts +1 -1
- package/cjs/core/LabeledSelect/LabeledSelect.d.ts +9 -9
- package/cjs/core/Menu/MenuItem.js +11 -2
- package/cjs/core/Popover/Popover.js +4 -1
- package/cjs/core/Select/Select.js +28 -2
- package/cjs/core/SideNavigation/SideNavigation.d.ts +1 -0
- package/cjs/core/SideNavigation/SideNavigation.js +20 -21
- package/cjs/core/SideNavigation/SidenavButton.js +5 -1
- package/cjs/core/Surface/Surface.js +2 -2
- package/cjs/core/Table/Table.js +4 -7
- package/cjs/core/Tabs/Tabs.d.ts +1 -1
- package/cjs/core/Tile/Tile.d.ts +17 -1
- package/cjs/core/Tooltip/Tooltip.js +28 -6
- package/cjs/core/Tree/TreeNode.d.ts +39 -0
- package/cjs/core/Tree/TreeNode.js +11 -11
- package/cjs/core/Tree/TreeNodeExpander.d.ts +2 -0
- package/cjs/core/Tree/TreeNodeExpander.js +2 -2
- package/esm/core/Alert/Alert.d.ts +1 -1
- package/esm/core/Buttons/Button.d.ts +4 -0
- package/esm/core/Buttons/Button.js +6 -4
- package/esm/core/Carousel/Carousel.d.ts +2 -2
- package/esm/core/Carousel/CarouselNavigation.d.ts +2 -2
- package/esm/core/ComboBox/ComboBoxInput.js +3 -5
- package/esm/core/ComboBox/ComboBoxMenu.js +4 -2
- package/esm/core/ExpandableBlock/ExpandableBlock.d.ts +1 -1
- package/esm/core/InputWithDecorations/InputWithDecorations.d.ts +1 -1
- package/esm/core/LabeledSelect/LabeledSelect.d.ts +9 -9
- package/esm/core/Menu/MenuItem.js +11 -2
- package/esm/core/Popover/Popover.js +4 -1
- package/esm/core/Select/Select.js +28 -2
- package/esm/core/SideNavigation/SideNavigation.d.ts +1 -0
- package/esm/core/SideNavigation/SideNavigation.js +20 -21
- package/esm/core/SideNavigation/SidenavButton.js +5 -1
- package/esm/core/Surface/Surface.js +2 -2
- package/esm/core/Table/Table.js +5 -8
- package/esm/core/Tabs/Tabs.d.ts +1 -1
- package/esm/core/Tile/Tile.d.ts +17 -1
- package/esm/core/Tooltip/Tooltip.js +28 -6
- package/esm/core/Tree/TreeNode.d.ts +39 -0
- package/esm/core/Tree/TreeNode.js +11 -11
- package/esm/core/Tree/TreeNodeExpander.d.ts +2 -0
- package/esm/core/Tree/TreeNodeExpander.js +2 -2
- package/package.json +1 -1
- package/styles.css +21 -21
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
*--------------------------------------------------------------------------------------------*/
|
|
5
5
|
import * as React from 'react';
|
|
6
6
|
import cx from 'classnames';
|
|
7
|
-
import { WithCSSTransition, SvgChevronRight, Box } from '../../utils/index.js';
|
|
7
|
+
import { WithCSSTransition, SvgChevronRight, Box, useControlledState, } from '../../utils/index.js';
|
|
8
8
|
import { IconButton } from '../Buttons/IconButton.js';
|
|
9
|
-
|
|
9
|
+
// ----------------------------------------------------------------------------
|
|
10
|
+
export const SidenavExpandedContext = React.createContext(undefined);
|
|
10
11
|
/**
|
|
11
12
|
* Left side navigation menu component.
|
|
12
13
|
* @example
|
|
@@ -22,25 +23,23 @@ import { Tooltip } from '../Tooltip/Tooltip.js';
|
|
|
22
23
|
* />
|
|
23
24
|
*/
|
|
24
25
|
export const SideNavigation = React.forwardRef((props, forwardedRef) => {
|
|
25
|
-
const { items, secondaryItems, expanderPlacement = 'top', className, isExpanded
|
|
26
|
-
const [
|
|
27
|
-
React.
|
|
28
|
-
|
|
29
|
-
}, [isExpanded]);
|
|
30
|
-
const ExpandButton = (React.createElement(IconButton, { label: 'Toggle icon labels', "aria-expanded": _isExpanded, className: 'iui-sidenav-button iui-expand', size: 'small', onClick: React.useCallback(() => {
|
|
31
|
-
_setIsExpanded((expanded) => !expanded);
|
|
26
|
+
const { items, secondaryItems, expanderPlacement = 'top', className, isExpanded: isExpandedProp, onExpanderClick, submenu, isSubmenuOpen = false, wrapperProps, contentProps, topProps, bottomProps, ...rest } = props;
|
|
27
|
+
const [isExpanded, setIsExpanded] = useControlledState(false, isExpandedProp);
|
|
28
|
+
const ExpandButton = (React.createElement(IconButton, { label: 'Toggle icon labels', "aria-expanded": isExpanded, className: 'iui-sidenav-button iui-expand', size: 'small', onClick: React.useCallback(() => {
|
|
29
|
+
setIsExpanded((expanded) => !expanded);
|
|
32
30
|
onExpanderClick?.();
|
|
33
|
-
}, [onExpanderClick]) },
|
|
31
|
+
}, [onExpanderClick, setIsExpanded]) },
|
|
34
32
|
React.createElement(SvgChevronRight, null)));
|
|
35
|
-
return (React.createElement(
|
|
36
|
-
React.createElement(Box, {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
React.createElement(Box, { as: 'div', ...
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
33
|
+
return (React.createElement(SidenavExpandedContext.Provider, { value: isExpanded },
|
|
34
|
+
React.createElement(Box, { ...wrapperProps, className: cx('iui-side-navigation-wrapper', wrapperProps?.className), ref: forwardedRef },
|
|
35
|
+
React.createElement(Box, { as: 'div', className: cx('iui-side-navigation', {
|
|
36
|
+
'iui-expanded': isExpanded,
|
|
37
|
+
'iui-collapsed': !isExpanded,
|
|
38
|
+
}, className), ...rest },
|
|
39
|
+
expanderPlacement === 'top' && ExpandButton,
|
|
40
|
+
React.createElement(Box, { as: 'div', ...contentProps, className: cx('iui-sidenav-content', contentProps?.className) },
|
|
41
|
+
React.createElement(Box, { as: 'div', ...topProps, className: cx('iui-top', topProps?.className) }, items),
|
|
42
|
+
React.createElement(Box, { as: 'div', ...bottomProps, className: cx('iui-bottom', bottomProps?.className) }, secondaryItems)),
|
|
43
|
+
expanderPlacement === 'bottom' && ExpandButton),
|
|
44
|
+
submenu && (React.createElement(WithCSSTransition, { in: isSubmenuOpen, dimension: 'width', timeout: 200, classNames: 'iui' }, submenu)))));
|
|
46
45
|
});
|
|
@@ -5,11 +5,15 @@
|
|
|
5
5
|
import cx from 'classnames';
|
|
6
6
|
import * as React from 'react';
|
|
7
7
|
import { Button } from '../Buttons/Button.js';
|
|
8
|
+
import { Tooltip } from '../Tooltip/Tooltip.js';
|
|
9
|
+
import { SidenavExpandedContext } from './SideNavigation.js';
|
|
8
10
|
/**
|
|
9
11
|
* Wrapper around Button to be used as SideNavigation items.
|
|
10
12
|
* Label is hidden when sidenav is collapsed.
|
|
11
13
|
*/
|
|
12
14
|
export const SidenavButton = React.forwardRef((props, ref) => {
|
|
13
15
|
const { className, children, isActive = false, disabled = false, isSubmenuOpen = false, ...rest } = props;
|
|
14
|
-
|
|
16
|
+
const isExpanded = React.useContext(SidenavExpandedContext) === true;
|
|
17
|
+
const sidenavButton = (React.createElement(Button, { className: cx('iui-sidenav-button', { 'iui-submenu-open': isSubmenuOpen }, className), "data-iui-active": isActive, size: 'large', disabled: disabled, ref: ref, ...rest }, children));
|
|
18
|
+
return !isExpanded ? (React.createElement(Tooltip, { content: children, placement: 'right', ariaStrategy: 'none' }, sidenavButton)) : (sidenavButton);
|
|
15
19
|
});
|
|
@@ -23,7 +23,7 @@ const getSurfaceElevationValue = (elevation) => {
|
|
|
23
23
|
case 5:
|
|
24
24
|
return 'var(--iui-shadow-5)';
|
|
25
25
|
default:
|
|
26
|
-
return
|
|
26
|
+
return undefined;
|
|
27
27
|
}
|
|
28
28
|
};
|
|
29
29
|
/** Returns correct border value based on prop */
|
|
@@ -34,7 +34,7 @@ const getBorderValue = (border) => {
|
|
|
34
34
|
if (border === false) {
|
|
35
35
|
return 'none';
|
|
36
36
|
}
|
|
37
|
-
return
|
|
37
|
+
return undefined;
|
|
38
38
|
};
|
|
39
39
|
// ----------------------------------------------------------------------------
|
|
40
40
|
// Surface.Header component
|
package/esm/core/Table/Table.js
CHANGED
|
@@ -6,7 +6,7 @@ import * as React from 'react';
|
|
|
6
6
|
import cx from 'classnames';
|
|
7
7
|
import { actions as TableActions, useFlexLayout, useFilters, useRowSelect, useSortBy, useTable, useExpanded, usePagination, useColumnOrder, useGlobalFilter, } from 'react-table';
|
|
8
8
|
import { ProgressRadial } from '../ProgressIndicators/ProgressRadial.js';
|
|
9
|
-
import { useGlobals, useResizeObserver, SvgSortDown, SvgSortUp, useLayoutEffect, Box, createWarningLogger, ShadowRoot, LineClamp, useMergedRefs, } from '../../utils/index.js';
|
|
9
|
+
import { useGlobals, useResizeObserver, SvgSortDown, SvgSortUp, useLayoutEffect, Box, createWarningLogger, ShadowRoot, LineClamp, useMergedRefs, useLatestRef, } from '../../utils/index.js';
|
|
10
10
|
import { TableColumnsContext, getCellStyle, getStickyStyle, getSubRowStyle, } from './utils.js';
|
|
11
11
|
import { TableRowMemoized } from './TableRowMemoized.js';
|
|
12
12
|
import { FilterToggle } from './filters/index.js';
|
|
@@ -81,13 +81,8 @@ export const Table = (props) => {
|
|
|
81
81
|
minWidth: 0,
|
|
82
82
|
width: 0,
|
|
83
83
|
}), []);
|
|
84
|
-
|
|
85
|
-
const
|
|
86
|
-
const onRowInViewportRef = React.useRef(onRowInViewport);
|
|
87
|
-
React.useEffect(() => {
|
|
88
|
-
onBottomReachedRef.current = onBottomReached;
|
|
89
|
-
onRowInViewportRef.current = onRowInViewport;
|
|
90
|
-
}, [onBottomReached, onRowInViewport]);
|
|
84
|
+
const onBottomReachedRef = useLatestRef(onBottomReached);
|
|
85
|
+
const onRowInViewportRef = useLatestRef(onRowInViewport);
|
|
91
86
|
const hasManualSelectionColumn = React.useMemo(() => {
|
|
92
87
|
const flatColumns = flattenColumns(columns);
|
|
93
88
|
return flatColumns.some((column) => column.id === SELECTION_CELL_ID);
|
|
@@ -357,6 +352,8 @@ export const Table = (props) => {
|
|
|
357
352
|
enableVirtualization,
|
|
358
353
|
tableRowRef,
|
|
359
354
|
density,
|
|
355
|
+
onBottomReachedRef,
|
|
356
|
+
onRowInViewportRef,
|
|
360
357
|
]);
|
|
361
358
|
const virtualizedItemRenderer = React.useCallback((index) => getPreparedRow(index), [getPreparedRow]);
|
|
362
359
|
const updateStickyState = () => {
|
package/esm/core/Tabs/Tabs.d.ts
CHANGED
|
@@ -269,7 +269,7 @@ export declare const Tabs: PolymorphicForwardRefComponent<"div", TabsLegacyProps
|
|
|
269
269
|
ref?: ((instance: HTMLSpanElement | null) => void) | React.RefObject<HTMLSpanElement> | null | undefined;
|
|
270
270
|
}, "fill" | "as" | "key" | "size" | keyof React.HTMLAttributes<HTMLSpanElement> | "padded"> & {
|
|
271
271
|
size?: "small" | "auto" | "medium" | "large" | import("../../utils/types.js").AnyString | undefined;
|
|
272
|
-
fill?: "default" |
|
|
272
|
+
fill?: "default" | "positive" | "negative" | "warning" | import("../../utils/types.js").AnyString | "informational" | undefined;
|
|
273
273
|
padded?: boolean | undefined;
|
|
274
274
|
} & Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & {
|
|
275
275
|
as?: "span" | undefined;
|
package/esm/core/Tile/Tile.d.ts
CHANGED
|
@@ -249,7 +249,7 @@ export declare const Tile: PolymorphicForwardRefComponent<"div", TileLegacyProps
|
|
|
249
249
|
*/
|
|
250
250
|
IconButton: PolymorphicForwardRefComponent<"button", Omit<Omit<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
|
|
251
251
|
ref?: ((instance: HTMLButtonElement | null) => void) | React.RefObject<HTMLButtonElement> | null | undefined;
|
|
252
|
-
}, "label" | "as" | "size" | "htmlDisabled" | "styleType" | "labelProps" | "stretched" | "isActive" | "iconProps"> & {
|
|
252
|
+
}, "label" | "as" | "loading" | "size" | "htmlDisabled" | "styleType" | "labelProps" | "stretched" | "isActive" | "iconProps"> & {
|
|
253
253
|
isActive?: boolean | undefined;
|
|
254
254
|
label?: React.ReactNode;
|
|
255
255
|
labelProps?: Omit<Omit<Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
|
|
@@ -262,6 +262,14 @@ export declare const Tile: PolymorphicForwardRefComponent<"div", TileLegacyProps
|
|
|
262
262
|
ancestorScroll?: boolean | undefined;
|
|
263
263
|
ancestorResize?: boolean | undefined;
|
|
264
264
|
elementResize?: boolean | undefined;
|
|
265
|
+
/**
|
|
266
|
+
* Flag whether the tile is disabled.
|
|
267
|
+
*
|
|
268
|
+
* Note: This only affects the tile. You need to manually disable
|
|
269
|
+
* the buttons and other interactive elements inside the tile.
|
|
270
|
+
*
|
|
271
|
+
* @default false
|
|
272
|
+
*/
|
|
265
273
|
animationFrame?: boolean | undefined;
|
|
266
274
|
layoutShift?: boolean | undefined;
|
|
267
275
|
} | undefined;
|
|
@@ -288,6 +296,14 @@ export declare const Tile: PolymorphicForwardRefComponent<"div", TileLegacyProps
|
|
|
288
296
|
ancestorScroll?: boolean | undefined;
|
|
289
297
|
ancestorResize?: boolean | undefined;
|
|
290
298
|
elementResize?: boolean | undefined;
|
|
299
|
+
/**
|
|
300
|
+
* Flag whether the tile is disabled.
|
|
301
|
+
*
|
|
302
|
+
* Note: This only affects the tile. You need to manually disable
|
|
303
|
+
* the buttons and other interactive elements inside the tile.
|
|
304
|
+
*
|
|
305
|
+
* @default false
|
|
306
|
+
*/
|
|
291
307
|
animationFrame?: boolean | undefined;
|
|
292
308
|
layoutShift?: boolean | undefined;
|
|
293
309
|
} | undefined;
|
|
@@ -6,10 +6,22 @@ import * as React from 'react';
|
|
|
6
6
|
import cx from 'classnames';
|
|
7
7
|
import { useFloating, autoUpdate, offset, flip, shift, useHover, useFocus, useDismiss, useInteractions, safePolygon, size, autoPlacement, hide, inline, useDelayGroupContext, useDelayGroup, } from '@floating-ui/react';
|
|
8
8
|
import { Box, Portal, cloneElementWithRef, useControlledState, useId, useMergedRefs, } from '../../utils/index.js';
|
|
9
|
+
// ----------------------------------------------------------------------------
|
|
9
10
|
const useTooltip = (options = {}) => {
|
|
10
11
|
const uniqueId = useId();
|
|
11
12
|
const { placement = 'top', visible, onVisibleChange, middleware = { flip: true, shift: true }, autoUpdateOptions = {}, reference, ariaStrategy = 'description', id = uniqueId, ...props } = options;
|
|
12
13
|
const [open, onOpenChange] = useControlledState(false, visible, onVisibleChange);
|
|
14
|
+
const syncWithControlledState = React.useCallback((element) => {
|
|
15
|
+
// Using a microtask ensures that the popover is mounted before calling togglePopover
|
|
16
|
+
queueMicrotask(() => {
|
|
17
|
+
try {
|
|
18
|
+
element?.togglePopover?.(open);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// Fail silently, to avoid crashing the page
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}, [open]);
|
|
13
25
|
const floating = useFloating({
|
|
14
26
|
placement,
|
|
15
27
|
open,
|
|
@@ -92,19 +104,29 @@ const useTooltip = (options = {}) => {
|
|
|
92
104
|
const getReferenceProps = React.useCallback((userProps) => {
|
|
93
105
|
return interactions.getReferenceProps({ ...userProps, ...ariaProps });
|
|
94
106
|
}, [interactions, ariaProps]);
|
|
95
|
-
const floatingProps = React.useMemo(() =>
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
107
|
+
const floatingProps = React.useMemo(() => ({
|
|
108
|
+
...interactions.getFloatingProps({
|
|
109
|
+
hidden: !open,
|
|
110
|
+
'aria-hidden': 'true',
|
|
111
|
+
...props,
|
|
112
|
+
id,
|
|
113
|
+
}),
|
|
114
|
+
popover: 'manual',
|
|
100
115
|
}), [interactions, props, id, open]);
|
|
101
116
|
return React.useMemo(() => ({
|
|
102
117
|
getReferenceProps,
|
|
103
118
|
floatingProps,
|
|
104
119
|
...floating,
|
|
120
|
+
refs: {
|
|
121
|
+
...floating.refs,
|
|
122
|
+
setFloating: (element) => {
|
|
123
|
+
floating.refs.setFloating(element);
|
|
124
|
+
syncWithControlledState(element);
|
|
125
|
+
},
|
|
126
|
+
},
|
|
105
127
|
// styles are not relevant when tooltip is not open
|
|
106
128
|
floatingStyles: floating.context.open ? floating.floatingStyles : {},
|
|
107
|
-
}), [getReferenceProps, floatingProps, floating]);
|
|
129
|
+
}), [getReferenceProps, floatingProps, floating, syncWithControlledState]);
|
|
108
130
|
};
|
|
109
131
|
/**
|
|
110
132
|
* Basic tooltip component to display informative content when an element is hovered or focused.
|
|
@@ -1,28 +1,53 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { CommonProps } from '../../utils/index.js';
|
|
3
|
+
import { TreeNodeExpander } from './TreeNodeExpander.js';
|
|
3
4
|
type TreeNodeProps = {
|
|
4
5
|
/**
|
|
5
6
|
* Unique id of the node.
|
|
6
7
|
* It has to be compatible with HTML id attribute.
|
|
7
8
|
*/
|
|
8
9
|
nodeId: string;
|
|
10
|
+
/**
|
|
11
|
+
* Props for treeNode
|
|
12
|
+
*/
|
|
13
|
+
nodeProps?: React.ComponentProps<'div'>;
|
|
9
14
|
/**
|
|
10
15
|
* The main text displayed on the node.
|
|
11
16
|
*/
|
|
12
17
|
label: React.ReactNode;
|
|
18
|
+
/**
|
|
19
|
+
* Props for TreeNode label(affects both the main and sub label).
|
|
20
|
+
*/
|
|
21
|
+
labelProps?: React.ComponentProps<'div'>;
|
|
22
|
+
/**
|
|
23
|
+
* Props for the TreeNode's main label.
|
|
24
|
+
*/
|
|
25
|
+
titleProps?: React.ComponentProps<'div'>;
|
|
13
26
|
/**
|
|
14
27
|
* Small note displayed below main label.
|
|
15
28
|
*/
|
|
16
29
|
sublabel?: React.ReactNode;
|
|
30
|
+
/**
|
|
31
|
+
* Props for TreeNode sublabel
|
|
32
|
+
*/
|
|
33
|
+
sublabelProps?: React.ComponentProps<'div'>;
|
|
17
34
|
/**
|
|
18
35
|
* Icon shown before label and sublabel content.
|
|
19
36
|
*/
|
|
20
37
|
icon?: JSX.Element;
|
|
38
|
+
/**
|
|
39
|
+
* Props for TreeNode Icon
|
|
40
|
+
*/
|
|
41
|
+
iconProps?: React.ComponentProps<'span'>;
|
|
21
42
|
/**
|
|
22
43
|
* Flag whether the node has child sub-nodes. It is used to show expander icon.
|
|
23
44
|
* @default false
|
|
24
45
|
*/
|
|
25
46
|
hasSubNodes?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Props for subTree list(affects all subnodes of this node).
|
|
49
|
+
*/
|
|
50
|
+
subTreeProps?: React.ComponentProps<'ul'>;
|
|
26
51
|
/**
|
|
27
52
|
* Flag whether the node is disabled.
|
|
28
53
|
* @default false
|
|
@@ -54,10 +79,24 @@ type TreeNodeProps = {
|
|
|
54
79
|
* Recommended to use `Checkbox` component.
|
|
55
80
|
*/
|
|
56
81
|
checkbox?: React.ReactNode;
|
|
82
|
+
/**
|
|
83
|
+
* Props for TreeNode checkbox.
|
|
84
|
+
*/
|
|
85
|
+
checkboxProps?: React.ComponentProps<'div'>;
|
|
57
86
|
/**
|
|
58
87
|
* Custom expander element. If `hasSubNodes` is false, it won't be shown.
|
|
59
88
|
*/
|
|
60
89
|
expander?: React.ReactNode;
|
|
90
|
+
/**
|
|
91
|
+
* Props for the default TreeNodeExpander that is shown when there are sub nodes and no expander is given.
|
|
92
|
+
*/
|
|
93
|
+
expanderProps?: React.ComponentProps<typeof TreeNodeExpander>;
|
|
94
|
+
/**
|
|
95
|
+
* Props for content of the TreeNode.
|
|
96
|
+
* This affects all passed in children of the node, as well as the label, sublabel, icon, and expander.
|
|
97
|
+
* Note that this does not affect the checkbox.
|
|
98
|
+
*/
|
|
99
|
+
contentProps?: React.ComponentProps<'div'>;
|
|
61
100
|
/**
|
|
62
101
|
* Content shown after `TreeNode`.
|
|
63
102
|
*/
|
|
@@ -27,7 +27,7 @@ import { useTreeContext } from './TreeContext.js';
|
|
|
27
27
|
/>
|
|
28
28
|
*/
|
|
29
29
|
export const TreeNode = (props) => {
|
|
30
|
-
const { nodeId, label, sublabel, children, className, icon, hasSubNodes = false, isDisabled = false, isExpanded = false, isSelected = false, onSelected, onExpanded, checkbox, expander, ...rest } = props;
|
|
30
|
+
const { nodeId, nodeProps = {}, label, labelProps = {}, sublabel, sublabelProps = {}, children, className, icon, iconProps = {}, hasSubNodes = false, isDisabled = false, isExpanded = false, isSelected = false, onSelected, onExpanded, checkbox, checkboxProps = {}, subTreeProps = {}, contentProps = {}, titleProps = {}, expanderProps = {}, expander, ...rest } = props;
|
|
31
31
|
const { nodeDepth, subNodeIds = [], parentNodeId, scrollToParent, groupSize, indexInGroup, } = useTreeContext();
|
|
32
32
|
const [isFocused, setIsFocused] = React.useState(false);
|
|
33
33
|
const nodeRef = React.useRef(null);
|
|
@@ -107,22 +107,22 @@ export const TreeNode = (props) => {
|
|
|
107
107
|
}, onBlur: () => {
|
|
108
108
|
setIsFocused(false);
|
|
109
109
|
}, ref: nodeRef, onKeyDown: onKeyDown, ...rest },
|
|
110
|
-
React.createElement(Box, { className: cx('iui-tree-node', {
|
|
110
|
+
React.createElement(Box, { as: 'div', style: { '--level': nodeDepth }, onClick: () => !isDisabled && onSelected?.(nodeId, !isSelected), ...nodeProps, className: cx('iui-tree-node', {
|
|
111
111
|
'iui-active': isSelected,
|
|
112
112
|
'iui-disabled': isDisabled,
|
|
113
|
-
}
|
|
114
|
-
checkbox && (React.createElement(Box, { className: 'iui-tree-node-checkbox' }, React.isValidElement(checkbox)
|
|
113
|
+
}, nodeProps?.className) },
|
|
114
|
+
checkbox && (React.createElement(Box, { as: 'div', ...checkboxProps, className: cx('iui-tree-node-checkbox', checkboxProps?.className) }, React.isValidElement(checkbox)
|
|
115
115
|
? React.cloneElement(checkbox, {
|
|
116
116
|
tabIndex: isFocused ? 0 : -1,
|
|
117
117
|
})
|
|
118
118
|
: checkbox)),
|
|
119
|
-
React.createElement(Box, { className: 'iui-tree-node-content' },
|
|
119
|
+
React.createElement(Box, { as: 'div', ...contentProps, className: cx('iui-tree-node-content', contentProps?.className) },
|
|
120
120
|
hasSubNodes && expander,
|
|
121
|
-
hasSubNodes && !expander && (React.createElement(TreeNodeExpander, { isExpanded: isExpanded, disabled: isDisabled, onClick: onExpanderClick, tabIndex: isFocused ? 0 : -1 })),
|
|
122
|
-
icon && (React.createElement(Box, { as: 'span', className: 'iui-tree-node-content-icon',
|
|
123
|
-
React.createElement(Box, { className: 'iui-tree-node-content-label' },
|
|
124
|
-
React.createElement(Box, { className: 'iui-tree-node-content-title' }, label),
|
|
125
|
-
sublabel && (React.createElement(Box, { className: 'iui-tree-node-content-caption' }, sublabel))),
|
|
121
|
+
hasSubNodes && !expander && (React.createElement(TreeNodeExpander, { isExpanded: isExpanded, disabled: isDisabled, onClick: onExpanderClick, tabIndex: isFocused ? 0 : -1, ...expanderProps })),
|
|
122
|
+
icon && (React.createElement(Box, { as: 'span', "aria-hidden": true, ...iconProps, className: cx('iui-tree-node-content-icon', iconProps?.className) }, icon)),
|
|
123
|
+
React.createElement(Box, { as: 'div', ...labelProps, className: cx('iui-tree-node-content-label', labelProps?.className) },
|
|
124
|
+
React.createElement(Box, { as: 'div', ...titleProps, className: cx('iui-tree-node-content-title', titleProps?.className) }, label),
|
|
125
|
+
sublabel && (React.createElement(Box, { as: 'div', ...sublabelProps, className: cx('iui-tree-node-content-caption', sublabelProps?.className) }, sublabel))),
|
|
126
126
|
children)),
|
|
127
|
-
hasSubNodes && (React.createElement(Box, { as: 'ul',
|
|
127
|
+
hasSubNodes && (React.createElement(Box, { as: 'ul', role: 'group', "aria-owns": subNodeIds.join(' '), ...subTreeProps, className: cx('iui-sub-tree', subTreeProps?.className) }))));
|
|
128
128
|
};
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
1
2
|
import type { PolymorphicForwardRefComponent } from '../../utils/index.js';
|
|
2
3
|
import type { IconButtonProps } from '../Buttons/IconButton.js';
|
|
3
4
|
type TreeNodeExpanderProps = {
|
|
4
5
|
isExpanded?: boolean;
|
|
6
|
+
expanderIconProps?: React.ComponentProps<'svg'>;
|
|
5
7
|
} & IconButtonProps;
|
|
6
8
|
export declare const TreeNodeExpander: PolymorphicForwardRefComponent<"button", TreeNodeExpanderProps>;
|
|
7
9
|
export {};
|
|
@@ -8,11 +8,11 @@ import { SvgChevronRight, SvgChevronRightSmall } from '../../utils/index.js';
|
|
|
8
8
|
import { IconButton } from '../Buttons/IconButton.js';
|
|
9
9
|
import { TreeContext } from './TreeContext.js';
|
|
10
10
|
export const TreeNodeExpander = React.forwardRef((props, ref) => {
|
|
11
|
-
const { isExpanded, ...rest } = props;
|
|
11
|
+
const { isExpanded, expanderIconProps = {}, ...rest } = props;
|
|
12
12
|
const size = React.useContext(TreeContext)?.size ?? 'default';
|
|
13
13
|
const ChevronIcon = size === 'small' ? SvgChevronRightSmall : SvgChevronRight;
|
|
14
14
|
return (React.createElement(IconButton, { styleType: 'borderless', size: 'small', "aria-label": isExpanded ? 'Collapse' : 'Expand', ref: ref, ...rest },
|
|
15
|
-
React.createElement(ChevronIcon, { className: cx('iui-tree-node-content-expander-icon', {
|
|
15
|
+
React.createElement(ChevronIcon, { ...expanderIconProps, className: cx('iui-tree-node-content-expander-icon', expanderIconProps?.className, {
|
|
16
16
|
'iui-tree-node-content-expander-icon-expanded': isExpanded,
|
|
17
17
|
}) })));
|
|
18
18
|
});
|