@xsolla/xui-b2c-popover 0.209.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/README.md ADDED
@@ -0,0 +1,22 @@
1
+ # @xsolla/xui-b2c-popover
2
+
3
+ Responsive overlay panel for player-facing surfaces — a 400px floating panel on
4
+ desktop and tablet, a full-screen page on mobile, optionally draggable and
5
+ pinnable. The container behind the Xsolla ID profile popover.
6
+
7
+ ```bash
8
+ yarn add @xsolla/xui-b2c-popover
9
+ ```
10
+
11
+ ```tsx
12
+ import { Popover, usePopover } from "@xsolla/xui-b2c-popover";
13
+
14
+ const { isOpen, open, close } = usePopover();
15
+
16
+ <Popover open={isOpen} onClose={close} title="Profile">
17
+ {sections}
18
+ </Popover>;
19
+ ```
20
+
21
+ Full API, device buckets, layout slots, drag/pin behaviour, and accessibility
22
+ notes: [docs/api/components/b2c-popover.md](../../../docs/api/components/b2c-popover.md).
@@ -0,0 +1,255 @@
1
+ import * as react from 'react';
2
+ import { ReactNode, CSSProperties, RefObject, PointerEvent, KeyboardEvent } from 'react';
3
+ import { ThemeOverrideProps } from '@xsolla/xui-core';
4
+ import * as react_jsx_runtime from 'react/jsx-runtime';
5
+
6
+ /**
7
+ * Device buckets from the Figma "Breakpoints" frame
8
+ * (file `SOOtaT80JAVJf7PKlFnt7Q`, node `6393:1137`):
9
+ *
10
+ * | Device | Viewport | Presentation |
11
+ * | ------- | ------------- | ------------------------------- |
12
+ * | Desktop | 1024px and up | 400px floating panel |
13
+ * | Tablet | 769–1023px | 400px floating panel |
14
+ * | Mobile | 320–768px | full-screen, reads as a page |
15
+ *
16
+ * Mirrors the `Device` variant on the Figma `idPopover` component set
17
+ * (node `7394:4832`), whose options are Desktop (default), Tablet, Mobile.
18
+ */
19
+ type PopoverDevice = "desktop" | "tablet" | "mobile";
20
+ /** Viewport-relative offset of the floating panel's top-left corner. */
21
+ interface PopoverPosition {
22
+ x: number;
23
+ y: number;
24
+ }
25
+ /** Handlers that turn an element into a drag grip for the floating panel. */
26
+ interface PopoverDragHandleProps {
27
+ onPointerDown: (event: PointerEvent) => void;
28
+ onKeyDown: (event: KeyboardEvent) => void;
29
+ }
30
+ interface PopoverProps extends ThemeOverrideProps {
31
+ /** Whether the popover is open. */
32
+ open?: boolean;
33
+ /** Called when the popover should close (Escape, scrim press, close button). */
34
+ onClose?: () => void;
35
+ /**
36
+ * Forces a device bucket instead of measuring the viewport. Useful for
37
+ * Storybook, tests, and product shells that already know their layout.
38
+ * Omit it and `useDeviceType` resolves the bucket from `window.innerWidth`.
39
+ */
40
+ device?: PopoverDevice;
41
+ /**
42
+ * Panel width on `desktop` / `tablet`. Ignored on `mobile`, which fills the
43
+ * viewport.
44
+ * @default 400
45
+ */
46
+ width?: number | string;
47
+ /**
48
+ * Renders the grab handle in the title bar and lets the user reposition the
49
+ * panel. Ignored on `mobile` — per the Figma spec, "Buttons for floating […]
50
+ * Don't use it in other cases and on mobile."
51
+ * @default false
52
+ */
53
+ draggable?: boolean;
54
+ /**
55
+ * Starting viewport offset for a `draggable` panel. Omit to let the panel
56
+ * centre itself until the first drag.
57
+ */
58
+ initialPosition?: PopoverPosition;
59
+ /** Called on every drag frame with the panel's new viewport offset. */
60
+ onPositionChange?: (position: PopoverPosition) => void;
61
+ /** Title shown in the default title bar, to the right of the grab handle. */
62
+ title?: ReactNode;
63
+ /**
64
+ * Whether the popover is pinned. Pinning shows the pin control in its active
65
+ * state and suppresses scrim dismissal. Controlled — the control only renders
66
+ * when `onPinnedChange` is supplied.
67
+ */
68
+ pinned?: boolean;
69
+ /** Called with the next pinned state when the pin control is pressed. */
70
+ onPinnedChange?: (pinned: boolean) => void;
71
+ /**
72
+ * Renders the close (X) control in the default title bar. Set it to `false`
73
+ * for the Figma "No buttons" variant, which has no chrome at all — `onClose`
74
+ * still runs on Escape and on a scrim press, so the popover stays
75
+ * dismissible.
76
+ * @default true
77
+ */
78
+ showCloseButton?: boolean;
79
+ /**
80
+ * Replaces the whole default title bar (grab handle, title, pin, close).
81
+ * You own the grab handle in this case — put `data-xui-popover-drag-handle`
82
+ * on the element that should accept arrow-key nudges.
83
+ */
84
+ titleBar?: ReactNode;
85
+ /**
86
+ * Content pinned above the scrollable body — the logo row, hero image, and
87
+ * greeting in the Xsolla ID profile popover.
88
+ */
89
+ header?: ReactNode;
90
+ /** Scrollable body content. */
91
+ children: ReactNode;
92
+ /** Content pinned below the scrollable body — sign-out button, legal links. */
93
+ footer?: ReactNode;
94
+ /**
95
+ * Whether pressing the scrim closes the popover. Always disabled while
96
+ * `pinned`, and on `mobile`, where a full-screen page has no outside.
97
+ * @default true
98
+ */
99
+ closeOnOverlayClick?: boolean;
100
+ /** Whether pressing Escape closes the popover. @default true */
101
+ closeOnEscape?: boolean;
102
+ /**
103
+ * Renders the dimming scrim behind the panel. Turn it off for a floating
104
+ * panel that should leave the page underneath usable — that is the
105
+ * "Float buttons for desktop" case in the Figma spec.
106
+ * @default true
107
+ */
108
+ scrim?: boolean;
109
+ /**
110
+ * Surface background. Accepts any theme background token or a CSS colour.
111
+ * @default theme.colors.background.primary
112
+ */
113
+ backgroundColor?: string;
114
+ /**
115
+ * Applies the 24px backdrop blur from the Figma `boxShadow&BlurPopover`
116
+ * effect style. Ignored on `mobile`.
117
+ * @default true
118
+ */
119
+ blur?: boolean;
120
+ /** Extra styles merged onto the panel. */
121
+ styled?: CSSProperties;
122
+ /** Element focused when the popover opens. Defaults to the first focusable. */
123
+ initialFocusRef?: RefObject<HTMLElement>;
124
+ /** Accessible name for the dialog. Falls back to a string `title`. */
125
+ "aria-label"?: string;
126
+ testID?: string;
127
+ }
128
+ interface PopoverRootProps {
129
+ children: ReactNode;
130
+ /** Whether the popover is logically open — `false` runs the exit animation. */
131
+ open: boolean;
132
+ /** Called once the exit animation has finished so the parent can unmount. */
133
+ onExited: () => void;
134
+ /** Press handler for the scrim. Omit to make the scrim inert. */
135
+ onBackdropClick?: () => void;
136
+ /** Scrim colour, or `undefined` to render no scrim at all. */
137
+ scrimColor?: string;
138
+ /** Full-bleed layout for the `mobile` variant. */
139
+ fullScreen: boolean;
140
+ /** Absolute viewport offset — set once a draggable panel has been moved. */
141
+ position?: PopoverPosition;
142
+ animationDuration: number;
143
+ testID?: string;
144
+ }
145
+ interface PopoverTitleBarProps {
146
+ title?: ReactNode;
147
+ /** Renders the grab handle and wires it to `dragHandleProps`. */
148
+ draggable: boolean;
149
+ dragHandleProps?: PopoverDragHandleProps;
150
+ pinned?: boolean;
151
+ onPinnedChange?: (pinned: boolean) => void;
152
+ onClose?: () => void;
153
+ testID?: string;
154
+ }
155
+
156
+ /**
157
+ * Responsive overlay panel for player-facing surfaces — the container behind
158
+ * the Xsolla ID profile popover.
159
+ *
160
+ * On `desktop` and `tablet` it presents as a 400px floating panel over a
161
+ * scrim, optionally draggable by its title bar. On `mobile` the same content
162
+ * takes over the whole screen as a page. The bucket is measured from the
163
+ * viewport by `useDeviceType`; pass `device` only to override that.
164
+ *
165
+ * Everything inside is a slot — `titleBar`, `header`, `children`, `footer` —
166
+ * which is how the Figma `idPopover` composes its variants (the component set
167
+ * declares one property, `Device`; every other difference between the usage
168
+ * examples is different content in the same slots).
169
+ *
170
+ * ```tsx
171
+ * <Popover
172
+ * open={open}
173
+ * onClose={() => setOpen(false)}
174
+ * title="Profile"
175
+ * header={<Greeting />}
176
+ * footer={<SignOut />}
177
+ * >
178
+ * {sections}
179
+ * </Popover>
180
+ * ```
181
+ */
182
+ declare const Popover: react.ForwardRefExoticComponent<PopoverProps & react.RefAttributes<HTMLDivElement>>;
183
+
184
+ /**
185
+ * The floating title row from the Figma `idPopover` spec: grab handle, title,
186
+ * pin toggle, close button.
187
+ *
188
+ * `dragHandleProps` is attached to the whole row rather than just the grip, so
189
+ * the title text is draggable too. Presses that originate inside a `<button>`
190
+ * (pin, close) are filtered out by `usePopoverDrag`, and the grip stays
191
+ * focusable so the row can also be moved with the arrow keys.
192
+ */
193
+ declare const PopoverTitleBar: react.MemoExoticComponent<({ title, draggable, dragHandleProps, pinned, onPinnedChange, onClose, testID, }: PopoverTitleBarProps) => react_jsx_runtime.JSX.Element>;
194
+
195
+ interface UsePopoverOptions {
196
+ onOpen?: () => void;
197
+ onClose?: () => void;
198
+ }
199
+ interface UsePopoverReturn {
200
+ isOpen: boolean;
201
+ open: () => void;
202
+ close: () => void;
203
+ toggle: () => void;
204
+ }
205
+ /** Open/close state for a `Popover`, mirroring `useDrawer`. */
206
+ declare function usePopover(options?: UsePopoverOptions): UsePopoverReturn;
207
+
208
+ interface UsePopoverDragOptions {
209
+ /** Drag is a no-op while this is false (mobile, or `draggable={false}`). */
210
+ enabled: boolean;
211
+ /** Starting viewport offset. `undefined` leaves the panel centred. */
212
+ initialPosition?: PopoverPosition;
213
+ onPositionChange?: (position: PopoverPosition) => void;
214
+ }
215
+ interface UsePopoverDragReturn {
216
+ /** `undefined` until the panel has been positioned, so it stays centred. */
217
+ position?: PopoverPosition;
218
+ /** Attach to the panel so the hook can measure it for clamping. */
219
+ panelRef: RefObject<HTMLDivElement>;
220
+ /** Spread onto the element that starts a drag. */
221
+ dragHandleProps: PopoverDragHandleProps;
222
+ isDragging: boolean;
223
+ }
224
+ /**
225
+ * Pointer- and keyboard-driven repositioning for a floating popover panel.
226
+ *
227
+ * The panel stays in its centred flow position until the first drag, at which
228
+ * point the hook switches it to an absolute viewport offset. Positions are
229
+ * always clamped so at least `EDGE_MARGIN` of the panel stays on screen.
230
+ */
231
+ declare const usePopoverDrag: ({ enabled, initialPosition, onPositionChange, }: UsePopoverDragOptions) => UsePopoverDragReturn;
232
+
233
+ /**
234
+ * Viewport thresholds from the Figma "Breakpoints" frame
235
+ * (file `SOOtaT80JAVJf7PKlFnt7Q`, node `6393:1137`).
236
+ */
237
+ declare const POPOVER_BREAKPOINTS: {
238
+ /** Widths at or below this are `mobile` (Figma: "Mobile: 320-768px"). */
239
+ readonly mobileMax: 768;
240
+ /** Widths at or below this, but above `mobileMax`, are `tablet` (Figma: "Tablet: 769-1023px"). */
241
+ readonly tabletMax: 1023;
242
+ };
243
+ /** Maps a viewport width in CSS pixels onto a {@link PopoverDevice} bucket. */
244
+ declare const resolveDevice: (width: number) => PopoverDevice;
245
+ /**
246
+ * Resolves the active device bucket from the viewport width, re-resolving on
247
+ * resize. Pass `override` to short-circuit measurement entirely — the override
248
+ * is returned verbatim and no listener is attached.
249
+ *
250
+ * Server-side (no `window`) the hook reports `desktop`, which matches the
251
+ * Figma default variant, and corrects itself on the first client effect.
252
+ */
253
+ declare const useDeviceType: (override?: PopoverDevice) => PopoverDevice;
254
+
255
+ export { POPOVER_BREAKPOINTS, Popover, type PopoverDevice, type PopoverDragHandleProps, type PopoverPosition, type PopoverProps, type PopoverRootProps, PopoverTitleBar, type PopoverTitleBarProps, type UsePopoverDragOptions, type UsePopoverDragReturn, type UsePopoverOptions, type UsePopoverReturn, resolveDevice, useDeviceType, usePopover, usePopoverDrag };
@@ -0,0 +1,255 @@
1
+ import * as react from 'react';
2
+ import { ReactNode, CSSProperties, RefObject, PointerEvent, KeyboardEvent } from 'react';
3
+ import { ThemeOverrideProps } from '@xsolla/xui-core';
4
+ import * as react_jsx_runtime from 'react/jsx-runtime';
5
+
6
+ /**
7
+ * Device buckets from the Figma "Breakpoints" frame
8
+ * (file `SOOtaT80JAVJf7PKlFnt7Q`, node `6393:1137`):
9
+ *
10
+ * | Device | Viewport | Presentation |
11
+ * | ------- | ------------- | ------------------------------- |
12
+ * | Desktop | 1024px and up | 400px floating panel |
13
+ * | Tablet | 769–1023px | 400px floating panel |
14
+ * | Mobile | 320–768px | full-screen, reads as a page |
15
+ *
16
+ * Mirrors the `Device` variant on the Figma `idPopover` component set
17
+ * (node `7394:4832`), whose options are Desktop (default), Tablet, Mobile.
18
+ */
19
+ type PopoverDevice = "desktop" | "tablet" | "mobile";
20
+ /** Viewport-relative offset of the floating panel's top-left corner. */
21
+ interface PopoverPosition {
22
+ x: number;
23
+ y: number;
24
+ }
25
+ /** Handlers that turn an element into a drag grip for the floating panel. */
26
+ interface PopoverDragHandleProps {
27
+ onPointerDown: (event: PointerEvent) => void;
28
+ onKeyDown: (event: KeyboardEvent) => void;
29
+ }
30
+ interface PopoverProps extends ThemeOverrideProps {
31
+ /** Whether the popover is open. */
32
+ open?: boolean;
33
+ /** Called when the popover should close (Escape, scrim press, close button). */
34
+ onClose?: () => void;
35
+ /**
36
+ * Forces a device bucket instead of measuring the viewport. Useful for
37
+ * Storybook, tests, and product shells that already know their layout.
38
+ * Omit it and `useDeviceType` resolves the bucket from `window.innerWidth`.
39
+ */
40
+ device?: PopoverDevice;
41
+ /**
42
+ * Panel width on `desktop` / `tablet`. Ignored on `mobile`, which fills the
43
+ * viewport.
44
+ * @default 400
45
+ */
46
+ width?: number | string;
47
+ /**
48
+ * Renders the grab handle in the title bar and lets the user reposition the
49
+ * panel. Ignored on `mobile` — per the Figma spec, "Buttons for floating […]
50
+ * Don't use it in other cases and on mobile."
51
+ * @default false
52
+ */
53
+ draggable?: boolean;
54
+ /**
55
+ * Starting viewport offset for a `draggable` panel. Omit to let the panel
56
+ * centre itself until the first drag.
57
+ */
58
+ initialPosition?: PopoverPosition;
59
+ /** Called on every drag frame with the panel's new viewport offset. */
60
+ onPositionChange?: (position: PopoverPosition) => void;
61
+ /** Title shown in the default title bar, to the right of the grab handle. */
62
+ title?: ReactNode;
63
+ /**
64
+ * Whether the popover is pinned. Pinning shows the pin control in its active
65
+ * state and suppresses scrim dismissal. Controlled — the control only renders
66
+ * when `onPinnedChange` is supplied.
67
+ */
68
+ pinned?: boolean;
69
+ /** Called with the next pinned state when the pin control is pressed. */
70
+ onPinnedChange?: (pinned: boolean) => void;
71
+ /**
72
+ * Renders the close (X) control in the default title bar. Set it to `false`
73
+ * for the Figma "No buttons" variant, which has no chrome at all — `onClose`
74
+ * still runs on Escape and on a scrim press, so the popover stays
75
+ * dismissible.
76
+ * @default true
77
+ */
78
+ showCloseButton?: boolean;
79
+ /**
80
+ * Replaces the whole default title bar (grab handle, title, pin, close).
81
+ * You own the grab handle in this case — put `data-xui-popover-drag-handle`
82
+ * on the element that should accept arrow-key nudges.
83
+ */
84
+ titleBar?: ReactNode;
85
+ /**
86
+ * Content pinned above the scrollable body — the logo row, hero image, and
87
+ * greeting in the Xsolla ID profile popover.
88
+ */
89
+ header?: ReactNode;
90
+ /** Scrollable body content. */
91
+ children: ReactNode;
92
+ /** Content pinned below the scrollable body — sign-out button, legal links. */
93
+ footer?: ReactNode;
94
+ /**
95
+ * Whether pressing the scrim closes the popover. Always disabled while
96
+ * `pinned`, and on `mobile`, where a full-screen page has no outside.
97
+ * @default true
98
+ */
99
+ closeOnOverlayClick?: boolean;
100
+ /** Whether pressing Escape closes the popover. @default true */
101
+ closeOnEscape?: boolean;
102
+ /**
103
+ * Renders the dimming scrim behind the panel. Turn it off for a floating
104
+ * panel that should leave the page underneath usable — that is the
105
+ * "Float buttons for desktop" case in the Figma spec.
106
+ * @default true
107
+ */
108
+ scrim?: boolean;
109
+ /**
110
+ * Surface background. Accepts any theme background token or a CSS colour.
111
+ * @default theme.colors.background.primary
112
+ */
113
+ backgroundColor?: string;
114
+ /**
115
+ * Applies the 24px backdrop blur from the Figma `boxShadow&BlurPopover`
116
+ * effect style. Ignored on `mobile`.
117
+ * @default true
118
+ */
119
+ blur?: boolean;
120
+ /** Extra styles merged onto the panel. */
121
+ styled?: CSSProperties;
122
+ /** Element focused when the popover opens. Defaults to the first focusable. */
123
+ initialFocusRef?: RefObject<HTMLElement>;
124
+ /** Accessible name for the dialog. Falls back to a string `title`. */
125
+ "aria-label"?: string;
126
+ testID?: string;
127
+ }
128
+ interface PopoverRootProps {
129
+ children: ReactNode;
130
+ /** Whether the popover is logically open — `false` runs the exit animation. */
131
+ open: boolean;
132
+ /** Called once the exit animation has finished so the parent can unmount. */
133
+ onExited: () => void;
134
+ /** Press handler for the scrim. Omit to make the scrim inert. */
135
+ onBackdropClick?: () => void;
136
+ /** Scrim colour, or `undefined` to render no scrim at all. */
137
+ scrimColor?: string;
138
+ /** Full-bleed layout for the `mobile` variant. */
139
+ fullScreen: boolean;
140
+ /** Absolute viewport offset — set once a draggable panel has been moved. */
141
+ position?: PopoverPosition;
142
+ animationDuration: number;
143
+ testID?: string;
144
+ }
145
+ interface PopoverTitleBarProps {
146
+ title?: ReactNode;
147
+ /** Renders the grab handle and wires it to `dragHandleProps`. */
148
+ draggable: boolean;
149
+ dragHandleProps?: PopoverDragHandleProps;
150
+ pinned?: boolean;
151
+ onPinnedChange?: (pinned: boolean) => void;
152
+ onClose?: () => void;
153
+ testID?: string;
154
+ }
155
+
156
+ /**
157
+ * Responsive overlay panel for player-facing surfaces — the container behind
158
+ * the Xsolla ID profile popover.
159
+ *
160
+ * On `desktop` and `tablet` it presents as a 400px floating panel over a
161
+ * scrim, optionally draggable by its title bar. On `mobile` the same content
162
+ * takes over the whole screen as a page. The bucket is measured from the
163
+ * viewport by `useDeviceType`; pass `device` only to override that.
164
+ *
165
+ * Everything inside is a slot — `titleBar`, `header`, `children`, `footer` —
166
+ * which is how the Figma `idPopover` composes its variants (the component set
167
+ * declares one property, `Device`; every other difference between the usage
168
+ * examples is different content in the same slots).
169
+ *
170
+ * ```tsx
171
+ * <Popover
172
+ * open={open}
173
+ * onClose={() => setOpen(false)}
174
+ * title="Profile"
175
+ * header={<Greeting />}
176
+ * footer={<SignOut />}
177
+ * >
178
+ * {sections}
179
+ * </Popover>
180
+ * ```
181
+ */
182
+ declare const Popover: react.ForwardRefExoticComponent<PopoverProps & react.RefAttributes<HTMLDivElement>>;
183
+
184
+ /**
185
+ * The floating title row from the Figma `idPopover` spec: grab handle, title,
186
+ * pin toggle, close button.
187
+ *
188
+ * `dragHandleProps` is attached to the whole row rather than just the grip, so
189
+ * the title text is draggable too. Presses that originate inside a `<button>`
190
+ * (pin, close) are filtered out by `usePopoverDrag`, and the grip stays
191
+ * focusable so the row can also be moved with the arrow keys.
192
+ */
193
+ declare const PopoverTitleBar: react.MemoExoticComponent<({ title, draggable, dragHandleProps, pinned, onPinnedChange, onClose, testID, }: PopoverTitleBarProps) => react_jsx_runtime.JSX.Element>;
194
+
195
+ interface UsePopoverOptions {
196
+ onOpen?: () => void;
197
+ onClose?: () => void;
198
+ }
199
+ interface UsePopoverReturn {
200
+ isOpen: boolean;
201
+ open: () => void;
202
+ close: () => void;
203
+ toggle: () => void;
204
+ }
205
+ /** Open/close state for a `Popover`, mirroring `useDrawer`. */
206
+ declare function usePopover(options?: UsePopoverOptions): UsePopoverReturn;
207
+
208
+ interface UsePopoverDragOptions {
209
+ /** Drag is a no-op while this is false (mobile, or `draggable={false}`). */
210
+ enabled: boolean;
211
+ /** Starting viewport offset. `undefined` leaves the panel centred. */
212
+ initialPosition?: PopoverPosition;
213
+ onPositionChange?: (position: PopoverPosition) => void;
214
+ }
215
+ interface UsePopoverDragReturn {
216
+ /** `undefined` until the panel has been positioned, so it stays centred. */
217
+ position?: PopoverPosition;
218
+ /** Attach to the panel so the hook can measure it for clamping. */
219
+ panelRef: RefObject<HTMLDivElement>;
220
+ /** Spread onto the element that starts a drag. */
221
+ dragHandleProps: PopoverDragHandleProps;
222
+ isDragging: boolean;
223
+ }
224
+ /**
225
+ * Pointer- and keyboard-driven repositioning for a floating popover panel.
226
+ *
227
+ * The panel stays in its centred flow position until the first drag, at which
228
+ * point the hook switches it to an absolute viewport offset. Positions are
229
+ * always clamped so at least `EDGE_MARGIN` of the panel stays on screen.
230
+ */
231
+ declare const usePopoverDrag: ({ enabled, initialPosition, onPositionChange, }: UsePopoverDragOptions) => UsePopoverDragReturn;
232
+
233
+ /**
234
+ * Viewport thresholds from the Figma "Breakpoints" frame
235
+ * (file `SOOtaT80JAVJf7PKlFnt7Q`, node `6393:1137`).
236
+ */
237
+ declare const POPOVER_BREAKPOINTS: {
238
+ /** Widths at or below this are `mobile` (Figma: "Mobile: 320-768px"). */
239
+ readonly mobileMax: 768;
240
+ /** Widths at or below this, but above `mobileMax`, are `tablet` (Figma: "Tablet: 769-1023px"). */
241
+ readonly tabletMax: 1023;
242
+ };
243
+ /** Maps a viewport width in CSS pixels onto a {@link PopoverDevice} bucket. */
244
+ declare const resolveDevice: (width: number) => PopoverDevice;
245
+ /**
246
+ * Resolves the active device bucket from the viewport width, re-resolving on
247
+ * resize. Pass `override` to short-circuit measurement entirely — the override
248
+ * is returned verbatim and no listener is attached.
249
+ *
250
+ * Server-side (no `window`) the hook reports `desktop`, which matches the
251
+ * Figma default variant, and corrects itself on the first client effect.
252
+ */
253
+ declare const useDeviceType: (override?: PopoverDevice) => PopoverDevice;
254
+
255
+ export { POPOVER_BREAKPOINTS, Popover, type PopoverDevice, type PopoverDragHandleProps, type PopoverPosition, type PopoverProps, type PopoverRootProps, PopoverTitleBar, type PopoverTitleBarProps, type UsePopoverDragOptions, type UsePopoverDragReturn, type UsePopoverOptions, type UsePopoverReturn, resolveDevice, useDeviceType, usePopover, usePopoverDrag };