@xsolla/xui-b2b-notification-panel 0.190.0 → 0.192.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 CHANGED
@@ -21,6 +21,7 @@ npm install @xsolla/xui-b2b-notification-panel
21
21
  import {
22
22
  NotificationPanel,
23
23
  type NotificationPanelProps,
24
+ type NotificationPanelDevice,
24
25
  type ActionButtonElement,
25
26
  } from '@xsolla/xui-b2b-notification-panel';
26
27
  ```
@@ -44,6 +45,7 @@ import { NotificationPanel } from '@xsolla/xui-b2b-notification-panel';
44
45
  | Prop | Type | Default | Description |
45
46
  | --- | --- | --- | --- |
46
47
  | `variant` | `"notification" \| "announcement"` | `"notification"` | Layout. `notification` is the taller banner with an icon frame; `announcement` is the slim, single-line bar. |
48
+ | `device` | `"desktop" \| "mobile"` | `"desktop"` | Device layout. Mobile `notification` uses a three-column row (icon \| stacked text + action \| close). Mobile `announcement` puts icon and title on one row, description below, and groups action + close on the right (top-aligned). |
47
49
  | `type` | `"alert" \| "warning" \| "success" \| "neutral" \| "brand"` | `"neutral"` | Visual tone of the panel. Controls background, default icon, and `role`. |
48
50
  | `title` | `string` | — | Bold title text. |
49
51
  | `description` | `string` | — | Secondary description text. |
@@ -52,7 +54,7 @@ import { NotificationPanel } from '@xsolla/xui-b2b-notification-panel';
52
54
  | `actionButton` | `ActionButtonElement` | — | A `Button`, `IconButton`, or `FlexButton` element. The panel injects styling via `cloneElement` (see below). |
53
55
  | `showCloseButton` | `boolean` | `true` | Show or hide the dismiss (×) button. |
54
56
  | `onClose` | `() => void` | — | Called when the close button is pressed. |
55
- | `closeButtonAlign` | `"top" \| "center"` | `"top"` | Vertical alignment of the close button. Applies to the `notification` variant only (`announcement` is always centered). |
57
+ | `closeButtonAlign` | `"top" \| "center"` | `"center"` | Vertical alignment of the action/close button group. Applies to the desktop `notification` variant only. |
56
58
  | `testID` | `string` | — | Test ID for testing frameworks. |
57
59
 
58
60
  Inherits `ThemeOverrideProps` (`themeMode`, `themeProductContext`).
@@ -65,10 +67,10 @@ type ActionButtonElement = React.ReactElement<
65
67
  >;
66
68
  ```
67
69
 
68
- The element passed to `actionButton`. The panel overrides a small set of props via `cloneElement` so the button matches the design; everything else (`onPress`, `icon`, `children`, etc.) is forwarded as authored. The injected props depend on `variant`:
70
+ The element passed to `actionButton`. The panel overrides a small set of props via `cloneElement` so the button matches the design; everything else (`onPress`, `icon`, `children`, etc.) is forwarded as authored:
69
71
 
70
- - **`notification`** — `size="xs"`, `variant="tertiary"`, `tone="mono"`. Pass a `Button`.
71
- - **`announcement`** — `size="xs"`, `variant="primary"`, `background={false}`. Pass a [`FlexButton`](./button.md) so it renders text-only with the designed subtle hover. (`FlexButton` has no `tone`; the Primary palette gives `content.primary` text.)
72
+ - **`FlexButton` / `Button`** — `size="xs"`, `variant="primary"`, `background={false}` (text-only XS action per Figma). Prefer [`FlexButton`](./button.md).
73
+ - **`IconButton`** — `size="xs"` only.
72
74
 
73
75
  ## Examples
74
76
 
@@ -88,17 +90,35 @@ import { NotificationPanel } from '@xsolla/xui-b2b-notification-panel';
88
90
 
89
91
  ### With action button
90
92
 
