@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 +22 -0
- package/native/index.d.mts +255 -0
- package/native/index.d.ts +255 -0
- package/native/index.js +712 -0
- package/native/index.js.map +1 -0
- package/native/index.mjs +688 -0
- package/native/index.mjs.map +1 -0
- package/package.json +60 -0
- package/web/index.d.mts +255 -0
- package/web/index.d.ts +255 -0
- package/web/index.js +842 -0
- package/web/index.js.map +1 -0
- package/web/index.mjs +808 -0
- package/web/index.mjs.map +1 -0
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 };
|