@apify/ui-library 1.138.2 → 1.138.4-featpublictasks-2f3d3c.48

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 (45) hide show
  1. package/dist/src/components/box.d.ts +1 -0
  2. package/dist/src/components/box.d.ts.map +1 -1
  3. package/dist/src/components/box.js.map +1 -1
  4. package/dist/src/components/browser_window/browser_window.d.ts +20 -0
  5. package/dist/src/components/browser_window/browser_window.d.ts.map +1 -0
  6. package/dist/src/components/browser_window/browser_window.js +72 -0
  7. package/dist/src/components/browser_window/browser_window.js.map +1 -0
  8. package/dist/src/components/browser_window/index.d.ts +2 -0
  9. package/dist/src/components/browser_window/index.d.ts.map +1 -0
  10. package/dist/src/components/browser_window/index.js +2 -0
  11. package/dist/src/components/browser_window/index.js.map +1 -0
  12. package/dist/src/components/chip.d.ts +1 -0
  13. package/dist/src/components/chip.d.ts.map +1 -1
  14. package/dist/src/components/chip.js +25 -2
  15. package/dist/src/components/chip.js.map +1 -1
  16. package/dist/src/components/code/prism_highlighter.d.ts +2 -0
  17. package/dist/src/components/code/prism_highlighter.d.ts.map +1 -1
  18. package/dist/src/components/collapsible_card/collapsible_card.d.ts +3 -2
  19. package/dist/src/components/collapsible_card/collapsible_card.d.ts.map +1 -1
  20. package/dist/src/components/collapsible_card/collapsible_card.js +2 -2
  21. package/dist/src/components/collapsible_card/collapsible_card.js.map +1 -1
  22. package/dist/src/components/floating/floating_component_base.d.ts +72 -1
  23. package/dist/src/components/floating/floating_component_base.d.ts.map +1 -1
  24. package/dist/src/components/floating/floating_component_base.js +66 -36
  25. package/dist/src/components/floating/floating_component_base.js.map +1 -1
  26. package/dist/src/components/floating/tooltip.d.ts +10 -3
  27. package/dist/src/components/floating/tooltip.d.ts.map +1 -1
  28. package/dist/src/components/floating/tooltip.js +24 -20
  29. package/dist/src/components/floating/tooltip.js.map +1 -1
  30. package/dist/src/components/icon_button.d.ts +1 -0
  31. package/dist/src/components/icon_button.d.ts.map +1 -1
  32. package/dist/src/components/index.d.ts +1 -0
  33. package/dist/src/components/index.d.ts.map +1 -1
  34. package/dist/src/components/index.js +1 -0
  35. package/dist/src/components/index.js.map +1 -1
  36. package/dist/tsconfig.build.tsbuildinfo +1 -1
  37. package/package.json +4 -4
  38. package/src/components/box.tsx +1 -0
  39. package/src/components/browser_window/browser_window.tsx +106 -0
  40. package/src/components/browser_window/index.ts +1 -0
  41. package/src/components/chip.tsx +27 -1
  42. package/src/components/collapsible_card/collapsible_card.tsx +6 -4
  43. package/src/components/floating/floating_component_base.tsx +89 -47
  44. package/src/components/floating/tooltip.tsx +53 -25
  45. package/src/components/index.ts +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apify/ui-library",
3
- "version": "1.138.2",
3
+ "version": "1.138.4-featpublictasks-2f3d3c.48+ff8f29a938a",
4
4
  "description": "React UI library used by apify.com",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -27,7 +27,7 @@
27
27
  "It's not nice, but helps us to get around the problem of multiple react instances."
28
28
  ],
29
29
  "dependencies": {
30
- "@apify/ui-icons": "^1.38.1",
30
+ "@apify/ui-icons": "^1.38.2-featpublictasks-2f3d3c.73+ff8f29a938a",
31
31
  "@floating-ui/react": "^0.27.19",
32
32
  "@floating-ui/react-dom": "^2.1.8",
33
33
  "@radix-ui/react-checkbox": "^1.3.3",
@@ -58,7 +58,7 @@
58
58
  "styled-components": "^6.1.19"
59
59
  },