91
- The panel styles the button to match the design (`size`, `variant`, and `tone`/`background` — see [`ActionButtonElement`](#actionbuttonelement)), so pass a plain `Button`.
93
+ Pass a [`FlexButton`](./button.md) in size XS styling — the panel injects `size="xs"`, `variant="primary"`, and `background={false}`.
92
94
 
93
95
  ```tsx
94
96
  import { NotificationPanel } from '@xsolla/xui-b2b-notification-panel';
95
- import { Button } from '@xsolla/xui-button';
97
+ import { FlexButton } from '@xsolla/xui-button';
96
98
 
97
99
  <NotificationPanel
98
100
  type="warning"
99
101
  title="Session expiring"
100
102
  description="Your session will expire in 5 minutes."
101
- actionButton={<Button onPress={() => extendSession()}>Extend session</Button>}
103
+ actionButton={<FlexButton onPress={() => extendSession()}>Extend session</FlexButton>}
104
+ onClose={() => dismiss()}
105
+ />;
106
+ ```
107
+
108
+ ### Mobile layout
109
+
110
+ On narrow viewports, pass `device="mobile"` for the Figma mobile layout: icon column on the left, title and description stacked in the center with the action below them, close button in the right column.
111
+
112
+ ```tsx
113
+ import { NotificationPanel } from '@xsolla/xui-b2b-notification-panel';
114
+ import { FlexButton } from '@xsolla/xui-button';
115
+
116
+ <NotificationPanel
117
+ device="mobile"
118
+ type="alert"
119
+ title="Alert notification"
120
+ description="A mutual NDA is required to begin your partnership with Xsolla"
121
+ actionButton={<FlexButton onPress={() => openNda()}>Button</FlexButton>}
102
122
  onClose={() => dismiss()}
103
123
  />;
104
124
  ```
@@ -164,7 +184,9 @@ import { NotificationPanel } from '@xsolla/xui-b2b-notification-panel';
164
184
  />;
165
185
  ```
166
186
 
167
- ### Center-aligned close button
187
+ ### Top-aligned action/close buttons
188
+
189
+ Use `closeButtonAlign="top"` when the button group should align with the title instead of the default vertical centering.
168
190
 
169
191
  ```tsx
170
192
  import { NotificationPanel } from '@xsolla/xui-b2b-notification-panel';
@@ -172,7 +194,8 @@ import { NotificationPanel } from '@xsolla/xui-b2b-notification-panel';
172
194
  <NotificationPanel
173
195
  type="success"
174
196
  title="Saved"
175
- closeButtonAlign="center"
197
+ description="This is a neutral notification message"
198
+ closeButtonAlign="top"
176
199
  onClose={() => dismiss()}
177
200
  />;
178
201
  ```
@@ -180,6 +203,6 @@ import { NotificationPanel } from '@xsolla/xui-b2b-notification-panel';
180
203
  ## Accessibility
181
204
 
182
205
  - `role="alert"` for `type="alert"`; `role="status"` for all other types.
183
- - `aria-label` on the root is `"<type> <variant>"` (e.g. `"warning notification"`, `"alert announcement"`).
184
- - The close button is an `IconButton` with `aria-label="Close notification"`.
206
+ - `aria-label` on the root is `"<type> <variant> <device>"` (e.g. `"warning notification desktop"`, `"alert announcement mobile"`).
207
+ - The close control is an icon-only [`IconButton`](./button.md) (`variant="tertiary"`, `tone="mono"`, `size="xs"`, `hoverBackground="none"`) with `aria-label="Close notification"`. Uses Box/`onPress` so it works on React Native as well as web.
185
208
  - The default type icons are decorative — pass `aria-hidden` on any custom `icon` you supply.
@@ -3,6 +3,7 @@ import { ThemeOverrideProps } from '@xsolla/xui-core';
3
3
  import { ButtonProps, IconButtonProps, FlexButtonProps } from '@xsolla/xui-button';
4
4
 
5
5
  type ActionButtonElement = React.ReactElement<ButtonProps | IconButtonProps | FlexButtonProps>;
6
+ type NotificationPanelDevice = "desktop" | "mobile";
6
7
  interface NotificationPanelProps extends ThemeOverrideProps {
7
8
  /**
8
9
  * Layout variant.
@@ -12,6 +13,15 @@ interface NotificationPanelProps extends ThemeOverrideProps {
12
13
  * title/description on one row.
13
14
  */
14
15
  variant?: "notification" | "announcement";
16
+ /**
17
+ * Device layout mode.
18
+ * - `desktop` (default): horizontal layout with actions on the right.
19
+ * - `mobile`: Figma mobile layout — `notification` uses a three-column row
20
+ * (icon | stacked text + action | close); `announcement` puts icon, title,
21
+ * on one row with description below; action and close are grouped on the
22
+ * right, top-aligned with the title row.
23
+ */
24
+ device?: NotificationPanelDevice;
15
25
  /** Visual variant/tone of the notification */
16
26
  type?: "alert" | "warning" | "success" | "neutral" | "brand";
17
27
  /** Title text (optional) */
@@ -23,18 +33,23 @@ interface NotificationPanelProps extends ThemeOverrideProps {
23
33
  /** Custom icon override (optional) */
24
34
  icon?: React.ReactNode;
25
35
  /**
26
- * Action button (optional - pass any Button/IconButton component).
27
- * The `tone`, `size`, and `variant` props will be automatically set.
36
+ * Action button (optional - pass any Button/IconButton/FlexButton component).
37
+ * `size` — plus `variant` and `background` for non-IconButton actions — falls
38
+ * back to a panel default, but any value you set on the button element itself
39
+ * takes precedence. `tone` is never overridden by the panel.
28
40
  */
29
41
  actionButton?: React.ReactElement;
30
42
  /** Show/hide close button */
31
43
  showCloseButton?: boolean;
32
44
  /** Close button click handler */
33
45
  onClose?: () => void;
34
- /** Vertical alignment of the close button — "top" (default) or "center" */
46
+ /**
47
+ * Vertical alignment of the action/close button group — "center" (default) or
48
+ * "top". Applies to the desktop `notification` variant only.
49
+ */
35
50
  closeButtonAlign?: "center" | "top";
36
51
  testID?: string;
37
52
  }
38
53
  declare const NotificationPanel: React.FC<NotificationPanelProps>;
39
54
 
40
- export { type ActionButtonElement, NotificationPanel, type NotificationPanelProps };
55
+ export { type ActionButtonElement, NotificationPanel, type NotificationPanelDevice, type NotificationPanelProps };
package/native/index.d.ts CHANGED
@@ -3,6 +3,7 @@ import { ThemeOverrideProps } from '@xsolla/xui-core';
3
3
  import { ButtonProps, IconButtonProps, FlexButtonProps } from '@xsolla/xui-button';
4
4
 
5
5
  type ActionButtonElement = React.ReactElement<ButtonProps | IconButtonProps | FlexButtonProps>;
6
+ type NotificationPanelDevice = "desktop" | "mobile";
6
7
  interface NotificationPanelProps extends ThemeOverrideProps {
7
8
  /**
8
9
  * Layout variant.
@@ -12,6 +13,15 @@ interface NotificationPanelProps extends ThemeOverrideProps {
12
13
  * title/description on one row.
13
14
  */
14
15
  variant?: "notification" | "announcement";
16
+ /**
17
+ * Device layout mode.
18
+ * - `desktop` (default): horizontal layout with actions on the right.
19
+ * - `mobile`: Figma mobile layout — `notification` uses a three-column row
20
+ * (icon | stacked text + action | close); `announcement` puts icon, title,
21
+ * on one row with description below; action and close are grouped on the
22
+ * right, top-aligned with the title row.
23
+ */
24
+ device?: NotificationPanelDevice;
15
25
  /** Visual variant/tone of the notification */
16
26
  type?: "alert" | "warning" | "success" | "neutral" | "brand";
17
27
  /** Title text (optional) */
@@ -23,18 +33,23 @@ interface NotificationPanelProps extends ThemeOverrideProps {
23
33
  /** Custom icon override (optional) */
24
34
  icon?: React.ReactNode;
25
35
  /**
26
- * Action button (optional - pass any Button/IconButton component).
27
- * The `tone`, `size`, and `variant` props will be automatically set.
36
+ * Action button (optional - pass any Button/IconButton/FlexButton component).
37
+ * `size` — plus `variant` and `background` for non-IconButton actions — falls
38
+ * back to a panel default, but any value you set on the button element itself
39
+ * takes precedence. `tone` is never overridden by the panel.
28
40
  */
29
41
  actionButton?: React.ReactElement;
30
42
  /** Show/hide close button */
31
43
  showCloseButton?: boolean;
32
44
  /** Close button click handler */
33
45
  onClose?: () => void;
34
- /** Vertical alignment of the close button — "top" (default) or "center" */
46
+ /**
47
+ * Vertical alignment of the action/close button group — "center" (default) or
48
+ * "top". Applies to the desktop `notification` variant only.
49
+ */
35
50
  closeButtonAlign?: "center" | "top";
36
51
  testID?: string;
37
52
  }
38
53
  declare const NotificationPanel: React.FC<NotificationPanelProps>;
39
54
 
40
- export { type ActionButtonElement, NotificationPanel, type NotificationPanelProps };
55
+ export { type ActionButtonElement, NotificationPanel, type NotificationPanelDevice, type NotificationPanelProps };
package/native/index.js CHANGED
@@ -209,6 +209,7 @@ var import_xui_icons_base = require("@xsolla/xui-icons-base");
209
209
  var import_jsx_runtime2 = require("react/jsx-runtime");
210
210
  var NotificationPanel = ({
211
211
  variant = "notification",
212
+ device = "desktop",
212
213
  type = "neutral",
213
214
  title,
214
215
  description,
@@ -217,13 +218,13 @@ var NotificationPanel = ({
217
218
  actionButton,
218
219
  showCloseButton = true,
219
220
  onClose,
220
- closeButtonAlign = "top",
221
+ closeButtonAlign = "center",
221
222
  testID,
222
223
  themeMode,
223
224
  themeProductContext
224
225
  }) => {
225
226
  const { theme } = (0, import_xui_core.useResolvedTheme)({ themeMode, themeProductContext });
226
- const config = theme.sizing.notificationPanel();
227
+ const config = theme.sizing.notificationPanel(device);
227
228
  const typeConfig = {
228
229
  alert: {
229
230
  panelBg: theme.colors.overlay.alert,
@@ -270,16 +271,129 @@ var NotificationPanel = ({
270
271
  const IconComponent = currentConfig.IconComponent;
271
272
  const ariaProps = {
272
273
  role: type === "alert" ? "alert" : "status",
273
- "aria-label": `${type} ${variant}`
274
+ "aria-label": `${type} ${variant} ${device}`
275
+ };
276
+ const renderCloseButton = (iconSize) => showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
277
+ import_xui_button.IconButton,
278
+ {
279
+ variant: "tertiary",
280
+ tone: "mono",
281
+ size: "xs",
282
+ onPress: onClose,
283
+ "aria-label": "Close notification",
284
+ icon: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_xui_icons_base.Remove, { size: iconSize }),
285
+ hoverBackground: "none"
286
+ }
287
+ ) : null;
288
+ const renderActionButton = () => {
289
+ if (!(0, import_react.isValidElement)(actionButton)) return null;
290
+ const element = actionButton;
291
+ const isIconButton = element.type.displayName === "IconButton";
292
+ const props = element.props;
293
+ return (0, import_react.cloneElement)(
294
+ element,
295
+ isIconButton ? { size: props.size ?? "xs" } : {
296
+ size: props.size ?? "xs",
297
+ // Non-IconButton actions default to a text-only FlexButton (Primary
298
+ // palette → content.primary text, no fill), per the Figma "Flex
299
+ // Button" node. hoverBackground is left at its default so the subtle
300
+ // mono hover overlay from the design is preserved.
301
+ variant: props.variant ?? "primary",
302
+ background: props.background ?? false
303
+ }
304
+ );
274
305
  };
275
306
  if (variant === "announcement") {
307
+ const isMobileAnnouncement = device === "mobile";
308
+ if (isMobileAnnouncement) {
309
+ const descriptionIndent = showIcon ? config.announcementIconSize + config.announcementContentGap : 0;
310
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
311
+ Box,
312
+ {
313
+ backgroundColor: currentConfig.announcementBg,
314
+ flexDirection: "row",
315
+ alignItems: "stretch",
316
+ padding: config.announcementPadding,
317
+ gap: config.announcementGap,
318
+ overflow: "hidden",
319
+ testID,
320
+ style: {
321
+ backdropFilter: `blur(${config.announcementBlurRadius}px)`
322
+ },
323
+ ...ariaProps,
324
+ children: [
325
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
326
+ Box,
327
+ {
328
+ flex: 1,
329
+ minWidth: 0,
330
+ flexDirection: "column",
331
+ gap: config.textGap,
332
+ children: [
333
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
334
+ Box,
335
+ {
336
+ flexDirection: "row",
337
+ alignItems: "flex-start",
338
+ gap: config.announcementContentGap,
339
+ children: [
340
+ showIcon && (icon || /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
341
+ IconComponent,
342
+ {
343
+ size: config.announcementIconSize,
344
+ color: currentConfig.iconColor,
345
+ variant: "solid"
346
+ }
347
+ )),
348
+ title && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box, { flex: 1, minWidth: 0, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
349
+ import_xui_typography.Typography,
350
+ {
351
+ variant: "bodyXsAccent",
352
+ color: theme.colors.content.primary,
353
+ noWrap: true,
354
+ children: title
355
+ }
356
+ ) })
357
+ ]
358
+ }
359
+ ),
360
+ description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box, { paddingLeft: descriptionIndent, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
361
+ import_xui_typography.Typography,
362
+ {
363
+ variant: "bodyXs",
364
+ color: theme.colors.content.secondary,
365
+ noWrap: true,
366
+ children: description
367
+ }
368
+ ) })
369
+ ]
370
+ }
371
+ ),
372
+ (actionButton || showCloseButton) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
373
+ Box,
374
+ {
375
+ flexShrink: 0,
376
+ alignSelf: "flex-start",
377
+ flexDirection: "row",
378
+ alignItems: "center",
379
+ gap: config.announcementButtonsGap,
380
+ children: [
381
+ renderActionButton(),
382
+ renderCloseButton(config.announcementCloseIconSize)
383
+ ]
384
+ }
385
+ )
386
+ ]
387
+ }
388
+ );
389
+ }
276
390
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
277
391
  Box,
278
392
  {
279
393
  backgroundColor: currentConfig.announcementBg,
280
394
  flexDirection: "row",
281
395
  alignItems: "center",
282
- justifyContent: "center",
396
+ justifyContent: "flex-start",
283
397
  padding: config.announcementPadding,
284
398
  gap: config.announcementGap,
285
399
  overflow: "hidden",
@@ -307,15 +421,37 @@ var NotificationPanel = ({
307
421
  variant: "solid"
308
422
  }
309
423
  )),
310
- title && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
311
- import_xui_typography.Typography,
424
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
425
+ Box,
312
426
  {
313
- variant: "bodyXsAccent",
314
- color: theme.colors.content.primary,
315
- children: title
427
+ flex: 1,
428
+ minWidth: 0,
429
+ overflow: "hidden",
430
+ flexDirection: "row",
431
+ alignItems: "center",
432
+ gap: config.announcementContentGap,
433
+ children: [
434
+ title && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
435
+ import_xui_typography.Typography,
436
+ {
437
+ variant: "bodyXsAccent",
438
+ color: theme.colors.content.primary,
439
+ noWrap: true,
440
+ children: title
441
+ }
442
+ ),
443
+ description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
444
+ import_xui_typography.Typography,
445
+ {
446
+ variant: "bodyXs",
447
+ color: theme.colors.content.secondary,
448
+ noWrap: true,
449
+ children: description
450
+ }
451
+ )
452
+ ]
316
453
  }
317
- ),
318
- description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_xui_typography.Typography, { variant: "bodyXs", color: theme.colors.content.secondary, children: description })
454
+ )
319
455
  ]
320
456
  }
321
457
  ),
@@ -327,27 +463,8 @@ var NotificationPanel = ({
327
463
  alignItems: "center",
328
464
  gap: config.announcementButtonsGap,
329
465
  children: [
330
- (0, import_react.isValidElement)(actionButton) && (0, import_react.cloneElement)(actionButton, {
331
- size: "xs",
332
- // Announcement uses a text-only FlexButton (Primary palette →
333
- // content.primary text, no fill), per the Figma "Flex Button"
334
- // node. hoverBackground is left at its default so the subtle
335
- // mono hover overlay from the design is preserved.
336
- variant: "primary",
337
- background: false
338
- }),
339
- showCloseButton && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
340
- import_xui_button.IconButton,
341
- {
342
- variant: "tertiary",
343
- tone: "mono",
344
- size: "xs",
345
- onPress: onClose,
346
- "aria-label": "Close notification",
347
- icon: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_xui_icons_base.Remove, { size: config.announcementCloseIconSize }),
348
- hoverBackground: "none"
349
- }
350
- )
466
+ renderActionButton(),
467
+ renderCloseButton(config.announcementCloseIconSize)
351
468
  ]
352
469
  }
353
470
  )
@@ -355,6 +472,89 @@ var NotificationPanel = ({
355
472
  }
356
473
  );
357
474
  }
475
+ if (device === "mobile") {
476
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
477
+ Box,
478
+ {
479
+ backgroundColor: currentConfig.panelBg,
480
+ borderRadius: config.borderRadius,
481
+ flexDirection: "row",
482
+ alignItems: "flex-start",
483
+ justifyContent: "space-between",
484
+ overflow: "hidden",
485
+ testID,
486
+ ...ariaProps,
487
+ children: [
488
+ showIcon && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
489
+ Box,
490
+ {
491
+ alignSelf: "stretch",
492
+ paddingTop: config.mobileIconColumnPaddingVertical,
493
+ paddingBottom: config.mobileIconColumnPaddingVertical,
494
+ paddingLeft: config.mobileIconColumnPaddingLeft,
495
+ alignItems: "flex-start",
496
+ justifyContent: "flex-start",
497
+ children: icon || /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
498
+ IconComponent,
499
+ {
500
+ size: config.mobileIconSize,
501
+ color: currentConfig.iconColor,
502
+ variant: "solid"
503
+ }
504
+ )
505
+ }
506
+ ),
507
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
508
+ Box,
509
+ {
510
+ flex: 1,
511
+ minWidth: 0,
512
+ paddingHorizontal: config.mobileBodyPaddingHorizontal,
513
+ paddingVertical: config.mobileBodyPaddingVertical,
514
+ flexDirection: "column",
515
+ alignItems: "flex-start",
516
+ justifyContent: "center",
517
+ gap: config.mobileBodyContentGap,
518
+ children: [
519
+ (title || description) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box, { alignSelf: "stretch", gap: config.textGap, children: [
520
+ title && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
521
+ import_xui_typography.Typography,
522
+ {
523
+ variant: "bodySmAccent",
524
+ color: theme.colors.content.primary,
525
+ children: title
526
+ }
527
+ ),
528
+ description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
529
+ import_xui_typography.Typography,
530
+ {
531
+ variant: "bodyXs",
532
+ color: theme.colors.content.tertiary,
533
+ children: description
534
+ }
535
+ )
536
+ ] }),
537
+ actionButton && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box, { marginLeft: config.mobileNotificationActionButtonOffsetLeft, children: renderActionButton() })
538
+ ]
539
+ }
540
+ ),
541
+ showCloseButton && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
542
+ Box,
543
+ {
544
+ alignSelf: "stretch",
545
+ flexDirection: "row",
546
+ paddingTop: config.mobileCloseColumnPaddingVertical,
547
+ paddingBottom: config.mobileCloseColumnPaddingVertical,
548
+ paddingRight: config.mobileCloseColumnPaddingRight,
549
+ alignItems: "flex-start",
550
+ justifyContent: "flex-end",
551
+ children: renderCloseButton(config.notificationCloseIconSize)
552
+ }
553
+ )
554
+ ]
555
+ }
556
+ );
557
+ }
358
558
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
359
559
  Box,
360
560
  {
@@ -412,29 +612,13 @@ var NotificationPanel = ({
412
612
  Box,
413
613
  {
414
614
  flexDirection: "row",
415
- alignSelf: closeButtonAlign === "top" ? "stretch" : "center",
416
- alignItems: closeButtonAlign === "top" ? "flex-start" : "center",
417
- justifyContent: "flex-start",
418
- paddingVertical: closeButtonAlign === "top" ? 4 : 0,
615
+ alignSelf: closeButtonAlign === "top" ? "flex-start" : void 0,
616
+ alignItems: "center",
617
+ flexShrink: 0,
419
618
  gap: config.buttonsGap,
420
619
  children: [
421
- (0, import_react.isValidElement)(actionButton) && (0, import_react.cloneElement)(actionButton, {
422
- size: "xs",
423
- variant: "tertiary",
424
- tone: "mono"
425
- }),
426
- showCloseButton && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
427
- import_xui_button.IconButton,
428
- {
429
- variant: "tertiary",
430
- tone: "mono",
431
- size: "xs",
432
- onPress: onClose,
433
- "aria-label": "Close notification",
434
- icon: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_xui_icons_base.Remove, { size: 18 }),
435
- hoverBackground: "none"
436
- }
437
- )
620
+ renderActionButton(),
621
+ renderCloseButton(config.notificationCloseIconSize)
438
622
  ]
439
623
  }
440
624
  )