@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
|
@@ -30,13 +30,17 @@ export type DialogContextProps = {
|
|
|
30
30
|
*/
|
|
31
31
|
closeOnEsc?: boolean;
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
33
|
+
* Prevents focus from leaving the dialog. This is useful when the dialog is modal.
|
|
34
|
+
*
|
|
35
|
+
* Setting this prop to `true` will also set `setFocus` to `true`.
|
|
36
|
+
*
|
|
34
37
|
* @default false
|
|
35
38
|
*/
|
|
36
39
|
trapFocus?: boolean;
|
|
37
40
|
/**
|
|
38
41
|
* If true, focuses the dialog.
|
|
39
|
-
*
|
|
42
|
+
*
|
|
43
|
+
* Defaults to `true` if `trapFocus` is set to `true`, otherwise defaults to `false`.
|
|
40
44
|
*/
|
|
41
45
|
setFocus?: boolean;
|
|
42
46
|
/**
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { PolymorphicForwardRefComponent } from '../../utils/index.js';
|
|
3
|
+
import { Text } from '../Typography/Text.js';
|
|
4
|
+
import type { FocusEntry, PanelsInstance, TriggerMapEntry } from './helpers.js';
|
|
5
|
+
type PanelsWrapperProps = {
|
|
6
|
+
/**
|
|
7
|
+
* Function that gets called when the active panel is changed.
|
|
8
|
+
*/
|
|
9
|
+
onActiveIdChange?: (newActiveId: string) => void;
|
|
10
|
+
children: React.ReactNode;
|
|
11
|
+
/**
|
|
12
|
+
* Pass an instance created by `useInstance` to control the panels imperatively.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* const panels = Panels.useInstance();
|
|
16
|
+
* <Panels instance={panels} />
|
|
17
|
+
*/
|
|
18
|
+
instance?: PanelsInstance;
|
|
19
|
+
};
|
|
20
|
+
export declare const PanelsWrapper: PolymorphicForwardRefComponent<"div", PanelsWrapperProps>;
|
|
21
|
+
export declare const PanelsWrapperContext: React.Context<{
|
|
22
|
+
activePanelId: string | undefined;
|
|
23
|
+
setActivePanelId: React.Dispatch<React.SetStateAction<string>>;
|
|
24
|
+
/**
|
|
25
|
+
* Simpler alternative to a full history stack.
|
|
26
|
+
*
|
|
27
|
+
* ```
|
|
28
|
+
* Record<
|
|
29
|
+
* string, // Id of a panel
|
|
30
|
+
* {
|
|
31
|
+
* triggerId: string, // Id of the trigger element that points to this panel
|
|
32
|
+
* panelId: string, // Id of the panel element in which the trigger is present
|
|
33
|
+
* }
|
|
34
|
+
* >
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
triggers: Record<string, TriggerMapEntry>;
|
|
38
|
+
setTriggers: React.Dispatch<React.SetStateAction<Record<string, TriggerMapEntry>>>;
|
|
39
|
+
changeActivePanel: (newActiveId: string) => void;
|
|
40
|
+
shouldFocus: FocusEntry;
|
|
41
|
+
setShouldFocus: React.Dispatch<React.SetStateAction<FocusEntry>>;
|
|
42
|
+
panels: React.MutableRefObject<Set<string>>;
|
|
43
|
+
} | undefined>;
|
|
44
|
+
type PanelProps = {
|
|
45
|
+
id: string;
|
|
46
|
+
};
|
|
47
|
+
type PanelTriggerProps = {
|
|
48
|
+
for: string;
|
|
49
|
+
children: React.ReactElement;
|
|
50
|
+
};
|
|
51
|
+
type PanelHeaderProps = {
|
|
52
|
+
titleProps?: React.ComponentProps<typeof Text>;
|
|
53
|
+
};
|
|
54
|
+
export declare const Panels: {
|
|
55
|
+
/**
|
|
56
|
+
* Component that manages the logic for layered panels.
|
|
57
|
+
* It can be used anywhere to create layers. E.g. `Menu`, `InformationPanel`, `Popover`, etc.
|
|
58
|
+
*
|
|
59
|
+
* Requirements:
|
|
60
|
+
* - The initial displayed Panel should be the first `Panel` in the `Panels.Wrapper`.
|
|
61
|
+
* - A panel can have only one trigger pointing to it. i.e. out of all the triggers across all panels,
|
|
62
|
+
* only one can point to a particular panel.
|
|
63
|
+
* - The `Panels.Panel`s within the wrapper should be in the order of the navigation. E.g.:
|
|
64
|
+
* ```jsx
|
|
65
|
+
* <Panels.Wrapper>
|
|
66
|
+
* <Panels.Panel id={root} /> // Must come before moreDetails since it contains the trigger to moreDetails
|
|
67
|
+
* <Panels.Panel id={moreDetails}> // Must come after root since it is navigated to from root
|
|
68
|
+
* </Panels.Wrapper>
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* <Panels.Wrapper as={Surface}>
|
|
73
|
+
* <Panels.Panel
|
|
74
|
+
* id={panelIdRoot}
|
|
75
|
+
* as={Surface}
|
|
76
|
+
* border={false}
|
|
77
|
+
* elevation={0}
|
|
78
|
+
* >
|
|
79
|
+
* <Surface.Header as={Panels.Header}>Root</Surface.Header>
|
|
80
|
+
* <Surface.Body as={List}>
|
|
81
|
+
* <ListItem>
|
|
82
|
+
* <Panels.Trigger for={panelIdMoreInfo}>
|
|
83
|
+
* <ListItem.Action>More details</ListItem.Action>
|
|
84
|
+
* </Panels.Trigger>
|
|
85
|
+
* </ListItem>
|
|
86
|
+
* </Surface.Body>
|
|
87
|
+
* </Panels.Panel>
|
|
88
|
+
*
|
|
89
|
+
* <Panels.Panel
|
|
90
|
+
* id={panelIdMoreInfo}
|
|
91
|
+
* as={Surface}
|
|
92
|
+
* border={false}
|
|
93
|
+
* elevation={0}
|
|
94
|
+
* >
|
|
95
|
+
* <Surface.Header as={Panels.Header}>More details</Surface.Header>
|
|
96
|
+
* <Surface.Body isPadded>
|
|
97
|
+
* <Text>Content</Text>
|
|
98
|
+
* </Surface.Body>
|
|
99
|
+
* </Panels.Panel>
|
|
100
|
+
* </Panels.Wrapper>
|
|
101
|
+
*/
|
|
102
|
+
Wrapper: PolymorphicForwardRefComponent<"div", PanelsWrapperProps>;
|
|
103
|
+
/**
|
|
104
|
+
* Takes an `id` and the panel content.
|
|
105
|
+
* Match this `id` with a `Panels.Triggers`'s `for` prop to create a link between them.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* <Panels.Panel id={panelIdRoot} as={Surface} border={false} elevation={0}>
|
|
109
|
+
* <Surface.Header as={Panels.Header}>Root</Surface.Header>
|
|
110
|
+
* <Surface.Body as={List}>
|
|
111
|
+
* <ListItem>
|
|
112
|
+
* <Panels.Trigger for={panelIdMoreInfo}>
|
|
113
|
+
* <ListItem.Action>More details</ListItem.Action>
|
|
114
|
+
* </Panels.Trigger>
|
|
115
|
+
* </ListItem>
|
|
116
|
+
* </Surface.Body>
|
|
117
|
+
* </Panels.Panel>
|
|
118
|
+
*/
|
|
119
|
+
Panel: PolymorphicForwardRefComponent<"div", PanelProps>;
|
|
120
|
+
/**
|
|
121
|
+
* Wraps the clickable element and appends an `onClick` to change the active panel to the one specified in the `for`
|
|
122
|
+
* prop. Also appends some attributes for accessibility.
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* <Panels.Trigger for={nextPanelId}>
|
|
126
|
+
* <Button>go to next panel</Button>
|
|
127
|
+
* </Panels.Trigger>
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* <ListItem>
|
|
131
|
+
* <Panels.Trigger for={panelIdMoreInfo}>
|
|
132
|
+
* <ListItem.Action>More details</ListItem.Action>
|
|
133
|
+
* </Panels.Trigger>
|
|
134
|
+
* </ListItem>
|
|
135
|
+
*/
|
|
136
|
+
Trigger: {
|
|
137
|
+
(props: PanelTriggerProps): string | number | true | React.ReactElement<any, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null;
|
|
138
|
+
displayName: string;
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* Required component to add an accessible name and also a back button (if previous panel exists) to the panel.
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* <Panels.Panel id={panelIdRoot}>
|
|
145
|
+
* <Panels.Header>Root</Panels.Header>
|
|
146
|
+
* …
|
|
147
|
+
* </Panels.Panel>
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* <Panels.Panel
|
|
151
|
+
* id={panelIdMoreInfo}
|
|
152
|
+
* as={Surface}
|
|
153
|
+
* border={false}
|
|
154
|
+
* elevation={0}
|
|
155
|
+
* >
|
|
156
|
+
* <Surface.Header as={Panels.Header}>More details</Surface.Header>
|
|
157
|
+
* <Surface.Body isPadded>
|
|
158
|
+
* <Text>Content</Text>
|
|
159
|
+
* </Surface.Body>
|
|
160
|
+
* </Panels.Panel>
|
|
161
|
+
*/
|
|
162
|
+
Header: PolymorphicForwardRefComponent<"div", PanelHeaderProps>;
|
|
163
|
+
/**
|
|
164
|
+
* You can use methods from `Panels.useInstance()` to control the state programmatically.
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* const panels = Panels.useInstance();
|
|
168
|
+
*
|
|
169
|
+
* <Button onClick={() => panels.goBack()}>Go back</Button>
|
|
170
|
+
* <Panels.Wrapper instance={panels}>{…}</Panels.Wrapper>;
|
|
171
|
+
*/
|
|
172
|
+
useInstance: () => PanelsInstance;
|
|
173
|
+
};
|
|
174
|
+
export {};
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as ReactDOM from 'react-dom';
|
|
3
|
+
import {
|
|
4
|
+
Box,
|
|
5
|
+
cloneElementWithRef,
|
|
6
|
+
mergeEventHandlers,
|
|
7
|
+
SvgChevronLeft,
|
|
8
|
+
useInstance,
|
|
9
|
+
useMergedRefs,
|
|
10
|
+
useSafeContext,
|
|
11
|
+
useMediaQuery,
|
|
12
|
+
useWarningLogger,
|
|
13
|
+
useLayoutEffect,
|
|
14
|
+
useLatestRef,
|
|
15
|
+
} from '../../utils/index.js';
|
|
16
|
+
import { IconButton } from '../Buttons/IconButton.js';
|
|
17
|
+
import { Flex } from '../Flex/Flex.js';
|
|
18
|
+
import { Text } from '../Typography/Text.js';
|
|
19
|
+
import cx from 'classnames';
|
|
20
|
+
import { PanelsInstanceContext, PanelsInstanceProvider } from './helpers.js';
|
|
21
|
+
export const PanelsWrapper = React.forwardRef((props, forwardedRef) => {
|
|
22
|
+
let {
|
|
23
|
+
children,
|
|
24
|
+
className,
|
|
25
|
+
onActiveIdChange: onActiveIdChangeProp,
|
|
26
|
+
instance,
|
|
27
|
+
...rest
|
|
28
|
+
} = props;
|
|
29
|
+
let onActiveIdChange = useLatestRef(onActiveIdChangeProp);
|
|
30
|
+
let ref = React.useRef(null);
|
|
31
|
+
let [activePanelId, setActivePanelId] = React.useState(void 0);
|
|
32
|
+
let [triggers, setTriggers] = React.useState({});
|
|
33
|
+
let panels = React.useRef(new Set());
|
|
34
|
+
let [shouldFocus, setShouldFocus] = React.useState(void 0);
|
|
35
|
+
let motionOk = useMediaQuery('(prefers-reduced-motion: no-preference)');
|
|
36
|
+
let changeActivePanel = React.useCallback(
|
|
37
|
+
(newActiveId) => {
|
|
38
|
+
if (!panels.current.has(newActiveId) || newActiveId === activePanelId)
|
|
39
|
+
return;
|
|
40
|
+
ReactDOM.flushSync(() => setActivePanelId(newActiveId));
|
|
41
|
+
onActiveIdChange.current?.(newActiveId);
|
|
42
|
+
ref.current?.ownerDocument.getElementById(newActiveId)?.scrollIntoView({
|
|
43
|
+
block: 'nearest',
|
|
44
|
+
inline: 'center',
|
|
45
|
+
behavior: motionOk ? 'smooth' : 'instant',
|
|
46
|
+
});
|
|
47
|
+
},
|
|
48
|
+
[activePanelId, motionOk, onActiveIdChange],
|
|
49
|
+
);
|
|
50
|
+
return React.createElement(
|
|
51
|
+
PanelsWrapperContext.Provider,
|
|
52
|
+
{
|
|
53
|
+
value: React.useMemo(
|
|
54
|
+
() => ({
|
|
55
|
+
activePanelId,
|
|
56
|
+
setActivePanelId,
|
|
57
|
+
changeActivePanel,
|
|
58
|
+
triggers,
|
|
59
|
+
setTriggers,
|
|
60
|
+
shouldFocus,
|
|
61
|
+
setShouldFocus,
|
|
62
|
+
panels,
|
|
63
|
+
}),
|
|
64
|
+
[
|
|
65
|
+
activePanelId,
|
|
66
|
+
changeActivePanel,
|
|
67
|
+
setActivePanelId,
|
|
68
|
+
setTriggers,
|
|
69
|
+
shouldFocus,
|
|
70
|
+
triggers,
|
|
71
|
+
],
|
|
72
|
+
),
|
|
73
|
+
},
|
|
74
|
+
React.createElement(
|
|
75
|
+
PanelsInstanceProvider,
|
|
76
|
+
{
|
|
77
|
+
instance: instance,
|
|
78
|
+
},
|
|
79
|
+
React.createElement(
|
|
80
|
+
Box,
|
|
81
|
+
{
|
|
82
|
+
ref: useMergedRefs(ref, forwardedRef),
|
|
83
|
+
...rest,
|
|
84
|
+
className: cx('iui-panel-wrapper', className),
|
|
85
|
+
},
|
|
86
|
+
children,
|
|
87
|
+
),
|
|
88
|
+
),
|
|
89
|
+
);
|
|
90
|
+
});
|
|
91
|
+
export const PanelsWrapperContext = React.createContext(void 0);
|
|
92
|
+
let Panel = React.forwardRef((props, forwardedRef) => {
|
|
93
|
+
let { id, children, className, ...rest } = props;
|
|
94
|
+
let { activePanelId, triggers, panels, setActivePanelId } =
|
|
95
|
+
useSafeContext(PanelsWrapperContext);
|
|
96
|
+
let associatedTrigger = React.useMemo(() => triggers[id], [id, triggers]);
|
|
97
|
+
let previousActivePanelId = useDelayed(activePanelId) || activePanelId;
|
|
98
|
+
let isMounted = [activePanelId, previousActivePanelId].includes(id);
|
|
99
|
+
let isTransitioning =
|
|
100
|
+
activePanelId === id && activePanelId !== previousActivePanelId;
|
|
101
|
+
let isInert = previousActivePanelId === id && activePanelId !== id;
|
|
102
|
+
useLayoutEffect(() => {
|
|
103
|
+
let isFirstPanel = null == activePanelId && 0 === panels.current.size;
|
|
104
|
+
if (isFirstPanel) setActivePanelId(id);
|
|
105
|
+
let panelsCurrent = panels.current;
|
|
106
|
+
if (!panelsCurrent.has(id)) panelsCurrent.add(id);
|
|
107
|
+
return () => {
|
|
108
|
+
panelsCurrent.delete(id);
|
|
109
|
+
};
|
|
110
|
+
}, [activePanelId, id, panels, setActivePanelId]);
|
|
111
|
+
return React.createElement(
|
|
112
|
+
PanelContext.Provider,
|
|
113
|
+
{
|
|
114
|
+
value: React.useMemo(
|
|
115
|
+
() => ({
|
|
116
|
+
id,
|
|
117
|
+
associatedTrigger,
|
|
118
|
+
}),
|
|
119
|
+
[associatedTrigger, id],
|
|
120
|
+
),
|
|
121
|
+
},
|
|
122
|
+
isMounted &&
|
|
123
|
+
React.createElement(
|
|
124
|
+
Box,
|
|
125
|
+
{
|
|
126
|
+
ref: forwardedRef,
|
|
127
|
+
id: id,
|
|
128
|
+
className: cx('iui-panel', className),
|
|
129
|
+
'aria-labelledby': `${id}-header-title`,
|
|
130
|
+
role: 'group',
|
|
131
|
+
inert: isInert ? '' : void 0,
|
|
132
|
+
'data-iui-transitioning': isTransitioning ? 'true' : void 0,
|
|
133
|
+
...rest,
|
|
134
|
+
},
|
|
135
|
+
children,
|
|
136
|
+
),
|
|
137
|
+
);
|
|
138
|
+
});
|
|
139
|
+
let PanelContext = React.createContext(void 0);
|
|
140
|
+
let PanelTrigger = (props) => {
|
|
141
|
+
let { children, for: forProp } = props;
|
|
142
|
+
let {
|
|
143
|
+
changeActivePanel,
|
|
144
|
+
triggers,
|
|
145
|
+
setTriggers,
|
|
146
|
+
activePanelId: activePanel,
|
|
147
|
+
shouldFocus,
|
|
148
|
+
setShouldFocus,
|
|
149
|
+
panels,
|
|
150
|
+
} = useSafeContext(PanelsWrapperContext);
|
|
151
|
+
let { id: panelId } = useSafeContext(PanelContext);
|
|
152
|
+
let fallbackId = React.useId();
|
|
153
|
+
let triggerId = children.props.id || fallbackId;
|
|
154
|
+
let onClick = React.useCallback(() => {
|
|
155
|
+
if (null == activePanel) return;
|
|
156
|
+
setShouldFocus({
|
|
157
|
+
fromPanelId: activePanel,
|
|
158
|
+
toPanelId: forProp,
|
|
159
|
+
direction: 'forward',
|
|
160
|
+
});
|
|
161
|
+
changeActivePanel?.(forProp);
|
|
162
|
+
}, [activePanel, changeActivePanel, forProp, setShouldFocus]);
|
|
163
|
+
let focusRef = React.useCallback(
|
|
164
|
+
(el) => {
|
|
165
|
+
if (
|
|
166
|
+
shouldFocus?.direction === 'backward' &&
|
|
167
|
+
shouldFocus?.toPanelId === panelId &&
|
|
168
|
+
shouldFocus?.fromPanelId === forProp
|
|
169
|
+
) {
|
|
170
|
+
el?.focus({
|
|
171
|
+
preventScroll: true,
|
|
172
|
+
});
|
|
173
|
+
setShouldFocus(void 0);
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
[forProp, panelId, setShouldFocus, shouldFocus],
|
|
177
|
+
);
|
|
178
|
+
let logWarning = useWarningLogger();
|
|
179
|
+
React.useEffect(() => {
|
|
180
|
+
if (!panels.current.has(forProp))
|
|
181
|
+
logWarning(
|
|
182
|
+
`Panels.Trigger's \`for\` prop ("${forProp}") corresponds to no Panel.`,
|
|
183
|
+
);
|
|
184
|
+
}, [forProp, logWarning, panels, triggers]);
|
|
185
|
+
React.useEffect(() => {
|
|
186
|
+
setTriggers((oldTriggers) => {
|
|
187
|
+
let triggersMatch = oldTriggers[forProp];
|
|
188
|
+
if (
|
|
189
|
+
null == triggersMatch ||
|
|
190
|
+
panelId !== triggersMatch.panelId ||
|
|
191
|
+
triggerId !== triggersMatch.triggerId
|
|
192
|
+
)
|
|
193
|
+
return {
|
|
194
|
+
...oldTriggers,
|
|
195
|
+
[forProp]: {
|
|
196
|
+
panelId,
|
|
197
|
+
triggerId,
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
return oldTriggers;
|
|
201
|
+
});
|
|
202
|
+
}, [forProp, panelId, setTriggers, triggerId]);
|
|
203
|
+
return cloneElementWithRef(children, (children) => ({
|
|
204
|
+
...children.props,
|
|
205
|
+
id: triggerId,
|
|
206
|
+
ref: focusRef,
|
|
207
|
+
onClick: mergeEventHandlers(children.props.onClick, onClick),
|
|
208
|
+
'aria-expanded': activePanel === forProp,
|
|
209
|
+
'aria-controls': forProp,
|
|
210
|
+
}));
|
|
211
|
+
};
|
|
212
|
+
let PanelHeader = React.forwardRef((props, forwardedRef) => {
|
|
213
|
+
let { titleProps, children, ...rest } = props;
|
|
214
|
+
let { shouldFocus, setShouldFocus } = useSafeContext(PanelsWrapperContext);
|
|
215
|
+
let { id: panelId, associatedTrigger: panelAssociatedTrigger } =
|
|
216
|
+
useSafeContext(PanelContext);
|
|
217
|
+
let focusRef = React.useCallback(
|
|
218
|
+
(el) => {
|
|
219
|
+
if (
|
|
220
|
+
shouldFocus?.direction === 'forward' &&
|
|
221
|
+
shouldFocus.toPanelId === panelId
|
|
222
|
+
) {
|
|
223
|
+
el?.focus({
|
|
224
|
+
preventScroll: true,
|
|
225
|
+
});
|
|
226
|
+
setShouldFocus(void 0);
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
[panelId, setShouldFocus, shouldFocus?.direction, shouldFocus?.toPanelId],
|
|
230
|
+
);
|
|
231
|
+
return React.createElement(
|
|
232
|
+
Flex,
|
|
233
|
+
{
|
|
234
|
+
ref: forwardedRef,
|
|
235
|
+
...rest,
|
|
236
|
+
},
|
|
237
|
+
panelAssociatedTrigger && React.createElement(PanelBackButton, null),
|
|
238
|
+
React.createElement(
|
|
239
|
+
Text,
|
|
240
|
+
{
|
|
241
|
+
id: `${panelId}-header-title`,
|
|
242
|
+
as: 'h2',
|
|
243
|
+
tabIndex: -1,
|
|
244
|
+
ref: focusRef,
|
|
245
|
+
...titleProps,
|
|
246
|
+
},
|
|
247
|
+
children,
|
|
248
|
+
),
|
|
249
|
+
);
|
|
250
|
+
});
|
|
251
|
+
let PanelBackButton = React.forwardRef((props, forwardedRef) => {
|
|
252
|
+
let { children, onClick, ...rest } = props;
|
|
253
|
+
let { instance: panelInstance } = useSafeContext(PanelsInstanceContext);
|
|
254
|
+
return React.createElement(
|
|
255
|
+
IconButton,
|
|
256
|
+
{
|
|
257
|
+
ref: forwardedRef,
|
|
258
|
+
'aria-label': 'Previous panel',
|
|
259
|
+
styleType: 'borderless',
|
|
260
|
+
size: 'small',
|
|
261
|
+
'data-iui-shift': 'left',
|
|
262
|
+
...rest,
|
|
263
|
+
onClick: mergeEventHandlers(
|
|
264
|
+
React.useCallback(() => panelInstance?.goBack(), [panelInstance]),
|
|
265
|
+
onClick,
|
|
266
|
+
),
|
|
267
|
+
},
|
|
268
|
+
children || React.createElement(SvgChevronLeft, null),
|
|
269
|
+
);
|
|
270
|
+
});
|
|
271
|
+
export const Panels = {
|
|
272
|
+
Wrapper: PanelsWrapper,
|
|
273
|
+
Panel,
|
|
274
|
+
Trigger: PanelTrigger,
|
|
275
|
+
Header: PanelHeader,
|
|
276
|
+
useInstance: useInstance,
|
|
277
|
+
};
|
|
278
|
+
function useDelayed(
|
|
279
|
+
value,
|
|
280
|
+
{ delay } = {
|
|
281
|
+
delay: 500,
|
|
282
|
+
},
|
|
283
|
+
) {
|
|
284
|
+
let [delayed, setDelayed] = React.useState(void 0);
|
|
285
|
+
let timeout = React.useRef(void 0);
|
|
286
|
+
React.useEffect(() => {
|
|
287
|
+
if (0 === delay) setDelayed(value);
|
|
288
|
+
else timeout.current = setTimeout(() => setDelayed(value), delay);
|
|
289
|
+
return () => {
|
|
290
|
+
clearTimeout(timeout.current);
|
|
291
|
+
};
|
|
292
|
+
}, [value, delay]);
|
|
293
|
+
return delayed;
|
|
294
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export type PanelsInstance = {
|
|
3
|
+
/** Go back to the panel that has a trigger that points to the current panel. */
|
|
4
|
+
goBack: () => void;
|
|
5
|
+
};
|
|
6
|
+
export type TriggerMapEntry = {
|
|
7
|
+
triggerId: string;
|
|
8
|
+
panelId: string;
|
|
9
|
+
};
|
|
10
|
+
export type FocusEntry = {
|
|
11
|
+
fromPanelId: string;
|
|
12
|
+
toPanelId: string;
|
|
13
|
+
direction: 'forward' | 'backward';
|
|
14
|
+
} | undefined;
|
|
15
|
+
export declare const PanelsInstanceContext: React.Context<{
|
|
16
|
+
instance: PanelsInstance;
|
|
17
|
+
} | undefined>;
|
|
18
|
+
type PanelInstanceProviderProps = {
|
|
19
|
+
children: React.ReactNode;
|
|
20
|
+
instance: PanelsInstance | undefined;
|
|
21
|
+
};
|
|
22
|
+
export declare const PanelsInstanceProvider: (props: PanelInstanceProviderProps) => React.JSX.Element;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useSafeContext, useSynchronizeInstance } from '../../utils/index.js';
|
|
3
|
+
import { Panels, PanelsWrapperContext } from './Panels.js';
|
|
4
|
+
export const PanelsInstanceContext = React.createContext(void 0);
|
|
5
|
+
export const PanelsInstanceProvider = (props) => {
|
|
6
|
+
let { children, instance: instanceProp } = props;
|
|
7
|
+
let instanceBackup = Panels.useInstance();
|
|
8
|
+
let instance = instanceProp || instanceBackup;
|
|
9
|
+
let { activePanelId, changeActivePanel, triggers, setShouldFocus } =
|
|
10
|
+
useSafeContext(PanelsWrapperContext);
|
|
11
|
+
let goBack = React.useCallback(async () => {
|
|
12
|
+
if (null == activePanelId) return;
|
|
13
|
+
let trigger = triggers[activePanelId];
|
|
14
|
+
if (null != trigger.triggerId) {
|
|
15
|
+
setShouldFocus({
|
|
16
|
+
fromPanelId: activePanelId,
|
|
17
|
+
toPanelId: trigger.panelId,
|
|
18
|
+
direction: 'backward',
|
|
19
|
+
});
|
|
20
|
+
changeActivePanel(trigger.panelId);
|
|
21
|
+
}
|
|
22
|
+
}, [activePanelId, changeActivePanel, setShouldFocus, triggers]);
|
|
23
|
+
useSynchronizeInstance(
|
|
24
|
+
instance,
|
|
25
|
+
React.useMemo(
|
|
26
|
+
() => ({
|
|
27
|
+
goBack,
|
|
28
|
+
}),
|
|
29
|
+
[goBack],
|
|
30
|
+
),
|
|
31
|
+
);
|
|
32
|
+
return React.createElement(
|
|
33
|
+
PanelsInstanceContext.Provider,
|
|
34
|
+
{
|
|
35
|
+
value: {
|
|
36
|
+
instance,
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
children,
|
|
40
|
+
);
|
|
41
|
+
};
|
package/esm/core/Radio/Radio.js
CHANGED
|
@@ -16,7 +16,7 @@ export const Radio = React.forwardRef((props, ref) => {
|
|
|
16
16
|
let refs = useMergedRefs(inputElementRef, ref);
|
|
17
17
|
let radio = React.createElement(Box, {
|
|
18
18
|
as: 'input',
|
|
19
|
-
className: cx('iui-radio', className),
|
|
19
|
+
className: cx('iui-checkbox', 'iui-radio', className),
|
|
20
20
|
style: style,
|
|
21
21
|
disabled: disabled,
|
|
22
22
|
type: 'radio',
|
|
@@ -29,14 +29,9 @@ export const Radio = React.forwardRef((props, ref) => {
|
|
|
29
29
|
{
|
|
30
30
|
as: 'label',
|
|
31
31
|
...wrapperProps,
|
|
32
|
-
className: cx(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
'iui-disabled': disabled,
|
|
36
|
-
[`iui-${status}`]: !!status,
|
|
37
|
-
},
|
|
38
|
-
wrapperProps?.className,
|
|
39
|
-
),
|
|
32
|
+
className: cx('iui-checkbox-wrapper', wrapperProps?.className),
|
|
33
|
+
'data-iui-status': status,
|
|
34
|
+
'data-iui-disabled': disabled ? 'true' : void 0,
|
|
40
35
|
},
|
|
41
36
|
radio,
|
|
42
37
|
label &&
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { InputGroup } from '../InputGroup/InputGroup.js';
|
|
3
3
|
import type { PolymorphicForwardRefComponent } from '../../utils/index.js';
|
|
4
|
-
type RadioTileGroupProps =
|
|
4
|
+
type RadioTileGroupProps = {
|
|
5
|
+
tileContainerProps?: React.ComponentProps<'div'>;
|
|
6
|
+
} & Omit<React.ComponentProps<typeof InputGroup>, 'displayStyle' | 'disabled'>;
|
|
5
7
|
/**
|
|
6
8
|
* RadioTileGroup component to group RadioTile components together
|
|
7
9
|
* @example
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { InputGroup } from '../InputGroup/InputGroup.js';
|
|
3
3
|
import { Box } from '../../utils/index.js';
|
|
4
|
+
import cx from 'classnames';
|
|
4
5
|
export const RadioTileGroup = React.forwardRef((props, forwardedRef) => {
|
|
5
|
-
let { children, label, ...rest } = props;
|
|
6
|
+
let { children, label, tileContainerProps, ...rest } = props;
|
|
6
7
|
return React.createElement(
|
|
7
8
|
InputGroup,
|
|
8
9
|
{
|
|
@@ -13,7 +14,12 @@ export const RadioTileGroup = React.forwardRef((props, forwardedRef) => {
|
|
|
13
14
|
React.createElement(
|
|
14
15
|
Box,
|
|
15
16
|
{
|
|
16
|
-
|
|
17
|
+
as: 'div',
|
|
18
|
+
...tileContainerProps,
|
|
19
|
+
className: cx(
|
|
20
|
+
'iui-radio-tile-container',
|
|
21
|
+
tileContainerProps?.className,
|
|
22
|
+
),
|
|
17
23
|
},
|
|
18
24
|
children,
|
|
19
25
|
),
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Tag } from '../Tag/Tag.js';
|
|
1
3
|
import type { PolymorphicForwardRefComponent } from '../../utils/index.js';
|
|
2
4
|
type SelectTagProps = {
|
|
3
5
|
/**
|
|
4
6
|
* Text inside the tag.
|
|
5
7
|
*/
|
|
6
8
|
label: string;
|
|
7
|
-
}
|
|
9
|
+
} & Pick<React.ComponentProps<typeof Tag>, 'onClick' | 'onRemove'>;
|
|
8
10
|
/**
|
|
9
11
|
* Tag for showing selected value in `Select`.
|
|
10
12
|
* @private
|
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
import cx from 'classnames';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { Tag } from '../Tag/Tag.js';
|
|
4
4
|
export const SelectTag = React.forwardRef((props, forwardedRef) => {
|
|
5
5
|
let { className, label, ...rest } = props;
|
|
6
6
|
return React.createElement(
|
|
7
|
-
|
|
7
|
+
Tag,
|
|
8
8
|
{
|
|
9
|
-
as: 'span',
|
|
10
9
|
className: cx('iui-select-tag', className),
|
|
10
|
+
labelProps: {
|
|
11
|
+
className: 'iui-select-tag-label',
|
|
12
|
+
},
|
|
13
|
+
removeButtonProps: {
|
|
14
|
+
className: 'iui-select-tag-button',
|
|
15
|
+
},
|
|
11
16
|
ref: forwardedRef,
|
|
12
17
|
...rest,
|
|
13
18
|
},
|
|
14
|
-
|
|
15
|
-
Box,
|
|
16
|
-
{
|
|
17
|
-
as: 'span',
|
|
18
|
-
className: 'iui-select-tag-label',
|
|
19
|
-
},
|
|
20
|
-
label,
|
|
21
|
-
),
|
|
19
|
+
label,
|
|
22
20
|
);
|
|
23
21
|
});
|
|
@@ -2,7 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
import cx from 'classnames';
|
|
3
3
|
import { SelectTag } from './SelectTag.js';
|
|
4
4
|
import { OverflowContainer } from '../../utils/index.js';
|
|
5
|
-
export const SelectTagContainer = React.forwardRef((props,
|
|
5
|
+
export const SelectTagContainer = React.forwardRef((props, forwardedRef) => {
|
|
6
6
|
let { tags: tagsProp, className, ...rest } = props;
|
|
7
7
|
let tags = React.useMemo(() => React.Children.toArray(tagsProp), [tagsProp]);
|
|
8
8
|
return React.createElement(
|
|
@@ -10,7 +10,7 @@ export const SelectTagContainer = React.forwardRef((props, ref) => {
|
|
|
10
10
|
{
|
|
11
11
|
itemsCount: tags.length,
|
|
12
12
|
className: cx('iui-select-tag-container', className),
|
|
13
|
-
ref:
|
|
13
|
+
ref: forwardedRef,
|
|
14
14
|
...rest,
|
|
15
15
|
},
|
|
16
16
|
React.createElement(SelectTagContainerContent, {
|
|
@@ -12,6 +12,10 @@ export type StepProperties = {
|
|
|
12
12
|
* A tooltip giving detailed description to this step.
|
|
13
13
|
*/
|
|
14
14
|
description?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Custom content displayed in the step's circle.
|
|
17
|
+
*/
|
|
18
|
+
stepContent?: () => React.ReactNode;
|
|
15
19
|
} & React.ComponentProps<'li'>;
|
|
16
20
|
export type StepperProps = {
|
|
17
21
|
/**
|