@itwin/itwinui-react 3.0.0-dev.7 → 3.0.0-dev.9

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.
Files changed (215) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/cjs/core/Alert/Alert.d.ts +20 -9
  3. package/cjs/core/Alert/Alert.js +48 -10
  4. package/cjs/core/ButtonGroup/ButtonGroup.js +41 -36
  5. package/cjs/core/Buttons/DropdownButton/DropdownButton.js +7 -19
  6. package/cjs/core/Buttons/IconButton/IconButton.js +27 -44
  7. package/cjs/core/Buttons/SplitButton/SplitButton.d.ts +4 -4
  8. package/cjs/core/Buttons/SplitButton/SplitButton.js +54 -29
  9. package/cjs/core/ColorPicker/ColorInputPanel.js +172 -231
  10. package/cjs/core/ComboBox/ComboBox.d.ts +2 -2
  11. package/cjs/core/ComboBox/ComboBox.js +33 -25
  12. package/cjs/core/ComboBox/ComboBoxEndIcon.js +3 -22
  13. package/cjs/core/ComboBox/ComboBoxInput.js +29 -21
  14. package/cjs/core/ComboBox/ComboBoxMenu.d.ts +2 -2
  15. package/cjs/core/ComboBox/ComboBoxMenu.js +73 -93
  16. package/cjs/core/ComboBox/ComboBoxMenuItem.d.ts +1 -1
  17. package/cjs/core/ComboBox/ComboBoxMenuItem.js +8 -6
  18. package/cjs/core/ComboBox/helpers.d.ts +5 -3
  19. package/cjs/core/DatePicker/DatePicker.d.ts +30 -8
  20. package/cjs/core/DatePicker/DatePicker.js +40 -5
  21. package/cjs/core/Dialog/Dialog.js +10 -16
  22. package/cjs/core/Dialog/DialogContext.d.ts +3 -4
  23. package/cjs/core/DropdownMenu/DropdownMenu.d.ts +6 -5
  24. package/cjs/core/DropdownMenu/DropdownMenu.js +59 -55
  25. package/cjs/core/ExpandableBlock/ExpandableBlock.d.ts +20 -14
  26. package/cjs/core/ExpandableBlock/ExpandableBlock.js +38 -15
  27. package/cjs/core/Header/HeaderDropdownButton.js +1 -2
  28. package/cjs/core/Header/HeaderSplitButton.js +2 -2
  29. package/cjs/core/Input/Input.d.ts +4 -0
  30. package/cjs/core/Input/Input.js +2 -1
  31. package/cjs/core/InputGrid/InputGrid.d.ts +25 -0
  32. package/cjs/core/InputGrid/InputGrid.js +39 -0
  33. package/cjs/core/InputGrid/index.d.ts +3 -0
  34. package/cjs/core/InputGrid/index.js +15 -0
  35. package/cjs/core/InputGroup/InputGroup.d.ts +13 -0
  36. package/cjs/core/InputGroup/InputGroup.js +35 -9
  37. package/cjs/core/InputWithDecorations/InputWithDecorations.d.ts +39 -0
  38. package/cjs/core/InputWithDecorations/InputWithDecorations.js +81 -0
  39. package/cjs/core/InputWithDecorations/index.d.ts +3 -0
  40. package/cjs/core/InputWithDecorations/index.js +15 -0
  41. package/cjs/core/Label/Label.d.ts +5 -0
  42. package/cjs/core/Label/Label.js +2 -0
  43. package/cjs/core/LabeledInput/LabeledInput.d.ts +22 -16
  44. package/cjs/core/LabeledInput/LabeledInput.js +52 -29
  45. package/cjs/core/LabeledSelect/LabeledSelect.d.ts +17 -7
  46. package/cjs/core/LabeledSelect/LabeledSelect.js +36 -17
  47. package/cjs/core/LabeledTextarea/LabeledTextarea.d.ts +15 -5
  48. package/cjs/core/LabeledTextarea/LabeledTextarea.js +12 -45
  49. package/cjs/core/Menu/Menu.d.ts +1 -1
  50. package/cjs/core/Menu/Menu.js +2 -2
  51. package/cjs/core/Menu/MenuDivider.d.ts +2 -1
  52. package/cjs/core/Menu/MenuDivider.js +1 -1
  53. package/cjs/core/Menu/MenuItem.d.ts +1 -1
  54. package/cjs/core/Menu/MenuItem.js +78 -55
  55. package/cjs/core/Menu/MenuItemSkeleton.d.ts +1 -1
  56. package/cjs/core/Menu/MenuItemSkeleton.js +0 -1
  57. package/cjs/core/SearchBox/SearchBox.js +1 -1
  58. package/cjs/core/Select/Select.d.ts +9 -5
  59. package/cjs/core/Select/Select.js +81 -99
  60. package/cjs/core/SideNavigation/SideNavigation.js +2 -0
  61. package/cjs/core/Slider/Thumb.js +1 -0
  62. package/cjs/core/StatusMessage/StatusMessage.d.ts +12 -2
  63. package/cjs/core/StatusMessage/StatusMessage.js +23 -9
  64. package/cjs/core/Table/SubRowExpander.js +2 -0
  65. package/cjs/core/Table/columns/actionColumn.js +3 -7
  66. package/cjs/core/Table/filters/DateRangeFilter/DatePickerInput.d.ts +6 -1
  67. package/cjs/core/Table/filters/DateRangeFilter/DatePickerInput.js +56 -33
  68. package/cjs/core/Table/filters/DateRangeFilter/DateRangeFilter.d.ts +2 -0
  69. package/cjs/core/Table/filters/DateRangeFilter/DateRangeFilter.js +2 -0
  70. package/cjs/core/Table/filters/FilterToggle.js +3 -2
  71. package/cjs/core/Textarea/Textarea.d.ts +7 -1
  72. package/cjs/core/Textarea/Textarea.js +6 -11
  73. package/cjs/core/ThemeProvider/ThemeProvider.js +1 -1
  74. package/cjs/core/Tile/Tile.d.ts +139 -15
  75. package/cjs/core/Tile/Tile.js +128 -38
  76. package/cjs/core/Toast/Toast.d.ts +12 -4
  77. package/cjs/core/Toast/Toast.js +20 -4
  78. package/cjs/core/Tooltip/Tooltip.d.ts +35 -28
  79. package/cjs/core/Tooltip/Tooltip.js +116 -117
  80. package/cjs/core/TransferList/TransferList.js +4 -12
  81. package/cjs/core/index.d.ts +3 -1
  82. package/cjs/core/index.js +28 -5
  83. package/cjs/core/utils/components/Icon.d.ts +5 -0
  84. package/cjs/core/utils/components/Icon.js +8 -1
  85. package/cjs/core/utils/components/InputContainer.d.ts +4 -5
  86. package/cjs/core/utils/components/InputContainer.js +21 -37
  87. package/cjs/core/utils/components/InputFlexContainer.d.ts +1 -0
  88. package/cjs/core/utils/components/InputFlexContainer.js +3 -1
  89. package/cjs/core/utils/components/Popover.d.ts +113 -27
  90. package/cjs/core/utils/components/Popover.js +156 -118
  91. package/cjs/core/utils/components/Portal.d.ts +27 -0
  92. package/cjs/core/utils/components/Portal.js +43 -0
  93. package/cjs/core/utils/components/index.d.ts +1 -0
  94. package/cjs/core/utils/components/index.js +1 -0
  95. package/cjs/core/utils/functions/index.d.ts +1 -0
  96. package/cjs/core/utils/functions/index.js +1 -0
  97. package/cjs/core/utils/functions/react.d.ts +8 -0
  98. package/cjs/core/utils/functions/react.js +40 -0
  99. package/cjs/core/utils/hooks/index.d.ts +1 -1
  100. package/cjs/core/utils/hooks/index.js +1 -1
  101. package/cjs/core/utils/hooks/useControlledState.d.ts +13 -0
  102. package/cjs/core/utils/hooks/useControlledState.js +39 -0
  103. package/cjs/styles.js +10 -31
  104. package/esm/core/Alert/Alert.d.ts +20 -9
  105. package/esm/core/Alert/Alert.js +49 -10
  106. package/esm/core/ButtonGroup/ButtonGroup.js +41 -36
  107. package/esm/core/Buttons/DropdownButton/DropdownButton.js +8 -24
  108. package/esm/core/Buttons/IconButton/IconButton.js +25 -40
  109. package/esm/core/Buttons/SplitButton/SplitButton.d.ts +4 -4
  110. package/esm/core/Buttons/SplitButton/SplitButton.js +61 -28
  111. package/esm/core/ColorPicker/ColorInputPanel.js +173 -232
  112. package/esm/core/ComboBox/ComboBox.d.ts +2 -2
  113. package/esm/core/ComboBox/ComboBox.js +34 -25
  114. package/esm/core/ComboBox/ComboBoxEndIcon.js +4 -25
  115. package/esm/core/ComboBox/ComboBoxInput.js +22 -21
  116. package/esm/core/ComboBox/ComboBoxMenu.d.ts +2 -2
  117. package/esm/core/ComboBox/ComboBoxMenu.js +67 -87
  118. package/esm/core/ComboBox/ComboBoxMenuItem.d.ts +1 -1
  119. package/esm/core/ComboBox/ComboBoxMenuItem.js +9 -7
  120. package/esm/core/ComboBox/helpers.d.ts +5 -3
  121. package/esm/core/DatePicker/DatePicker.d.ts +30 -8
  122. package/esm/core/DatePicker/DatePicker.js +25 -5
  123. package/esm/core/Dialog/Dialog.js +11 -23
  124. package/esm/core/Dialog/DialogContext.d.ts +3 -4
  125. package/esm/core/DropdownMenu/DropdownMenu.d.ts +6 -5
  126. package/esm/core/DropdownMenu/DropdownMenu.js +64 -56
  127. package/esm/core/ExpandableBlock/ExpandableBlock.d.ts +20 -14
  128. package/esm/core/ExpandableBlock/ExpandableBlock.js +39 -17
  129. package/esm/core/Header/HeaderDropdownButton.js +1 -2
  130. package/esm/core/Header/HeaderSplitButton.js +2 -2
  131. package/esm/core/Input/Input.d.ts +4 -0
  132. package/esm/core/Input/Input.js +2 -1
  133. package/esm/core/InputGrid/InputGrid.d.ts +25 -0
  134. package/esm/core/InputGrid/InputGrid.js +35 -0
  135. package/esm/core/InputGrid/index.d.ts +3 -0
  136. package/esm/core/InputGrid/index.js +6 -0
  137. package/esm/core/InputGroup/InputGroup.d.ts +13 -0
  138. package/esm/core/InputGroup/InputGroup.js +34 -10
  139. package/esm/core/InputWithDecorations/InputWithDecorations.d.ts +39 -0
  140. package/esm/core/InputWithDecorations/InputWithDecorations.js +80 -0
  141. package/esm/core/InputWithDecorations/index.d.ts +3 -0
  142. package/esm/core/InputWithDecorations/index.js +6 -0
  143. package/esm/core/Label/Label.d.ts +5 -0
  144. package/esm/core/Label/Label.js +2 -0
  145. package/esm/core/LabeledInput/LabeledInput.d.ts +22 -16
  146. package/esm/core/LabeledInput/LabeledInput.js +53 -29
  147. package/esm/core/LabeledSelect/LabeledSelect.d.ts +17 -7
  148. package/esm/core/LabeledSelect/LabeledSelect.js +37 -18
  149. package/esm/core/LabeledTextarea/LabeledTextarea.d.ts +15 -5
  150. package/esm/core/LabeledTextarea/LabeledTextarea.js +14 -45
  151. package/esm/core/Menu/Menu.d.ts +1 -1
  152. package/esm/core/Menu/Menu.js +8 -3
  153. package/esm/core/Menu/MenuDivider.d.ts +2 -1
  154. package/esm/core/Menu/MenuDivider.js +1 -1
  155. package/esm/core/Menu/MenuItem.d.ts +1 -1
  156. package/esm/core/Menu/MenuItem.js +85 -52
  157. package/esm/core/Menu/MenuItemSkeleton.d.ts +1 -1
  158. package/esm/core/Menu/MenuItemSkeleton.js +0 -1
  159. package/esm/core/SearchBox/SearchBox.js +1 -1
  160. package/esm/core/Select/Select.d.ts +9 -5
  161. package/esm/core/Select/Select.js +81 -96
  162. package/esm/core/SideNavigation/SideNavigation.js +2 -0
  163. package/esm/core/Slider/Thumb.js +1 -0
  164. package/esm/core/StatusMessage/StatusMessage.d.ts +12 -2
  165. package/esm/core/StatusMessage/StatusMessage.js +23 -16
  166. package/esm/core/Table/SubRowExpander.js +2 -0
  167. package/esm/core/Table/columns/actionColumn.js +3 -7
  168. package/esm/core/Table/filters/DateRangeFilter/DatePickerInput.d.ts +6 -1
  169. package/esm/core/Table/filters/DateRangeFilter/DatePickerInput.js +56 -33
  170. package/esm/core/Table/filters/DateRangeFilter/DateRangeFilter.d.ts +2 -0
  171. package/esm/core/Table/filters/DateRangeFilter/DateRangeFilter.js +2 -0
  172. package/esm/core/Table/filters/FilterToggle.js +3 -2
  173. package/esm/core/Textarea/Textarea.d.ts +7 -1
  174. package/esm/core/Textarea/Textarea.js +6 -11
  175. package/esm/core/ThemeProvider/ThemeProvider.js +4 -3
  176. package/esm/core/Tile/Tile.d.ts +139 -15
  177. package/esm/core/Tile/Tile.js +128 -38
  178. package/esm/core/Toast/Toast.d.ts +12 -4
  179. package/esm/core/Toast/Toast.js +21 -4
  180. package/esm/core/Tooltip/Tooltip.d.ts +35 -28
  181. package/esm/core/Tooltip/Tooltip.js +119 -116
  182. package/esm/core/TransferList/TransferList.js +4 -9
  183. package/esm/core/index.d.ts +3 -1
  184. package/esm/core/index.js +3 -0
  185. package/esm/core/utils/components/Icon.d.ts +5 -0
  186. package/esm/core/utils/components/Icon.js +8 -1
  187. package/esm/core/utils/components/InputContainer.d.ts +4 -5
  188. package/esm/core/utils/components/InputContainer.js +21 -32
  189. package/esm/core/utils/components/InputFlexContainer.d.ts +1 -0
  190. package/esm/core/utils/components/InputFlexContainer.js +3 -1
  191. package/esm/core/utils/components/Popover.d.ts +113 -27
  192. package/esm/core/utils/components/Popover.js +175 -118
  193. package/esm/core/utils/components/Portal.d.ts +27 -0
  194. package/esm/core/utils/components/Portal.js +36 -0
  195. package/esm/core/utils/components/index.d.ts +1 -0
  196. package/esm/core/utils/components/index.js +1 -0
  197. package/esm/core/utils/functions/index.d.ts +1 -0
  198. package/esm/core/utils/functions/index.js +1 -0
  199. package/esm/core/utils/functions/react.d.ts +8 -0
  200. package/esm/core/utils/functions/react.js +35 -0
  201. package/esm/core/utils/hooks/index.d.ts +1 -1
  202. package/esm/core/utils/hooks/index.js +1 -1
  203. package/esm/core/utils/hooks/useControlledState.d.ts +13 -0
  204. package/esm/core/utils/hooks/useControlledState.js +34 -0
  205. package/esm/styles.js +10 -31
  206. package/package.json +3 -5
  207. package/styles.css +23 -20
  208. package/cjs/core/ComboBox/ComboBoxDropdown.d.ts +0 -7
  209. package/cjs/core/ComboBox/ComboBoxDropdown.js +0 -48
  210. package/cjs/core/utils/hooks/useUncontrolledState.d.ts +0 -6
  211. package/cjs/core/utils/hooks/useUncontrolledState.js +0 -18
  212. package/esm/core/ComboBox/ComboBoxDropdown.d.ts +0 -7
  213. package/esm/core/ComboBox/ComboBoxDropdown.js +0 -42
  214. package/esm/core/utils/hooks/useUncontrolledState.d.ts +0 -6
  215. package/esm/core/utils/hooks/useUncontrolledState.js +0 -13