60
60
  "devDependencies": {
61
- "@apify-packages/types": "^3.353.2",
61
+ "@apify-packages/types": "^3.353.4-featpublictasks-2f3d3c.48+ff8f29a938a",
62
62
  "@storybook/react-vite": "^10.3.5",
63
63
  "@types/hast": "^3.0.4",
64
64
  "@types/lodash": "^4.14.200",
@@ -72,5 +72,5 @@
72
72
  "src",
73
73
  "style"
74
74
  ],
75
- "gitHead": "6559101d432b8c35bad8dc06c79e0f3236cdefe6"
75
+ "gitHead": "ff8f29a938ac47851ce5b052bf96594609db7041"
76
76
  }
@@ -34,6 +34,7 @@ type SharedBoxProps = {
34
34
  style?: React.CSSProperties;
35
35
  onClick?: (e: React.MouseEvent) => void;
36
36
  id?: string;
37
+ title?: string;
37
38
  };
38
39
 
39
40
  // This should be renamed - these props are global for any element not just Boxes
@@ -0,0 +1,106 @@
1
+ import clsx from 'clsx';
2
+ import type { ReactNode } from 'react';
3
+ import styled from 'styled-components';
4
+
5
+ import { theme } from '../../design_system/theme.js';
6
+ import { Badge } from '../badge.js';
7
+
8
+ const classNames = {
9
+ ROOT: 'browser-window',
10
+ HEADER: 'browser-window__header',
11
+ DOTS: 'browser-window__dots',
12
+ DOT: 'browser-window__dot',
13
+ URL: 'browser-window__url',
14
+ TITLE: 'browser-window__title',
15
+ CONTAINER: 'browser-window__container',
16
+ CONTENT: 'browser-window__content',
17
+ } as const;
18
+
19
+ export { classNames as browserWindowClassNames };
20
+
21
+ const BrowserWindowWrapper = styled.div`
22
+ border: 1px solid ${theme.color.neutral.separatorSubtle};
23
+ border-radius: ${theme.radius.radius12};
24
+ background-color: ${theme.color.neutral.background};
25
+ overflow: hidden;
26
+
27
+ .${classNames.HEADER} {
28
+ display: flex;
29
+ align-items: center;
30
+ gap: ${theme.space.space8};
31
+ padding: ${theme.space.space6} ${theme.space.space8};
32
+ border-bottom: 1px solid ${theme.color.neutral.separatorSubtle};
33
+ background-color: ${theme.color.neutral.backgroundMuted};
34
+ }
35
+
36
+ .${classNames.DOTS} {
37
+ display: flex;
38
+ gap: 0.3rem;
39
+ flex-shrink: 0;
40
+ }
41
+
42
+ .${classNames.DOT} {
43
+ width: 0.6rem;
44
+ height: 0.6rem;
45
+ border-radius: 50%;
46
+ background-color: ${theme.color.neutral.separatorSubtle};
47
+ }
48
+
49
+ .${classNames.URL} {
50
+ width: 100%;
51
+ min-width: 0;
52
+ justify-content: flex-start;
53
+ color: ${theme.color.neutral.textSubtle};
54
+
55
+ span {
56
+ min-width: 0;
57
+ text-overflow: ellipsis;
58
+ white-space: nowrap;
59
+ overflow: hidden;
60
+ }
61
+ }
62
+
63
+ .${classNames.TITLE} {
64
+ margin-left: auto;
65
+ flex-shrink: 0;
66
+ }
67
+
68
+ .${classNames.CONTAINER} {
69
+ min-width: 0;
70
+ overflow-x: auto;
71
+ }
72
+ `;
73
+
74
+ type Props = {
75
+ title: string;
76
+ url?: ReactNode;
77
+ children: ReactNode;
78
+ className?: string;
79
+ };
80
+
81
+ export const BrowserWindow = ({ title, url, children, className }: Props) => {
82
+ return (
83
+ <BrowserWindowWrapper className={clsx(classNames.ROOT, className)}>
84
+ <div className={classNames.HEADER}>
85
+ {url && (
86
+ <>
87
+ <div className={classNames.DOTS}>
88
+ <span className={classNames.DOT} />
89
+ <span className={classNames.DOT} />
90
+ <span className={classNames.DOT} />
91
+ </div>
92
+ <Badge size="extra_small" variant="neutral_subtle" className={classNames.URL}>
93
+ {url}
94
+ </Badge>
95
+ </>
96
+ )}
97
+ <Badge size="extra_small" className={classNames.TITLE}>
98
+ {title}
99
+ </Badge>
100
+ </div>
101
+ <div className={classNames.CONTAINER}>
102
+ <div className={classNames.CONTENT}>{children}</div>
103
+ </div>
104
+ </BrowserWindowWrapper>
105
+ );
106
+ };
@@ -0,0 +1 @@
1
+ export * from './browser_window.js';
@@ -80,9 +80,34 @@ const chipTypeStyle = {
80
80
  `,
81
81
  } satisfies Record<CHIP_TYPES, unknown>;
82
82
 
83
+ const chipTypeHoverStyle = {
84
+ [CHIP_TYPES.DEFAULT]: css`
85
+ background: ${theme.color.neutral.chipBackgroundHover};
86
+ `,
87
+ [CHIP_TYPES.PRIMARY]: css`
88
+ background: ${theme.color.primary.chipBackgroundHover};
89
+ `,
90
+ [CHIP_TYPES.SUCCESS]: css`
91
+ background: ${theme.color.success.chipBackgroundHover};
92
+ `,
93
+ [CHIP_TYPES.WARNING]: css`
94
+ background: ${theme.color.warning.chipBackgroundHover};
95
+ `,
96
+ [CHIP_TYPES.DANGER]: css`
97
+ background: ${theme.color.danger.chipBackgroundHover};
98
+ `,
99
+ } satisfies Record<CHIP_TYPES, unknown>;
100
+
83
101
  const StyledChip = styled.span<{ size: CHIP_SIZES; type: CHIP_TYPES; clickable: boolean }>`
84
102
  ${({ size }) => chipSizeStyle[size]};
85
103
  ${({ type }) => chipTypeStyle[type]};
104
+ ${({ type, clickable }) =>
105
+ clickable &&
106
+ css`
107
+ &:hover {
108
+ ${chipTypeHoverStyle[type]};
109
+ }
110
+ `};
86
111
  /* Static styles */
87
112
  width: fit-content;
88
113
  display: flex;
@@ -111,6 +136,7 @@ export const Chip = forwardRef(
111
136
  {
112
137
  type = CHIP_TYPES.DEFAULT,
113
138
  size = CHIP_SIZES.MEDIUM,
139
+ clickable = false,
114
140
  icon,
115
141
  children,
116
142
  className,
@@ -118,7 +144,7 @@ export const Chip = forwardRef(
118
144
  }: ChipProps,
119
145
  ref,
120
146
  ) => {
121
- const otherProps = { ...passThroughProps, type, size, className: clsx(className, classNames.BODY) };
147
+ const otherProps = { ...passThroughProps, type, size, clickable, className: clsx(className, classNames.BODY) };
122
148
 
123
149
  return (
124
150
  <StyledChip ref={ref} {...otherProps}>
@@ -1,6 +1,6 @@
1
1
  import * as Collapsible from '@radix-ui/react-collapsible';
2
2
  import clsx from 'clsx';
3
- import { type FC, type ReactNode, useState } from 'react';
3
+ import { type ReactNode, useState } from 'react';
4
4
  import styled, { css } from 'styled-components';
5
5
 
6
6
  import { ChevronDownIcon } from '@apify/ui-icons';
@@ -27,6 +27,7 @@ export type CollapsibleCardProps = {
27
27
  header: ReactNode;
28
28
  children: ReactNode;
29
29
  isExpanded?: boolean;
30
+ isExpandedDefault?: boolean;
30
31
  onIsExpandedChanged?: (expanded: boolean) => void;
31
32
  noChevron?: boolean;
32
33
  noDivider?: boolean;
@@ -110,10 +111,11 @@ const CollapsibleContent = styled(Collapsible.Content)<{ $noDivider?: boolean }>
110
111
  ${({ $noDivider }) => ($noDivider ? '' : `border-top: 1px solid ${theme.color.neutral.border};`)}
111
112
  `;
112
113
 
113
- export const CollapsibleCard: FC<CollapsibleCardProps> = ({
114
+ export const CollapsibleCard = ({
114
115
  header,
115
116
  children,
116
117
  isExpanded,
118
+ isExpandedDefault = false,
117
119
  onIsExpandedChanged,
118
120
  noChevron,
119
121
  noDivider,
@@ -124,9 +126,9 @@ export const CollapsibleCard: FC<CollapsibleCardProps> = ({
124
126
  isHeaderGreyOnHover,
125
127
  as: Element,
126
128
  ...rest
127
- }) => {
129
+ }: CollapsibleCardProps) => {
128
130
  const isUncontrolled = isExpanded === undefined;
129
- const [isOpen, setOpen] = useState(false);
131
+ const [isOpen, setOpen] = useState(isExpandedDefault);
130
132
 
131
133
  let onHeaderClick;
132
134
  if (isUncontrolled) onHeaderClick = () => setOpen((prevIsOpen) => !prevIsOpen);
@@ -44,6 +44,81 @@ export const FLOATING_PLACEMENT = {
44
44
 
45
45
  export type FloatingPlacement = (typeof FLOATING_PLACEMENT)[keyof typeof FLOATING_PLACEMENT];
46
46
 
47
+ type UseFloatingPopupOptions = {
48
+ open: boolean;
49
+ onOpenChange?: (open: boolean) => void;
50
+ placement?: FloatingPlacement;
51
+ strategy?: Strategy;
52
+ autoPlacements?: FloatingPlacement[];
53
+ offsetPx?: number;
54
+ };
55
+
56
+ /**
57
+ * Shared `useFloating` + `useTransitionStyles` setup for popup-style components (`Tooltip`,
58
+ * `Popover`, the inner positioning of `FloatingComponentBase`). Owns the middleware stack
59
+ * (`offset` / `flip` | `autoPlacement` / `shift` / `hide`) and the side-aware in/out animation,
60
+ * so individual consumers don't duplicate these.
61
+ *
62
+ * Returns the full `useFloating` result plus `isMounted` and `transitionStyles` from
63
+ * `useTransitionStyles` — destructure what each consumer needs.
64
+ */
65
+ export const useFloatingPopup = ({
66
+ open,
67
+ onOpenChange,
68
+ placement = FLOATING_PLACEMENT.TOP,
69
+ strategy = 'fixed',
70
+ autoPlacements,
71
+ offsetPx = 10,
72
+ }: UseFloatingPopupOptions) => {
73
+ const floating = useFloating({
74
+ open,
75
+ onOpenChange,
76
+ placement,
77
+ strategy,
78
+ whileElementsMounted: autoUpdate,
79
+ middleware: [
80
+ offset(offsetPx),
81
+ autoPlacements?.length ? autoPlacement({ allowedPlacements: autoPlacements }) : flip(),
82
+ shift({ padding: 5 }),
83
+ hide({ strategy: 'referenceHidden' }),
84
+ ],
85
+ });
86
+
87
+ const { isMounted, styles: transitionStyles } = useTransitionStyles(floating.context, {
88
+ initial: ({ side }) => {
89
+ switch (side) {
90
+ case 'top':
91
+ return { opacity: 0, scale: '0.9', transform: 'translateY(10px)' };
92
+ case 'bottom':
93
+ return { opacity: 0, scale: '0.9', transform: 'translateY(-10px)' };
94
+ case 'left':
95
+ return { opacity: 0, scale: '0.9', transform: 'translateX(10px)' };
96
+ case 'right':
97
+ return { opacity: 0, scale: '0.9', transform: 'translateX(-10px)' };
98
+ default:
99
+ return {};
100
+ }
101
+ },
102
+ });
103
+
104
+ return { ...floating, isMounted, transitionStyles };
105
+ };
106
+
107
+ /**
108
+ * Builds the inline `style` object floating-ui consumers spread onto their popup wrapper:
109
+ * positioning (`position`/`top`/`left`), `width: 'max-content'`, the `referenceHidden`
110
+ * visibility toggle, and the in/out transition styles. Centralized so Tooltip / Popover /
111
+ * `FloatingComponentBase` don't redeclare it.
112
+ */
113
+ export const getFloatingPopupStyle = (floating: ReturnType<typeof useFloatingPopup>): CSSProperties => ({
114
+ position: floating.strategy,
115
+ top: floating.y ?? 0,
116
+ left: floating.x ?? 0,
117
+ width: 'max-content',
118
+ visibility: floating.middlewareData.hide?.referenceHidden ? 'hidden' : 'visible',
119
+ ...floating.transitionStyles,
120
+ });
121
+
47
122
  interface FloatingComponentWrapProps {
48
123
  showInPortal?: boolean;
49
124
  className?: string;
@@ -67,7 +142,12 @@ export interface FloatingComponentBaseProps {
67
142
  showInPortal?: boolean;
68
143
  }
69
144
 
70
- const FloatingComponentWrapStyled = styled.span`
145
+ /**
146
+ * Base styling for any popup that renders via floating-ui (Tooltip, Popover, …). Tooltip extends
147
+ * this via `styled(...)` to layer on its dark theme + tighter padding without re-declaring the
148
+ * shared rules.
149
+ */
150
+ export const FloatingComponentWrapper = styled.span`
71
151
  padding: ${theme.space.space16};
72
152
  ${theme.typography.shared.mobile.bodyM};
73
153
  border-radius: 0.8rem;
@@ -100,7 +180,7 @@ const StyledPopoverBox = styled.div`
100
180
 
101
181
  const FloatingComponentWrap = forwardRef<HTMLSpanElement, FloatingComponentWrapProps>((props, ref) => {
102
182
  const { showInPortal, ...rest } = props;
103
- const component = <FloatingComponentWrapStyled {...rest} ref={ref} />;
183
+ const component = <FloatingComponentWrapper {...rest} ref={ref} />;
104
184
  if (showInPortal) {
105
185
  return <FloatingPortal>{component}</FloatingPortal>;
106
186
  }
@@ -127,43 +207,12 @@ export const FloatingComponentBase = ({
127
207
  CloseButtonComponent,
128
208
  showInPortal = false,
129
209
  }: FloatingComponentBaseProps) => {
130
- const {
131
- x,
132
- y,
133
- refs: { setReference, setFloating },
134
- strategy: effectiveStrategy,
135
- middlewareData: { hide: refHidden },
136
- context,
137
- } = useFloating({
210
+ const floating = useFloatingPopup({
138
211
  open: isOpen,
139
212
  placement,
140
213
  strategy,
141
- whileElementsMounted: autoUpdate,
142
- middleware: [
143
- offset(offsetPx),
144
- autoPlacements?.length ? autoPlacement({ allowedPlacements: autoPlacements }) : flip(),
145
- shift({ padding: 5 }),
146
- hide({
147
- strategy: 'referenceHidden',
148
- }),
149
- ],
150
- });
151
-
152
- const { isMounted, styles } = useTransitionStyles(context, {
153
- initial: ({ side }) => {
154
- switch (side) {
155
- case 'top':
156
- return { opacity: 0, scale: '0.9', transform: 'translateY(10px)' };
157
- case 'bottom':
158
- return { opacity: 0, scale: '0.9', transform: 'translateY(-10px)' };
159
- case 'left':
160
- return { opacity: 0, scale: '0.9', transform: 'translateX(10px)' };
161
- case 'right':
162
- return { opacity: 0, scale: '0.9', transform: 'translateX(-10px)' };
163
- default:
164
- return {};
165
- }
166
- },
214
+ autoPlacements,
215
+ offsetPx,
167
216
  });
168
217
 
169
218
  if (!content) return <span>{children}</span>;
@@ -171,21 +220,14 @@ export const FloatingComponentBase = ({
171
220
  return (
172
221
  <>
173
222
  {/* Adding className to children for easier identifying in DevTools */}
174
- <ChildrenWrap className={clsx(classNames.CHILDREN, contentWrapClassName)} ref={setReference}>
223
+ <ChildrenWrap className={clsx(classNames.CHILDREN, contentWrapClassName)} ref={floating.refs.setReference}>
175
224
  {children}
176
225
  </ChildrenWrap>
177
- {isMounted && (
226
+ {floating.isMounted && (
178
227
  <FloatingComponentWrap
179
228
  className={className}
180
- ref={setFloating}
181
- style={{
182
- position: effectiveStrategy,
183
- top: y ?? 0,
184
- left: x ?? 0,
185
- width: 'max-content',
186
- visibility: refHidden?.referenceHidden ? 'hidden' : 'visible',
187
- ...styles,
188
- }}
229
+ ref={floating.refs.setFloating}
230
+ style={getFloatingPopupStyle(floating)}
189
231
  onClick={(e) => e.stopPropagation()}
190
232
  showInPortal={showInPortal}
191
233
  >
@@ -1,10 +1,15 @@
1
- import { useFloating, useHover, useInteractions } from '@floating-ui/react';
1
+ import { FloatingPortal, useHover, useInteractions } from '@floating-ui/react';
2
2
  import { type ComponentType, type ElementType, forwardRef, type ReactNode, useState } from 'react';
3
3
  import styled, { css } from 'styled-components';
4
4
 
5
5
  import { theme } from '../../design_system/theme.js';
6
6
  import { useSharedUiDependencies } from '../../ui_dependency_provider.js';
7
- import { FloatingComponentBase, type FloatingComponentBaseProps } from './floating_component_base.js';
7
+ import {
8
+ type FloatingComponentBaseProps,
9
+ FloatingComponentWrapper,
10
+ getFloatingPopupStyle,
11
+ useFloatingPopup,
12
+ } from './floating_component_base.js';
8
13
  import { TooltipContent } from './tooltip_content.js';
9
14
 
10
15
  export const TOOLTIP_TEXT_ALIGNS = {
@@ -24,7 +29,10 @@ export const TOOLTIP_SIZES = {
24
29
 
25
30
  export type TooltipSize = (typeof TOOLTIP_SIZES)[keyof typeof TOOLTIP_SIZES];
26
31
 
27
- export interface TooltipProps extends Omit<FloatingComponentBaseProps, 'isOpen' | 'size'> {
32
+ export interface TooltipProps extends Omit<
33
+ FloatingComponentBaseProps,
34
+ 'isOpen' | 'size' | 'triggerRef' | 'CloseButtonComponent'
35
+ > {
28
36
  as?: ElementType;
29
37
  className?: string;
30
38
  delayShow?: number;
@@ -43,7 +51,7 @@ interface WithTooltipProps {
43
51
  // Using a styled component to get access to the `as` prop
44
52
  const TooltipFocusArea = styled.span``;
45
53
 
46
- const StyledFloatingComponentBase = styled(FloatingComponentBase)<{ $isDarkTheme?: boolean }>`
54
+ const TooltipPopup = styled(FloatingComponentWrapper)<{ $isDarkTheme?: boolean }>`
47
55
  color: ${theme.colorPalette.dark.neutral0};
48
56
  background-color: ${theme.colorPalette.dark.neutral900};
49
57
  padding: ${theme.space.space8};
@@ -65,7 +73,14 @@ const StyledFloatingComponentBase = styled(FloatingComponentBase)<{ $isDarkTheme
65
73
  `;
66
74
 
67
75
  /**
68
- * Tooltip appears on hover, for onclick use Popover
76
+ * Tooltip appears on hover, for onclick use Popover.
77
+ *
78
+ * Reference (the trigger wrapper) and floating (the popup) are rendered as separate DOM subtrees
79
+ * — the popup is portaled (or rendered as a sibling fragment when `showInPortal={false}`), never
80
+ * nested inside the trigger. floating-ui's `useHover` resolves open/close state by tracking the
81
+ * cursor across distinct reference and floating elements; nesting them causes their bounding
82
+ * rects to overlap and the state machine flips unpredictably (see floating-ui docs on the
83
+ * reference/floating element separation requirement).
69
84
  */
70
85
  export const Tooltip = ({
71
86
  as,
@@ -77,48 +92,61 @@ export const Tooltip = ({
77
92
  subtleText,
78
93
  size = TOOLTIP_SIZES.SMALL,
79
94
  textAlign = TOOLTIP_TEXT_ALIGNS.LEFT,
80
- ...rest
95
+ placement,
96
+ autoPlacements,
97
+ strategy,
98
+ offsetPx,
99
+ contentWrapClassName,
100
+ showInPortal = false,
101
+ content,
102
+ children,
81
103
  }: TooltipProps): ReactNode => {
82
104
  const { uiTheme, tooltipSafeHtml } = useSharedUiDependencies();
83
105
  const [open, setOpen] = useState(false);
84
106
 
85
- const { refs, context } = useFloating({
107
+ const floating = useFloatingPopup({
86
108
  open,
87
109
  onOpenChange: setOpen,
110
+ placement,
111
+ strategy,
112
+ autoPlacements,
113
+ offsetPx,
88
114
  });
89
115
 
90
- const hover = useHover(context, {
91
- delay: {
92
- open: delayShow,
93
- close: delayHide,
94
- },
116
+ const hover = useHover(floating.context, {
117
+ delay: { open: delayShow, close: delayHide },
95
118
  });
96
119
 
97
120
  const { getReferenceProps, getFloatingProps } = useInteractions([hover]);
98
121
 
99
- if (!rest.content && !shortcuts?.length && !imageUrl && !subtleText) return rest.children;
122
+ if (!content && !shortcuts?.length && !imageUrl && !subtleText) return children;
100
123
 
101
- const tooltipProps = {
102
- isOpen: open,
103
- ...rest,
104
- content: (
124
+ const popup = (
125
+ <TooltipPopup
126
+ ref={floating.refs.setFloating}
127
+ className={contentWrapClassName}
128
+ $isDarkTheme={uiTheme === 'DARK'}
129
+ style={getFloatingPopupStyle(floating)}
130
+ {...getFloatingProps()}
131
+ >
105
132
  <TooltipContent
106
- content={tooltipSafeHtml(rest.content)}
133
+ content={tooltipSafeHtml(content)}
107
134
  shortcuts={shortcuts}
108
135
  imageUrl={imageUrl}
109
136
  subtleText={subtleText}
110
137
  size={size}
111
138
  textAlign={textAlign}
112
139
  />
113
- ),
114
- };
140
+ </TooltipPopup>
141
+ );
115
142
 
116
143
  return (
117
- <TooltipFocusArea as={as} className={className} ref={refs.setReference} {...getReferenceProps()}>
118
- <div ref={refs.setFloating} {...getFloatingProps()}>
119
- <StyledFloatingComponentBase {...tooltipProps} $isDarkTheme={uiTheme === 'DARK'} />
120
- </div>
121
- </TooltipFocusArea>
144
+ <>
145
+ <TooltipFocusArea as={as} className={className} ref={floating.refs.setReference} {...getReferenceProps()}>
146
+ {children}
147
+ </TooltipFocusArea>
148
+ {floating.isMounted && (showInPortal ? <FloatingPortal>{popup}</FloatingPortal> : popup)}
149
+ </>
122
150
  );
123
151
  };
124
152
 
@@ -27,6 +27,7 @@ export * from './icon_button.js';
27
27
  export * from './spinner.js';
28
28
  export * from './store/index.js';
29
29
  export * from './checkbox/index.js';
30
+ export * from './browser_window/index.js';
30
31
  export * from './collapsible_card/index.js';
31
32
  export * from './select/index.js';
32
33
  export * from './switch/index.js';