@xsolla/xui-modal 0.158.0 → 0.159.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 +108 -81
- package/native/index.d.mts +9 -1
- package/native/index.d.ts +9 -1
- package/native/index.js +22 -14
- package/native/index.js.map +1 -1
- package/native/index.mjs +23 -15
- package/native/index.mjs.map +1 -1
- package/package.json +5 -5
- package/web/index.d.mts +9 -1
- package/web/index.d.ts +9 -1
- package/web/index.js +19 -12
- package/web/index.js.map +1 -1
- package/web/index.mjs +20 -13
- package/web/index.mjs.map +1 -1
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
type ModalVariant,
|
|
24
24
|
type WorkAreaProps,
|
|
25
25
|
type WorkAreaSize,
|
|
26
|
-
} from
|
|
26
|
+
} from "@xsolla/xui-modal";
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
`useModalId` is re-exported from `@xsolla/xui-core` and is consumed by portaled descendants (e.g. `Select`, `Dropdown`) so click-outside detection ignores content that logically belongs to the modal.
|
|
@@ -31,9 +31,9 @@ import {
|
|
|
31
31
|
## Quick start
|
|
32
32
|
|
|
33
33
|
```tsx
|
|
34
|
-
import * as React from
|
|
35
|
-
import { Modal, ModalProvider, useModal } from
|
|
36
|
-
import { Button } from
|
|
34
|
+
import * as React from "react";
|
|
35
|
+
import { Modal, ModalProvider, useModal } from "@xsolla/xui-modal";
|
|
36
|
+
import { Button } from "@xsolla/xui-button";
|
|
37
37
|
|
|
38
38
|
function Trigger() {
|
|
39
39
|
const [open, close] = useModal(() => (
|
|
@@ -60,56 +60,57 @@ export default function QuickStart() {
|
|
|
60
60
|
|
|
61
61
|
The dialog component with header, body, and footer zones. Accepts a `ref` forwarded to the inner `WorkArea`. Unknown props are spread onto the root `Box`. `size` is a typed `ModalProps` field but is never consumed by `Modal`'s internal layout; it passes through via `...rest` to the root `Box` with no built-in styling effect.
|
|
62
62
|
|
|
63
|
-
| Prop
|
|
64
|
-
|
|
|
65
|
-
| `
|
|
66
|
-
| `
|
|
67
|
-
| `
|
|
68
|
-
| `
|
|
69
|
-
| `
|
|
70
|
-
| `
|
|
71
|
-
| `
|
|
72
|
-
| `
|
|
73
|
-
| `
|
|
74
|
-
| `
|
|
75
|
-
| `
|
|
76
|
-
| `
|
|
77
|
-
| `
|
|
78
|
-
| `
|
|
79
|
-
| `aria-
|
|
80
|
-
| `
|
|
63
|
+
| Prop | Type | Default | Description |
|
|
64
|
+
| ------------------ | -------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
65
|
+
| `testID` | `string` | — | Test ID for testing frameworks. On web this renders as `data-testid`; on React Native it renders as `testID`. |
|
|
66
|
+
| `children` | `ReactNode` | — | **Required.** Modal body content. |
|
|
67
|
+
| `type` | `"popup" \| "bottom-sheet" \| "full-screen"` | `"popup"` | Presentation type. Drives positioning, border-radius, and shadow. |
|
|
68
|
+
| `align` | `"left" \| "center"` | `"left"` | Content alignment within the body. |
|
|
69
|
+
| `onClose` | `() => void` | — | Close callback. When provided, renders a close (X) button and enables Escape and click-outside dismissal. |
|
|
70
|
+
| `onBack` | `() => void` | — | Back callback. Renders a chevron-left button on the left of the header. |
|
|
71
|
+
| `header` | `ReactNode` | — | Custom header — replaces the default back/close row. |
|
|
72
|
+
| `footer` | `ReactNode` | — | Footer content rendered below children. |
|
|
73
|
+
| `openContent` | `boolean` | `false` | Removes inner padding so children fill edge-to-edge. |
|
|
74
|
+
| `closeOutside` | `boolean` | `true` | Whether clicking outside closes the modal (requires `onClose`). |
|
|
75
|
+
| `maxWidth` | `string \| number` | `680` | Forced to `100%` for `bottom-sheet` and `full-screen`. |
|
|
76
|
+
| `minHeight` | `string \| number` | — | Minimum height of the modal. |
|
|
77
|
+
| `styled` | `CSSProperties` | — | Inline overrides on the modal container. |
|
|
78
|
+
| `title` | `string` | — | Visually hidden accessible title — drives `aria-labelledby`. For a visible heading, render it inside `children` or pass a custom `header`. |
|
|
79
|
+
| `aria-label` | `string` | — | Alternative accessible name when `title` is not used. |
|
|
80
|
+
| `aria-describedby` | `string` | — | ID of an element describing modal content. |
|
|
81
|
+
| `initialFocusRef` | `RefObject<HTMLElement>` | — | Element to focus on open. Falls back to the close button, then the first focusable child. |
|
|
81
82
|
|
|
82
83
|
Inherits `ThemeOverrideProps` (`themeMode`, `themeProductContext`).
|
|
83
84
|
|
|
84
85
|
### Modal types
|
|
85
86
|
|
|
86
|
-
| Type
|
|
87
|
-
|
|
|
88
|
-
| `popup` (default) | Centred in the overlay | All corners
|
|
89
|
-
| `bottom-sheet`
|
|
90
|
-
| `full-screen`
|
|
87
|
+
| Type | Positioning | Border radius | Shadow | Max width |
|
|
88
|
+
| ----------------- | ---------------------- | ---------------- | ------ | ------------------- |
|
|
89
|
+
| `popup` (default) | Centred in the overlay | All corners | Yes | `680px` (or custom) |
|
|
90
|
+
| `bottom-sheet` | Anchored to the bottom | Top corners only | Yes | `100%` (forced) |
|
|
91
|
+
| `full-screen` | Fills the viewport | `0` | None | `100%` (forced) |
|
|
91
92
|
|
|
92
93
|
### `<ModalProvider>`
|
|
93
94
|
|
|
94
95
|
Wraps your app, manages the open-modal stack, and renders `ModalRoot`.
|
|
95
96
|
|
|
96
|
-
| Prop
|
|
97
|
-
|
|
|
97
|
+
| Prop | Type | Description |
|
|
98
|
+
| ---------- | ----------- | ---------------------------------- |
|
|
98
99
|
| `children` | `ReactNode` | **Required.** Application content. |
|
|
99
100
|
|
|
100
101
|
### `<WorkArea>`
|
|
101
102
|
|
|
102
103
|
Internal chrome used by `Modal`. Can be rendered standalone for custom layouts.
|
|
103
104
|
|
|
104
|
-
| Prop
|
|
105
|
-
|
|
|
106
|
-
| `children`
|
|
107
|
-
| `type`
|
|
108
|
-
| `align`
|
|
109
|
-
| `indent`
|
|
110
|
-
| `stretched`
|
|
111
|
-
| `openContent` | `boolean`
|
|
112
|
-
| `fetching`
|
|
105
|
+
| Prop | Type | Default | Description |
|
|
106
|
+
| ------------- | -------------------------------------------- | --------- | --------------------------------------------------- |
|
|
107
|
+
| `children` | `ReactNode` | — | **Required.** Content. |
|
|
108
|
+
| `type` | `"popup" \| "bottom-sheet" \| "full-screen"` | `"popup"` | Affects border-radius and shadow. |
|
|
109
|
+
| `align` | `"left" \| "center"` | — | Content alignment. |
|
|
110
|
+
| `indent` | `"sm" \| "md" \| "lg"` | — | Padding hint passed alongside the work-area sizing. |
|
|
111
|
+
| `stretched` | `boolean` | `false` | Stretch to full height. |
|
|
112
|
+
| `openContent` | `boolean` | `false` | Edge-to-edge mode. |
|
|
113
|
+
| `fetching` | `boolean` | `false` | Renders a loading placeholder when `true`. |
|
|
113
114
|
|
|
114
115
|
Inherits `ThemeOverrideProps` (`themeMode`, `themeProductContext`).
|
|
115
116
|
|
|
@@ -133,26 +134,26 @@ The raw React context. Most apps consume `useModal`, but advanced cases can call
|
|
|
133
134
|
|
|
134
135
|
### Exported types
|
|
135
136
|
|
|
136
|
-
| Type
|
|
137
|
-
|
|
|
138
|
-
| `ModalProps`
|
|
139
|
-
| `ModalSize`
|
|
140
|
-
| `ModalVariant`
|
|
141
|
-
| `ModalType`
|
|
142
|
-
| `ModalContextType`
|
|
143
|
-
| `ModalProviderProps` | Props for `<ModalProvider>`.
|
|
144
|
-
| `ModalRootProps`
|
|
145
|
-
| `WorkAreaProps`
|
|
146
|
-
| `WorkAreaSize`
|
|
137
|
+
| Type | Members |
|
|
138
|
+
| -------------------- | ------------------------------------------------------------ |
|
|
139
|
+
| `ModalProps` | Props for `<Modal>`. |
|
|
140
|
+
| `ModalSize` | `"sm" \| "md" \| "lg"` |
|
|
141
|
+
| `ModalVariant` | `"popup" \| "bottom-sheet" \| "full-screen"` |
|
|
142
|
+
| `ModalType` | `(props: any) => ReactNode` — the render function signature. |
|
|
143
|
+
| `ModalContextType` | `{ onOpenModal, onCloseModal }` |
|
|
144
|
+
| `ModalProviderProps` | Props for `<ModalProvider>`. |
|
|
145
|
+
| `ModalRootProps` | Props for the internal root. |
|
|
146
|
+
| `WorkAreaProps` | Props for `<WorkArea>`. |
|
|
147
|
+
| `WorkAreaSize` | `"sm" \| "md" \| "lg"` |
|
|
147
148
|
|
|
148
149
|
## Examples
|
|
149
150
|
|
|
150
151
|
### Modal types
|
|
151
152
|
|
|
152
153
|
```tsx
|
|
153
|
-
import * as React from
|
|
154
|
-
import { Modal, ModalProvider, useModal } from
|
|
155
|
-
import { Button } from
|
|
154
|
+
import * as React from "react";
|
|
155
|
+
import { Modal, ModalProvider, useModal } from "@xsolla/xui-modal";
|
|
156
|
+
import { Button } from "@xsolla/xui-button";
|
|
156
157
|
|
|
157
158
|
function Demo() {
|
|
158
159
|
const [openPopup, closePopup] = useModal(() => (
|
|
@@ -171,7 +172,7 @@ function Demo() {
|
|
|
171
172
|
</Modal>
|
|
172
173
|
));
|
|
173
174
|
return (
|
|
174
|
-
<div style={{ display:
|
|
175
|
+
<div style={{ display: "flex", gap: 12 }}>
|
|
175
176
|
<Button onPress={openPopup}>Popup</Button>
|
|
176
177
|
<Button onPress={openSheet}>Bottom sheet</Button>
|
|
177
178
|
<Button onPress={openFull}>Full screen</Button>
|
|
@@ -191,9 +192,9 @@ export default function Example() {
|
|
|
191
192
|
### Confirmation dialog
|
|
192
193
|
|
|
193
194
|
```tsx
|
|
194
|
-
import * as React from
|
|
195
|
-
import { Modal, ModalProvider, useModal } from
|
|
196
|
-
import { Button, ButtonGroup } from
|
|
195
|
+
import * as React from "react";
|
|
196
|
+
import { Modal, ModalProvider, useModal } from "@xsolla/xui-modal";
|
|
197
|
+
import { Button, ButtonGroup } from "@xsolla/xui-button";
|
|
197
198
|
|
|
198
199
|
function ConfirmTrigger() {
|
|
199
200
|
const [confirmed, setConfirmed] = React.useState(false);
|
|
@@ -205,8 +206,18 @@ function ConfirmTrigger() {
|
|
|
205
206
|
title="Delete item?"
|
|
206
207
|
footer={
|
|
207
208
|
<ButtonGroup orientation="horizontal" size="xl">
|
|
208
|
-
<Button variant="secondary" tone="mono" onPress={close}>
|
|
209
|
-
|
|
209
|
+
<Button variant="secondary" tone="mono" onPress={close}>
|
|
210
|
+
Cancel
|
|
211
|
+
</Button>
|
|
212
|
+
<Button
|
|
213
|
+
tone="alert"
|
|
214
|
+
onPress={() => {
|
|
215
|
+
setConfirmed(true);
|
|
216
|
+
close();
|
|
217
|
+
}}
|
|
218
|
+
>
|
|
219
|
+
Delete
|
|
220
|
+
</Button>
|
|
210
221
|
</ButtonGroup>
|
|
211
222
|
}
|
|
212
223
|
>
|
|
@@ -216,7 +227,9 @@ function ConfirmTrigger() {
|
|
|
216
227
|
|
|
217
228
|
return (
|
|
218
229
|
<div>
|
|
219
|
-
<Button tone="alert" onPress={open}>
|
|
230
|
+
<Button tone="alert" onPress={open}>
|
|
231
|
+
Delete
|
|
232
|
+
</Button>
|
|
220
233
|
{confirmed && <p>Deleted.</p>}
|
|
221
234
|
</div>
|
|
222
235
|
);
|
|
@@ -234,15 +247,18 @@ export default function ConfirmDialog() {
|
|
|
234
247
|
### Multi-step modal
|
|
235
248
|
|
|
236
249
|
```tsx
|
|
237
|
-
import * as React from
|
|
238
|
-
import { Modal, ModalProvider, useModal } from
|
|
239
|
-
import { Button } from
|
|
250
|
+
import * as React from "react";
|
|
251
|
+
import { Modal, ModalProvider, useModal } from "@xsolla/xui-modal";
|
|
252
|
+
import { Button } from "@xsolla/xui-button";
|
|
240
253
|
|
|
241
254
|
function MultiStep() {
|
|
242
255
|
const [step, setStep] = React.useState(1);
|
|
243
256
|
const [open, close] = useModal(() => (
|
|
244
257
|
<Modal
|
|
245
|
-
onClose={() => {
|
|
258
|
+
onClose={() => {
|
|
259
|
+
setStep(1);
|
|
260
|
+
close();
|
|
261
|
+
}}
|
|
246
262
|
onBack={step > 1 ? () => setStep((s) => s - 1) : undefined}
|
|
247
263
|
title={`Step ${step} of 3`}
|
|
248
264
|
>
|
|
@@ -250,7 +266,14 @@ function MultiStep() {
|
|
|
250
266
|
{step < 3 ? (
|
|
251
267
|
<Button onPress={() => setStep((s) => s + 1)}>Next</Button>
|
|
252
268
|
) : (
|
|
253
|
-
<Button
|
|
269
|
+
<Button
|
|
270
|
+
onPress={() => {
|
|
271
|
+
setStep(1);
|
|
272
|
+
close();
|
|
273
|
+
}}
|
|
274
|
+
>
|
|
275
|
+
Finish
|
|
276
|
+
</Button>
|
|
254
277
|
)}
|
|
255
278
|
</Modal>
|
|
256
279
|
));
|
|
@@ -269,14 +292,18 @@ export default function MultiStepExample() {
|
|
|
269
292
|
### Edge-to-edge content
|
|
270
293
|
|
|
271
294
|
```tsx
|
|
272
|
-
import * as React from
|
|
273
|
-
import { Modal, ModalProvider, useModal } from
|
|
274
|
-
import { Button } from
|
|
295
|
+
import * as React from "react";
|
|
296
|
+
import { Modal, ModalProvider, useModal } from "@xsolla/xui-modal";
|
|
297
|
+
import { Button } from "@xsolla/xui-button";
|
|
275
298
|
|
|
276
299
|
function HeroTrigger() {
|
|
277
300
|
const [open, close] = useModal(() => (
|
|
278
301
|
<Modal openContent onClose={close} title="Gallery">
|
|
279
|
-
<img
|
|
302
|
+
<img
|
|
303
|
+
src="/hero-image.jpg"
|
|
304
|
+
alt="Hero"
|
|
305
|
+
style={{ width: "100%", display: "block" }}
|
|
306
|
+
/>
|
|
280
307
|
</Modal>
|
|
281
308
|
));
|
|
282
309
|
return <Button onPress={open}>Open hero</Button>;
|
|
@@ -293,23 +320,23 @@ export default function EdgeToEdge() {
|
|
|
293
320
|
|
|
294
321
|
## Platform Support
|
|
295
322
|
|
|
296
|
-
| Feature
|
|
297
|
-
|
|
|
298
|
-
| Provider
|
|
299
|
-
| Hook
|
|
300
|
-
| Overlay
|
|
301
|
-
| Focus trap
|
|
302
|
-
| Escape key
|
|
303
|
-
| Click outside | Dismisses when `closeOutside={true}`
|
|
323
|
+
| Feature | Web | React Native |
|
|
324
|
+
| ------------- | ----------------------------------------- | ---------------------------------------------- |
|
|
325
|
+
| Provider | `ModalProvider` (with `ModalRoot` portal) | `ModalProvider` (root is a no-op stub) |
|
|
326
|
+
| Hook | `useModal()` → `[open, close]` | Same signature; provider stack does not render |
|
|
327
|
+
| Overlay | Fixed-positioned backdrop | N/A |
|
|
328
|
+
| Focus trap | Keyboard Tab trapping | N/A |
|
|
329
|
+
| Escape key | Closes modal | N/A |
|
|
330
|
+
| Click outside | Dismisses when `closeOutside={true}` | N/A |
|
|
304
331
|
|
|
305
332
|
## Keyboard Interaction
|
|
306
333
|
|
|
307
|
-
| Key
|
|
308
|
-
|
|
|
309
|
-
| `Escape`
|
|
310
|
-
| `Tab`
|
|
334
|
+
| Key | Action |
|
|
335
|
+
| ------------- | -------------------------------------------------------- |
|
|
336
|
+
| `Escape` | Closes the modal (when `onClose` is provided). |
|
|
337
|
+
| `Tab` | Moves focus to the next focusable element (trapped). |
|
|
311
338
|
| `Shift + Tab` | Moves focus to the previous focusable element (trapped). |
|
|
312
|
-
| `Enter`
|
|
339
|
+
| `Enter` | Activates the focused button. |
|
|
313
340
|
|
|
314
341
|
## Accessibility
|
|
315
342
|
|
package/native/index.d.mts
CHANGED
|
@@ -33,6 +33,8 @@ interface ModalProps extends ThemeOverrideProps {
|
|
|
33
33
|
"aria-describedby"?: string;
|
|
34
34
|
/** Ref to element that should receive focus when modal opens */
|
|
35
35
|
initialFocusRef?: RefObject<HTMLElement>;
|
|
36
|
+
/** Test ID for testing frameworks */
|
|
37
|
+
testID?: string;
|
|
36
38
|
}
|
|
37
39
|
type ModalType = (props: any) => ReactNode;
|
|
38
40
|
interface ModalContextType {
|
|
@@ -41,9 +43,13 @@ interface ModalContextType {
|
|
|
41
43
|
}
|
|
42
44
|
interface ModalProviderProps {
|
|
43
45
|
children: ReactNode;
|
|
46
|
+
/** Test ID for testing frameworks */
|
|
47
|
+
testID?: string;
|
|
44
48
|
}
|
|
45
49
|
interface ModalRootProps {
|
|
46
50
|
modals: Record<string, ModalType>;
|
|
51
|
+
/** Test ID for testing frameworks */
|
|
52
|
+
testID?: string;
|
|
47
53
|
}
|
|
48
54
|
type WorkAreaSize = "sm" | "md" | "lg";
|
|
49
55
|
interface WorkAreaProps extends ThemeOverrideProps {
|
|
@@ -56,11 +62,13 @@ interface WorkAreaProps extends ThemeOverrideProps {
|
|
|
56
62
|
type?: ModalVariant;
|
|
57
63
|
/** Content alignment */
|
|
58
64
|
align?: "left" | "center";
|
|
65
|
+
/** Test ID for testing frameworks */
|
|
66
|
+
testID?: string;
|
|
59
67
|
}
|
|
60
68
|
|
|
61
69
|
declare const Modal: react.ForwardRefExoticComponent<ModalProps & react.RefAttributes<any>>;
|
|
62
70
|
|
|
63
|
-
declare const ModalProvider: ({ children }: ModalProviderProps) => react_jsx_runtime.JSX.Element;
|
|
71
|
+
declare const ModalProvider: ({ children, testID }: ModalProviderProps) => react_jsx_runtime.JSX.Element;
|
|
64
72
|
|
|
65
73
|
declare const useModal: (modal: ModalType) => [() => void, () => void];
|
|
66
74
|
|
package/native/index.d.ts
CHANGED
|
@@ -33,6 +33,8 @@ interface ModalProps extends ThemeOverrideProps {
|
|
|
33
33
|
"aria-describedby"?: string;
|
|
34
34
|
/** Ref to element that should receive focus when modal opens */
|
|
35
35
|
initialFocusRef?: RefObject<HTMLElement>;
|
|
36
|
+
/** Test ID for testing frameworks */
|
|
37
|
+
testID?: string;
|
|
36
38
|
}
|
|
37
39
|
type ModalType = (props: any) => ReactNode;
|
|
38
40
|
interface ModalContextType {
|
|
@@ -41,9 +43,13 @@ interface ModalContextType {
|
|
|
41
43
|
}
|
|
42
44
|
interface ModalProviderProps {
|
|
43
45
|
children: ReactNode;
|
|
46
|
+
/** Test ID for testing frameworks */
|
|
47
|
+
testID?: string;
|
|
44
48
|
}
|
|
45
49
|
interface ModalRootProps {
|
|
46
50
|
modals: Record<string, ModalType>;
|
|
51
|
+
/** Test ID for testing frameworks */
|
|
52
|
+
testID?: string;
|
|
47
53
|
}
|
|
48
54
|
type WorkAreaSize = "sm" | "md" | "lg";
|
|
49
55
|
interface WorkAreaProps extends ThemeOverrideProps {
|
|
@@ -56,11 +62,13 @@ interface WorkAreaProps extends ThemeOverrideProps {
|
|
|
56
62
|
type?: ModalVariant;
|
|
57
63
|
/** Content alignment */
|
|
58
64
|
align?: "left" | "center";
|
|
65
|
+
/** Test ID for testing frameworks */
|
|
66
|
+
testID?: string;
|
|
59
67
|
}
|
|
60
68
|
|
|
61
69
|
declare const Modal: react.ForwardRefExoticComponent<ModalProps & react.RefAttributes<any>>;
|
|
62
70
|
|
|
63
|
-
declare const ModalProvider: ({ children }: ModalProviderProps) => react_jsx_runtime.JSX.Element;
|
|
71
|
+
declare const ModalProvider: ({ children, testID }: ModalProviderProps) => react_jsx_runtime.JSX.Element;
|
|
64
72
|
|
|
65
73
|
declare const useModal: (modal: ModalType) => [() => void, () => void];
|
|
66
74
|
|
package/native/index.js
CHANGED
|
@@ -232,6 +232,7 @@ var WorkArea = (0, import_react.forwardRef)(
|
|
|
232
232
|
fetching = false,
|
|
233
233
|
type = "popup",
|
|
234
234
|
align,
|
|
235
|
+
testID,
|
|
235
236
|
themeMode,
|
|
236
237
|
themeProductContext
|
|
237
238
|
}, ref) => {
|
|
@@ -241,6 +242,7 @@ var WorkArea = (0, import_react.forwardRef)(
|
|
|
241
242
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
242
243
|
Box,
|
|
243
244
|
{
|
|
245
|
+
testID,
|
|
244
246
|
ref,
|
|
245
247
|
backgroundColor: theme.colors.background.primary,
|
|
246
248
|
width: "100%",
|
|
@@ -309,6 +311,7 @@ var Modal = (0, import_react2.forwardRef)(
|
|
|
309
311
|
"aria-label": ariaLabel,
|
|
310
312
|
"aria-describedby": ariaDescribedBy,
|
|
311
313
|
initialFocusRef,
|
|
314
|
+
testID,
|
|
312
315
|
themeMode,
|
|
313
316
|
themeProductContext,
|
|
314
317
|
...rest
|
|
@@ -395,6 +398,7 @@ var Modal = (0, import_react2.forwardRef)(
|
|
|
395
398
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
396
399
|
Box,
|
|
397
400
|
{
|
|
401
|
+
testID,
|
|
398
402
|
ref: modalRef,
|
|
399
403
|
role: "dialog",
|
|
400
404
|
"aria-modal": "true",
|
|
@@ -453,14 +457,14 @@ var Modal = (0, import_react2.forwardRef)(
|
|
|
453
457
|
style: { flexShrink: 0 },
|
|
454
458
|
children: header ?? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
455
459
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box, { style: { minWidth: 36 }, children: onBack && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
456
|
-
import_xui_button.
|
|
460
|
+
import_xui_button.IconButton,
|
|
457
461
|
{
|
|
458
462
|
variant: "secondary",
|
|
463
|
+
tone: "mono",
|
|
459
464
|
size: sizing.headerButtonSize,
|
|
460
|
-
|
|
465
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_xui_icons_base.ChevronLeft, {}),
|
|
461
466
|
onPress: onBack,
|
|
462
|
-
"aria-label": "Go back"
|
|
463
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_xui_icons_base.ChevronLeft, {})
|
|
467
|
+
"aria-label": "Go back"
|
|
464
468
|
}
|
|
465
469
|
) }),
|
|
466
470
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
@@ -470,14 +474,14 @@ var Modal = (0, import_react2.forwardRef)(
|
|
|
470
474
|
style: { minWidth: 36 },
|
|
471
475
|
alignItems: "flex-end",
|
|
472
476
|
children: onClose && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
473
|
-
import_xui_button.
|
|
477
|
+
import_xui_button.IconButton,
|
|
474
478
|
{
|
|
475
479
|
variant: "secondary",
|
|
480
|
+
tone: "mono",
|
|
476
481
|
size: sizing.headerButtonSize,
|
|
477
|
-
|
|
482
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_xui_icons_base.Remove, {}),
|
|
478
483
|
onPress: onClose,
|
|
479
|
-
"aria-label": "Close modal"
|
|
480
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_xui_icons_base.Remove, {})
|
|
484
|
+
"aria-label": "Close modal"
|
|
481
485
|
}
|
|
482
486
|
)
|
|
483
487
|
}
|
|
@@ -491,7 +495,9 @@ var Modal = (0, import_react2.forwardRef)(
|
|
|
491
495
|
flexGrow: 1,
|
|
492
496
|
width: "100%",
|
|
493
497
|
padding: openContent ? 0 : sizing.contentPadding,
|
|
494
|
-
style: {
|
|
498
|
+
style: {
|
|
499
|
+
paddingTop: hasHeader && !openContent ? sizing.headerGap : void 0
|
|
500
|
+
},
|
|
495
501
|
children
|
|
496
502
|
}
|
|
497
503
|
),
|
|
@@ -531,14 +537,16 @@ var ModalContext = (0, import_react3.createContext)({
|
|
|
531
537
|
|
|
532
538
|
// src/ModalRoot.native.tsx
|
|
533
539
|
var import_react4 = require("react");
|
|
534
|
-
var ModalRoot = (0, import_react4.memo)(
|
|
535
|
-
|
|
536
|
-
|
|
540
|
+
var ModalRoot = (0, import_react4.memo)(
|
|
541
|
+
({ modals: _modals, testID: _testID }) => {
|
|
542
|
+
return null;
|
|
543
|
+
}
|
|
544
|
+
);
|
|
537
545
|
ModalRoot.displayName = "ModalRoot";
|
|
538
546
|
|
|
539
547
|
// src/ModalProvider.tsx
|
|
540
548
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
541
|
-
var ModalProvider = ({ children }) => {
|
|
549
|
+
var ModalProvider = ({ children, testID }) => {
|
|
542
550
|
const [modals, setModals] = (0, import_react5.useState)({});
|
|
543
551
|
const onOpenModal = (0, import_react5.useCallback)(
|
|
544
552
|
(key, modal) => setModals((m) => ({ ...m, [key]: modal })),
|
|
@@ -559,7 +567,7 @@ var ModalProvider = ({ children }) => {
|
|
|
559
567
|
);
|
|
560
568
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(ModalContext.Provider, { value: contextValue, children: [
|
|
561
569
|
children,
|
|
562
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ModalRoot, { modals })
|
|
570
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ModalRoot, { modals, testID })
|
|
563
571
|
] });
|
|
564
572
|
};
|
|
565
573
|
|