@@ -1,39 +1,125 @@
1
1
  import * as React from 'react';
2
- import type { TippyProps } from '@tippyjs/react';
3
- import type { Placement, Instance } from 'tippy.js';
4
- export type PopoverInstance = Instance;
5
- export type PopoverProps = {
2
+ import type { Placement } from '@floating-ui/react';
3
+ import type { PolymorphicForwardRefComponent } from '../index.js';
4
+ import type { PortalProps } from './Portal.js';
5
+ type PopoverOptions = {
6
+ /**
7
+ * Placement of the popover content.
8
+ * @default 'bottom-start'
9
+ */
10
+ placement?: Placement;
6
11
  /**
7
12
  * Controlled flag for whether the popover is visible.
8
13
  */
9
14
  visible?: boolean;
10
15
  /**
11
- * Determines the events that cause the popover to show.
12
- * Should not be used when `visible` is set.
13
- * @see [tippy.js trigger prop](https://atomiks.github.io/tippyjs/v6/all-props/#trigger)
16
+ * Callback invoked every time the popover visibility changes as a result
17
+ * of internal logic. Should be used alongside `visible` prop.
14
18
  */
15
- trigger?: string;
19
+ onVisibleChange?: (visible: boolean) => void;
16
20
  /**
17
- * Placement of the popover content.
18
- * @default 'bottom-start'
19
- * @see [tippy.js placement prop](https://atomiks.github.io/tippyjs/v6/all-props/#placement).
21
+ * If true, the popover will close when clicking outside it.
20
22
  */
21
- placement?: Placement;
22
- } & Omit<TippyProps, 'placement' | 'trigger' | 'visible'>;
23
- /**
24
- * Wrapper around [tippy.js](https://atomiks.github.io/tippyjs)
25
- * with pre-configured props and plugins (e.g. lazy mounting, focus, etc).
26
- * @private
27
- */
28
- export declare const Popover: React.ForwardRefExoticComponent<Omit<PopoverProps, "ref"> & React.RefAttributes<unknown>>;
29
- /**
30
- * Plugin to hide Popover when either Esc key is pressed,
31
- * or when the content inside is not tabbable and Tab key is pressed.
32
- */
33
- export declare const hideOnEscOrTab: {
34
- fn(instance: Instance): {
35
- onShow(): void;
36
- onHide(): void;
23
+ closeOnOutsideClick?: boolean;
24
+ /**
25
+ * Whether the popover should match the width of the trigger.
26
+ */
27
+ matchWidth?: boolean;
28
+ };
29
+ type PopoverInternalProps = {
30
+ /**
31
+ * autoUpdate options that recalculates position
32
+ * to ensure the floating element remains anchored
33
+ * to its reference element, such as when scrolling
34
+ * and resizing the screen
35
+ *
36
+ * https://floating-ui.com/docs/autoUpdate#options
37
+ */
38
+ autoUpdateOptions?: {
39
+ ancestorScroll?: boolean;
40
+ ancestorResize?: boolean;
41
+ elementResize?: boolean;
42
+ /**
43
+ * Use this if you want popover to follow moving trigger element
44
+ */
45
+ animationFrame?: boolean;
46
+ layoutShift?: boolean;
47
+ };
48
+ /**
49
+ * Middleware options.
50
+ *
51
+ * @see https://floating-ui.com/docs/offset
52
+ */
53
+ middleware?: {
54
+ offset?: number;
55
+ flip?: boolean;
56
+ shift?: boolean;
57
+ autoPlacement?: boolean;
58
+ hide?: boolean;
59
+ inline?: boolean;
37
60
  };
61
+ /**
62
+ * By default, the popover will only open on click.
63
+ * `hover` and `focus` can be manually specified as triggers.
64
+ */
65
+ trigger?: Partial<Record<'hover' | 'click' | 'focus', boolean>>;
66
+ role?: 'dialog' | 'menu' | 'listbox';
67
+ };
68
+ export declare const usePopover: (options: PopoverOptions & PopoverInternalProps) => {
69
+ placement: Placement;
70
+ strategy: import("@floating-ui/utils").Strategy;
71
+ middlewareData: import("@floating-ui/core").MiddlewareData;
72
+ x: number;
73
+ y: number;
74
+ isPositioned: boolean;
75
+ update: () => void;
76
+ floatingStyles: React.CSSProperties;
77
+ refs: {
78
+ reference: React.MutableRefObject<import("@floating-ui/react-dom").ReferenceType | null>;
79
+ floating: React.MutableRefObject<HTMLElement | null>;
80
+ setReference: (node: import("@floating-ui/react-dom").ReferenceType | null) => void;
81
+ setFloating: (node: HTMLElement | null) => void;
82
+ } & import("@floating-ui/react").ExtendedRefs<import("@floating-ui/react").ReferenceType>;
83
+ elements: {
84
+ reference: import("@floating-ui/react-dom").ReferenceType | null; /**
85
+ * Middleware options.
86
+ *
87
+ * @see https://floating-ui.com/docs/offset
88
+ */
89
+ floating: HTMLElement | null;
90
+ } & import("@floating-ui/react").ExtendedElements<import("@floating-ui/react").ReferenceType>;
91
+ context: {
92
+ x: number;
93
+ y: number;
94
+ placement: Placement;
95
+ strategy: import("@floating-ui/utils").Strategy;
96
+ middlewareData: import("@floating-ui/core").MiddlewareData;
97
+ isPositioned: boolean;
98
+ update: () => void;
99
+ floatingStyles: React.CSSProperties;
100
+ open: boolean;
101
+ onOpenChange: (open: boolean, event?: Event | undefined) => void;
102
+ events: import("@floating-ui/react").FloatingEvents;
103
+ dataRef: React.MutableRefObject<import("@floating-ui/react").ContextData>;
104
+ nodeId: string | undefined;
105
+ floatingId: string;
106
+ refs: import("@floating-ui/react").ExtendedRefs<import("@floating-ui/react").ReferenceType>;
107
+ elements: import("@floating-ui/react").ExtendedElements<import("@floating-ui/react").ReferenceType>;
108
+ };
109
+ getFloatingProps: (userProps?: React.HTMLProps<HTMLElement>) => Record<string, unknown>;
110
+ getReferenceProps: (userProps?: React.HTMLProps<Element> | undefined) => Record<string, unknown>;
111
+ getItemProps: (userProps?: React.HTMLProps<HTMLElement> | undefined) => Record<string, unknown>;
112
+ open: boolean | undefined;
113
+ onOpenChange: React.Dispatch<React.SetStateAction<boolean | undefined>>;
38
114
  };
115
+ type PopoverPublicProps = {
116
+ content?: React.ReactNode;
117
+ children?: React.ReactNode;
118
+ applyBackground?: boolean;
119
+ } & PortalProps & PopoverOptions;
120
+ /**
121
+ * A utility component to help with positioning of floating content.
122
+ * Built on top of [`floating-ui`](https://floating-ui.com/)
123
+ */
124
+ export declare const Popover: PolymorphicForwardRefComponent<"div", PopoverPublicProps>;
39
125
  export default Popover;
@@ -4,129 +4,167 @@
4
4
  * See LICENSE.md in the project root for license terms and full copyright notice.
5
5
  *--------------------------------------------------------------------------------------------*/
6
6
  Object.defineProperty(exports, '__esModule', { value: true });
7
- exports.hideOnEscOrTab = exports.Popover = void 0;
7
+ exports.Popover = exports.usePopover = void 0;
8
8
  const tslib_1 = require('tslib');
9
9
  const React = tslib_1.__importStar(require('react'));
10
- const classnames_1 = tslib_1.__importDefault(require('classnames'));
11
- const react_1 = tslib_1.__importDefault(require('@tippyjs/react'));
12
- const index_js_1 = require('../hooks/index.js');
13
- const ThemeContext_js_1 = require('../../ThemeProvider/ThemeContext.js');
14
- /**
15
- * Wrapper around [tippy.js](https://atomiks.github.io/tippyjs)
16
- * with pre-configured props and plugins (e.g. lazy mounting, focus, etc).
17
- * @private
18
- */
19
- exports.Popover = React.forwardRef((props, ref) => {
20
- const [mounted, setMounted] = React.useState(false);
21
- const themeInfo = React.useContext(ThemeContext_js_1.ThemeContext);
22
- const isDomAvailable = (0, index_js_1.useIsClient)();
23
- const tippyRef = React.useRef(null);
24
- const refs = (0, index_js_1.useMergedRefs)(tippyRef, ref);
25
- // Plugin to allow lazy mounting. See https://github.com/atomiks/tippyjs-react#lazy-mounting
26
- const lazyLoad = {
27
- fn: () => ({
28
- onShow: () => setMounted(true),
29
- onHidden: () => setMounted(false),
10
+ const react_1 = require('@floating-ui/react');
11
+ const index_js_1 = require('../index.js');
12
+ const Portal_js_1 = require('./Portal.js');
13
+ const index_js_2 = require('../../Surface/index.js');
14
+ const index_js_3 = require('../../ThemeProvider/index.js');
15
+ // ----------------------------------------------------------------------------
16
+ const usePopover = (options) => {
17
+ const {
18
+ placement = 'bottom-start',
19
+ visible,
20
+ onVisibleChange,
21
+ closeOnOutsideClick,
22
+ autoUpdateOptions,
23
+ middleware = { flip: true, shift: true },
24
+ matchWidth,
25
+ trigger = { click: true, hover: false, focus: false },
26
+ role,
27
+ } = options;
28
+ const [open, onOpenChange] = (0, index_js_1.useControlledState)(
29
+ false,
30
+ visible,
31
+ onVisibleChange,
32
+ );
33
+ const floating = (0, react_1.useFloating)({
34
+ placement,
35
+ open,
36
+ onOpenChange,
37
+ whileElementsMounted: (...args) =>
38
+ (0, react_1.autoUpdate)(...args, autoUpdateOptions),
39
+ middleware: [
40
+ middleware.offset !== undefined && (0, react_1.offset)(middleware.offset),
41
+ middleware.flip && (0, react_1.flip)(),
42
+ middleware.shift && (0, react_1.shift)(),
43
+ matchWidth &&
44
+ (0, react_1.size)({
45
+ apply: ({ rects }) => {
46
+ setReferenceWidth(rects.reference.width);
47
+ },
48
+ }),
49
+ middleware.autoPlacement && (0, react_1.autoPlacement)(),
50
+ middleware.inline && (0, react_1.inline)(),
51
+ middleware.hide && (0, react_1.hide)(),
52
+ ].filter(Boolean),
53
+ });
54
+ const interactions = (0, react_1.useInteractions)([
55
+ (0, react_1.useClick)(floating.context, { enabled: !!trigger.click }),
56
+ (0, react_1.useDismiss)(floating.context, {
57
+ outsidePress: closeOnOutsideClick,
30
58
  }),
31
- };
32
- // Plugin to remove tabindex from tippy, to prevent focus ring from unintentionally showing.
33
- const removeTabIndex = {
34
- fn: () => ({
35
- onCreate: (instance) => {
36
- instance.popper.firstElementChild?.removeAttribute('tabindex');
37
- },
59
+ (0, react_1.useHover)(floating.context, {
60
+ enabled: !!trigger.hover,
61
+ delay: 100,
62
+ handleClose: (0, react_1.safePolygon)({ buffer: 1 }),
38
63
  }),
39
- };
40
- const computedProps = {
41
- allowHTML: true,
42
- animation: false,
43
- appendTo: (el) => themeInfo?.portalContainer || el.ownerDocument.body,
44
- arrow: false,
45
- duration: 0,
46
- interactive: true,
47
- role: '',
48
- offset: [0, 0],
49
- maxWidth: '',
50
- zIndex: 99999,
51
- ...props,
52
- className: (0, classnames_1.default)('iui-popover', props.className),
53
- // add additional check for isDomAvailable when using in controlled mode,
54
- // because rootRef is not available in first render
55
- visible:
56
- props.visible !== undefined ? props.visible && isDomAvailable : undefined,
57
- plugins: [
58
- lazyLoad,
59
- removeTabIndex,
60
- exports.hideOnEscOrTab,
61
- ...(props.plugins || []),
62
- ],
63
- popperOptions: {
64
- strategy: 'fixed',
65
- ...props.popperOptions,
66
- modifiers: [
67
- { name: 'flip' },
68
- {
69
- name: 'preventOverflow',
70
- options: { padding: 0 },
64
+ (0, react_1.useFocus)(floating.context, { enabled: !!trigger.focus }),
65
+ (0, react_1.useRole)(floating.context, { role: 'dialog', enabled: !!role }),
66
+ ]);
67
+ const [referenceWidth, setReferenceWidth] = React.useState();
68
+ const getFloatingProps = React.useCallback(
69
+ (userProps) =>
70
+ interactions.getFloatingProps({
71
+ ...userProps,
72
+ style: {
73
+ ...floating.floatingStyles,
74
+ zIndex: 9999,
75
+ ...(matchWidth && referenceWidth
76
+ ? {
77
+ minInlineSize: `${referenceWidth}px`,
78
+ maxInlineSize: `min(${referenceWidth * 2}px, 90vw)`,
79
+ }
80
+ : {}),
81
+ ...userProps?.style,
71
82
  },
72
- ...(props.popperOptions?.modifiers || []),
73
- ],
74
- },
75
- };
76
- if (props.render) {
77
- const render = props.render;
78
- computedProps.render = (...args) => (mounted ? render(...args) : '');
79
- } else {
80
- // Fixing issue where elements below Popover gets click events.
81
- // Tippy uses react Portal, which propagates events by react tree, not dom tree.
82
- // Read more: https://reactjs.org/docs/portals.html#event-bubbling-through-portals
83
- const clonedContent = React.isValidElement(props.content)
84
- ? React.cloneElement(props.content, {
85
- onClick: (e) => {
86
- e.stopPropagation();
87
- props.content.props.onClick?.(e);
88
- },
89
- })
90
- : props.content;
91
- computedProps.content = mounted ? clonedContent : '';
92
- }
93
- return React.createElement(react_1.default, { ...computedProps, ref: refs });
94
- });
83
+ }),
84
+ [floating.floatingStyles, interactions, matchWidth, referenceWidth],
85
+ );
86
+ return React.useMemo(
87
+ () => ({
88
+ open,
89
+ onOpenChange,
90
+ ...interactions,
91
+ getFloatingProps,
92
+ ...floating,
93
+ }),
94
+ [open, onOpenChange, interactions, getFloatingProps, floating],
95
+ );
96
+ };
97
+ exports.usePopover = usePopover;
95
98
  /**
96
- * Plugin to hide Popover when either Esc key is pressed,
97
- * or when the content inside is not tabbable and Tab key is pressed.
99
+ * A utility component to help with positioning of floating content.
100
+ * Built on top of [`floating-ui`](https://floating-ui.com/)
98
101
  */
99
- exports.hideOnEscOrTab = {
100
- fn(instance) {
101
- /** @returns true if none of the children are tabbable */
102
- const shouldHideOnTab = () => {
103
- const descendents = Array.from(instance.popper.querySelectorAll('*'));
104
- return !descendents.some((el) => el?.tabIndex >= 0);
105
- };
106
- const onKeyDown = (event) => {
107
- if (event.altKey) {
108
- return;
109
- }
110
- switch (event.key) {
111
- case 'Escape':
112
- instance.hide();
113
- break;
114
- case 'Tab':
115
- if (shouldHideOnTab()) {
116
- event.shiftKey && event.preventDefault(); // focus popover target on Shift+Tab
117
- instance.hide();
118
- }
119
- break;
120
- }
121
- };
122
- return {
123
- onShow() {
124
- instance.popper.addEventListener('keydown', onKeyDown);
125
- },
126
- onHide() {
127
- instance.popper.removeEventListener('keydown', onKeyDown);
128
- },
129
- };
130
- },
131
- };
102
+ exports.Popover = React.forwardRef((props, forwardedRef) => {
103
+ const {
104
+ portal = true,
105
+ //
106
+ // popover options
107
+ visible,
108
+ placement,
109
+ onVisibleChange,
110
+ closeOnOutsideClick,
111
+ matchWidth,
112
+ //
113
+ // dom props
114
+ children,
115
+ content,
116
+ applyBackground,
117
+ ...rest
118
+ } = props;
119
+ const popover = (0, exports.usePopover)({
120
+ visible,
121
+ placement,
122
+ onVisibleChange,
123
+ closeOnOutsideClick,
124
+ matchWidth,
125
+ role: 'dialog',
126
+ });
127
+ const [popoverElement, setPopoverElement] = React.useState();
128
+ const popoverRef = (0, index_js_1.useMergedRefs)(
129
+ popover.refs.setFloating,
130
+ forwardedRef,
131
+ setPopoverElement,
132
+ );
133
+ return React.createElement(
134
+ React.Fragment,
135
+ null,
136
+ (0, index_js_1.cloneElementWithRef)(children, (children) => ({
137
+ ...popover.getReferenceProps(children.props),
138
+ ref: popover.refs.setReference,
139
+ })),
140
+ popover.open
141
+ ? React.createElement(
142
+ Portal_js_1.Portal,
143
+ { portal: portal },
144
+ React.createElement(
145
+ index_js_3.ThemeProvider,
146
+ { portalContainer: popoverElement },
147
+ React.createElement(
148
+ react_1.FloatingFocusManager,
149
+ {
150
+ context: popover.context,
151
+ modal: false,
152
+ initialFocus: -1,
153
+ returnFocus: true,
154
+ },
155
+ React.createElement(
156
+ index_js_1.Box,
157
+ {
158
+ as: applyBackground ? index_js_2.Surface : 'div',
159
+ ...popover.getFloatingProps(rest),
160
+ ref: popoverRef,
161
+ },
162
+ content,
163
+ ),
164
+ ),
165
+ ),
166
+ )
167
+ : null,
168
+ );
169
+ });
132
170
  exports.default = exports.Popover;
@@ -0,0 +1,27 @@
1
+ import * as React from 'react';
2
+ export type PortalProps = {
3
+ /**
4
+ * Where should the element be portaled to?
5
+ *
6
+ * If true, it will portal into nearest ThemeContext.portalContainer.
7
+ *
8
+ * If false, it will not be portaled.
9
+ *
10
+ * Otherwise, it will portal to the element passed to `to`.
11
+ *
12
+ * @default true
13
+ */
14
+ portal?: boolean | {
15
+ to: HTMLElement | (() => HTMLElement);
16
+ };
17
+ };
18
+ /**
19
+ * Helper component that portals children according to the following conditions:
20
+ * - renders null on server
21
+ * - if `portal` is set to true, renders into nearest ThemeContext.portalContainer
22
+ * - if `portal` is set to false, renders as-is without portal
23
+ * - otherwise renders into `portal.to` (can be an element or a function)
24
+ *
25
+ * @private
26
+ */
27
+ export declare const Portal: (props: React.PropsWithChildren<PortalProps>) => React.ReactNode;
@@ -0,0 +1,43 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, '__esModule', { value: true });
3
+ exports.Portal = void 0;
4
+ const tslib_1 = require('tslib');
5
+ /*---------------------------------------------------------------------------------------------
6
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
7
+ * See LICENSE.md in the project root for license terms and full copyright notice.
8
+ *--------------------------------------------------------------------------------------------*/
9
+ const React = tslib_1.__importStar(require('react'));
10
+ const ReactDOM = tslib_1.__importStar(require('react-dom'));
11
+ const ThemeContext_js_1 = require('../../ThemeProvider/ThemeContext.js');
12
+ const dom_js_1 = require('../functions/dom.js');
13
+ const useIsClient_js_1 = require('../hooks/useIsClient.js');
14
+ // ----------------------------------------------------------------------------
15
+ /**
16
+ * Helper component that portals children according to the following conditions:
17
+ * - renders null on server
18
+ * - if `portal` is set to true, renders into nearest ThemeContext.portalContainer
19
+ * - if `portal` is set to false, renders as-is without portal
20
+ * - otherwise renders into `portal.to` (can be an element or a function)
21
+ *
22
+ * @private
23
+ */
24
+ const Portal = (props) => {
25
+ const { portal = true, children } = props;
26
+ const isClient = (0, useIsClient_js_1.useIsClient)();
27
+ const portalTo = usePortalTo(portal);
28
+ if (!isClient) {
29
+ return null;
30
+ }
31
+ return portalTo ? ReactDOM.createPortal(children, portalTo) : children;
32
+ };
33
+ exports.Portal = Portal;
34
+ // ----------------------------------------------------------------------------
35
+ const usePortalTo = (portal) => {
36
+ const themeInfo = React.useContext(ThemeContext_js_1.ThemeContext);
37
+ if (typeof portal === 'boolean') {
38
+ return portal
39
+ ? themeInfo?.portalContainer ?? (0, dom_js_1.getDocument)()?.body
40
+ : null;
41
+ }
42
+ return typeof portal.to === 'function' ? portal.to() : portal.to;
43
+ };
@@ -14,3 +14,4 @@ export * from './LinkAction.js';
14
14
  export * from './AutoclearingHiddenLiveRegion.js';
15
15
  export * from './Box.js';
16
16
  export * from './ButtonBase.js';
17
+ export * from './Portal.js';
@@ -21,3 +21,4 @@ tslib_1.__exportStar(require('./LinkAction.js'), exports);
21
21
  tslib_1.__exportStar(require('./AutoclearingHiddenLiveRegion.js'), exports);
22
22
  tslib_1.__exportStar(require('./Box.js'), exports);
23
23
  tslib_1.__exportStar(require('./ButtonBase.js'), exports);
24
+ tslib_1.__exportStar(require('./Portal.js'), exports);
@@ -6,3 +6,4 @@ export * from './focusable.js';
6
6
  export * from './supports.js';
7
7
  export * from './polymorphic.js';
8
8
  export * from './import.js';
9
+ export * from './react.js';
@@ -13,3 +13,4 @@ tslib_1.__exportStar(require('./focusable.js'), exports);
13
13
  tslib_1.__exportStar(require('./supports.js'), exports);
14
14
  tslib_1.__exportStar(require('./polymorphic.js'), exports);
15
15
  tslib_1.__exportStar(require('./import.js'), exports);
16
+ tslib_1.__exportStar(require('./react.js'), exports);
@@ -0,0 +1,8 @@
1
+ import * as React from 'react';
2
+ /**
3
+ * Wrapper over `cloneElement` that automatically checks for `isValidElement`
4
+ * and automatically merges `children.ref` with the ref passed in props.
5
+ *
6
+ * @private
7
+ */
8
+ export declare const cloneElementWithRef: (children: React.ReactNode, getProps: (children: JSX.Element) => Record<string, unknown>) => string | number | true | React.ReactElement<any, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null;
@@ -0,0 +1,40 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, '__esModule', { value: true });
3
+ exports.cloneElementWithRef = void 0;
4
+ const tslib_1 = require('tslib');
5
+ /*---------------------------------------------------------------------------------------------
6
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
7
+ * See LICENSE.md in the project root for license terms and full copyright notice.
8
+ *--------------------------------------------------------------------------------------------*/
9
+ const React = tslib_1.__importStar(require('react'));
10
+ const useMergedRefs_js_1 = require('../hooks/useMergedRefs.js');
11
+ /**
12
+ * Wrapper over `cloneElement` that automatically checks for `isValidElement`
13
+ * and automatically merges `children.ref` with the ref passed in props.
14
+ *
15
+ * @private
16
+ */
17
+ const cloneElementWithRef = (children, getProps) => {
18
+ if (!children) {
19
+ return null;
20
+ }
21
+ if (!React.isValidElement(children)) {
22
+ return children;
23
+ }
24
+ const props = getProps(children);
25
+ const ref = (0, useMergedRefs_js_1.mergeRefs)(
26
+ ...[
27
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
+ 'ref' in children ? children.ref : null,
29
+ 'ref' in props ? props.ref : null,
30
+ ].filter(Boolean),
31
+ );
32
+ return React.cloneElement(children, {
33
+ ...props,
34
+ // we already checked ref above and handled null, so ts-ignore is ok
35
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
36
+ // @ts-ignore
37
+ ref,
38
+ });
39
+ };
40
+ exports.cloneElementWithRef = cloneElementWithRef;
@@ -11,4 +11,4 @@ export * from './useLatestRef.js';
11
11
  export * from './useIsomorphicLayoutEffect.js';
12
12
  export * from './useIsClient.js';
13
13
  export * from './useId.js';
14
- export * from './useUncontrolledState.js';
14
+ export * from './useControlledState.js';
@@ -18,4 +18,4 @@ tslib_1.__exportStar(require('./useLatestRef.js'), exports);
18
18
  tslib_1.__exportStar(require('./useIsomorphicLayoutEffect.js'), exports);
19
19
  tslib_1.__exportStar(require('./useIsClient.js'), exports);
20
20
  tslib_1.__exportStar(require('./useId.js'), exports);
21
- tslib_1.__exportStar(require('./useUncontrolledState.js'), exports);
21
+ tslib_1.__exportStar(require('./useControlledState.js'), exports);
@@ -0,0 +1,13 @@
1
+ import * as React from 'react';
2
+ /**
3
+ * Wrapper over `useState` that always gives preference to the
4
+ * controlled state (which often comes from a prop).
5
+ *
6
+ * This is helpful when a component needs to support both uncontrolled
7
+ * and controlled states. If controlled value/setter is not passed,
8
+ * then it will work just like a regular `useState`.
9
+ *
10
+ * @example
11
+ * const [state, setState] = useControlledState(null, props.value, props.onChange);
12
+ */
13
+ export declare const useControlledState: <T>(initialValue: T, controlledState: T, setControlledState?: React.Dispatch<React.SetStateAction<T>> | undefined) => readonly [T, React.Dispatch<React.SetStateAction<T>>];
@@ -0,0 +1,39 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, '__esModule', { value: true });
3
+ exports.useControlledState = void 0;
4
+ const tslib_1 = require('tslib');
5
+ /*---------------------------------------------------------------------------------------------
6
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
7
+ * See LICENSE.md in the project root for license terms and full copyright notice.
8
+ *--------------------------------------------------------------------------------------------*/
9
+ const React = tslib_1.__importStar(require('react'));
10
+ /**
11
+ * Wrapper over `useState` that always gives preference to the
12
+ * controlled state (which often comes from a prop).
13
+ *
14
+ * This is helpful when a component needs to support both uncontrolled
15
+ * and controlled states. If controlled value/setter is not passed,
16
+ * then it will work just like a regular `useState`.
17
+ *
18
+ * @example
19
+ * const [state, setState] = useControlledState(null, props.value, props.onChange);
20
+ */
21
+ const useControlledState = (
22
+ initialValue,
23
+ controlledState,
24
+ setControlledState,
25
+ ) => {
26
+ const [uncontrolledState, setUncontrolledState] =
27
+ React.useState(initialValue);
28
+ const state =
29
+ controlledState !== undefined ? controlledState : uncontrolledState;
30
+ const setState = React.useCallback(
31
+ (value) => {
32
+ setUncontrolledState(value);
33
+ setControlledState?.(value);
34
+ },
35
+ [setControlledState, setUncontrolledState],
36
+ );
37
+ return [state, setState];
38
+ };
39
+ exports.useControlledState = useControlledState;