@xsolla/xui-toast 0.158.0 → 0.160.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/web/index.mjs CHANGED
@@ -1,5 +1,10 @@
1
1
  // src/Toast.tsx
2
- import { useEffect, useState } from "react";
2
+ import {
3
+ cloneElement,
4
+ isValidElement,
5
+ useEffect,
6
+ useState
7
+ } from "react";
3
8
 
4
9
  // ../../foundation/primitives-web/src/Box.tsx
5
10
  import React2 from "react";
@@ -271,6 +276,8 @@ var Text = ({
271
276
  className,
272
277
  id,
273
278
  role,
279
+ testID,
280
+ "data-testid": dataTestId,
274
281
  numberOfLines: _numberOfLines,
275
282
  ...props
276
283
  }) => {
@@ -281,7 +288,8 @@ var Text = ({
281
288
  style,
282
289
  className,
283
290
  id,
284
- role
291
+ role,
292
+ "data-testid": dataTestId || testID
285
293
  }
286
294
  );
287
295
  };
@@ -305,51 +313,116 @@ var StyledIcon = styled3(FilteredDiv2)`
305
313
  stroke: currentColor;
306
314
  }
307
315
  `;
308
- var Icon = ({ children, ...props }) => {
309
- return /* @__PURE__ */ jsx3(StyledIcon, { ...props, children });
316
+ var Icon = ({
317
+ children,
318
+ testID,
319
+ "data-testid": dataTestId,
320
+ ...props
321
+ }) => {
322
+ return /* @__PURE__ */ jsx3(StyledIcon, { "data-testid": dataTestId || testID, ...props, children });
310
323
  };
311
324
 
312
325
  // src/Toast.tsx
313
326
  import { useResolvedTheme } from "@xsolla/xui-core";
314
- import { Check, AlertCircle, X } from "@xsolla/xui-icons";
327
+ import {
328
+ CheckCr,
329
+ ExclamationMarkCr,
330
+ InfoCr,
331
+ Remove,
332
+ Warning as WarningIcon
333
+ } from "@xsolla/xui-icons-base";
315
334
  import { jsx as jsx4, jsxs } from "react/jsx-runtime";
316
- var getDefaultIcon = (variant, size, color) => {
317
- switch (variant) {
318
- case "success":
319
- return /* @__PURE__ */ jsx4(Check, { size, color });
320
- case "info":
321
- case "warning":
322
- case "error":
323
- default:
324
- return /* @__PURE__ */ jsx4(AlertCircle, { size, color });
325
- }
335
+ var TOAST_COLORS = {
336
+ alert: "#ff553d",
337
+ success: "#47d94a",
338
+ neutral: "#7899a1",
339
+ warning: "#ffb95c"
326
340
  };
327
- var getIconColor = (variant, colors) => {
328
- switch (variant) {
341
+ var DEFAULT_COLOR_SCHEME = {
342
+ background: "#34474b",
343
+ text: "#ffffff",
344
+ descriptionText: "rgba(255, 255, 255, 0.7)",
345
+ divider: "rgba(255, 255, 255, 0.16)",
346
+ actionText: "#ffffff"
347
+ };
348
+ var getDefaultIcon = (type, size, color) => {
349
+ switch (type) {
329
350
  case "success":
330
- return colors.content.success.primary;
351
+ return /* @__PURE__ */ jsx4(
352
+ CheckCr,
353
+ {
354
+ variant: "solid",
355
+ size,
356
+ color,
357
+ "data-testid": "toast-icon-success"
358
+ }
359
+ );
360
+ case "neutral":
361
+ return /* @__PURE__ */ jsx4(
362
+ InfoCr,
363
+ {
364
+ variant: "solid",
365
+ size,
366
+ color,
367
+ "data-testid": "toast-icon-neutral"
368
+ }
369
+ );
331
370
  case "warning":
332
- return colors.content.warning.primary;
333
- case "error":
334
- return colors.content.alert.primary;
335
- case "info":
371
+ return /* @__PURE__ */ jsx4(
372
+ WarningIcon,
373
+ {
374
+ variant: "solid",
375
+ size,
376
+ color,
377
+ "data-testid": "toast-icon-warning"
378
+ }
379
+ );
380
+ case "alert":
336
381
  default:
337
- return colors.content.inverse;
382
+ return /* @__PURE__ */ jsx4(
383
+ ExclamationMarkCr,
384
+ {
385
+ variant: "solid",
386
+ size,
387
+ color,
388
+ "data-testid": "toast-icon-alert"
389
+ }
390
+ );
338
391
  }
339
392
  };
340
393
  var ANIMATION_DURATION = 200;
394
+ var PROGRESS_HEIGHT = 4;
395
+ var TOAST_CONFIG = {
396
+ minHeight: 56,
397
+ paddingHorizontal: 16,
398
+ paddingVertical: 12,
399
+ borderRadius: 4,
400
+ gap: 12,
401
+ iconSize: 24,
402
+ closeButtonSize: 24,
403
+ closeIconSize: 20,
404
+ fontSize: 16,
405
+ lineHeight: 20,
406
+ maxWidth: 440
407
+ };
341
408
  var Toast = ({
342
409
  id,
343
- variant = "info",
344
- message,
345
- icon,
410
+ type = "neutral",
411
+ title,
412
+ description,
413
+ icon = true,
414
+ action,
415
+ showCloseButton = true,
416
+ progress = false,
346
417
  duration,
347
418
  onClose,
419
+ colorScheme = DEFAULT_COLOR_SCHEME,
420
+ testID,
348
421
  themeMode,
349
422
  themeProductContext
350
423
  }) => {
351
- const { theme } = useResolvedTheme({ themeMode, themeProductContext });
352
- const config = theme.sizing.toast();
424
+ useResolvedTheme({ themeMode, themeProductContext });
425
+ const config = TOAST_CONFIG;
353
426
  const [visible, setVisible] = useState(false);
354
427
  const [dismissing, setDismissing] = useState(false);
355
428
  useEffect(() => {
@@ -366,63 +439,147 @@ var Toast = ({
366
439
  const timer = setTimeout(handleClose, duration);
367
440
  return () => clearTimeout(timer);
368
441
  }, [duration]);
369
- const iconColor = getIconColor(variant, theme.colors);
370
- const displayIcon = icon !== void 0 ? /* @__PURE__ */ jsx4(Icon, { size: config.iconSize, color: iconColor, children: icon }) : getDefaultIcon(variant, config.iconSize, iconColor);
442
+ const iconColor = TOAST_COLORS[type];
443
+ const shouldShowIcon = icon !== false;
444
+ const displayIcon = icon === true || icon === void 0 ? getDefaultIcon(type, config.iconSize, iconColor) : icon;
445
+ const renderedAction = isValidElement(action) && typeof action.type !== "string" ? cloneElement(action, {
446
+ size: "xs",
447
+ variant: "inverse",
448
+ background: false,
449
+ themeMode: "dark",
450
+ themeProductContext,
451
+ children: /* @__PURE__ */ jsx4("span", { style: { color: colorScheme.actionText }, children: action.props.children })
452
+ }) : action;
453
+ const hasAction = Boolean(action);
454
+ const hasCloseButton = showCloseButton && Boolean(onClose);
455
+ const hasActions = hasAction || hasCloseButton;
456
+ const role = type === "neutral" || type === "success" ? "status" : "alert";
457
+ const ariaLive = type === "neutral" || type === "success" ? "polite" : "assertive";
371
458
  return /* @__PURE__ */ jsxs(
372
459
  Box,
373
460
  {
374
- backgroundColor: theme.colors.background.inverse,
461
+ testID,
462
+ backgroundColor: colorScheme.background,
375
463
  borderRadius: config.borderRadius,
376
- paddingHorizontal: config.paddingHorizontal,
377
- paddingVertical: config.paddingVertical,
378
464
  minHeight: config.minHeight,
379
465
  flexDirection: "row",
380
466
  alignItems: "center",
381
- gap: config.gap,
382
- width: "100%",
383
- role: "alert",
384
- "aria-live": "polite",
467
+ justifyContent: "center",
468
+ overflow: "hidden",
469
+ width: config.maxWidth,
470
+ maxWidth: "100%",
471
+ role,
472
+ "aria-live": ariaLive,
385
473
  "data-toast-id": id,
386
474
  style: {
387
475
  opacity: visible && !dismissing ? 1 : 0,
388
476
  transform: visible && !dismissing ? "translateY(0)" : "translateY(-8px)",
389
- transition: `opacity ${ANIMATION_DURATION}ms ease-out, transform ${ANIMATION_DURATION}ms ease-out`
477
+ transition: `opacity ${ANIMATION_DURATION}ms ease-out, transform ${ANIMATION_DURATION}ms ease-out`,
478
+ boxShadow: colorScheme.shadow,
479
+ backdropFilter: colorScheme.backdropFilter
390
480
  },
391
481
  children: [
392
- /* @__PURE__ */ jsx4(
482
+ /* @__PURE__ */ jsxs(
393
483
  Box,
394
484
  {
395
- width: config.iconSize,
396
- height: config.iconSize,
485
+ flex: 1,
486
+ minHeight: config.minHeight,
487
+ minWidth: 0,
488
+ flexDirection: "row",
397
489
  alignItems: "center",
398
- justifyContent: "center",
399
- flexShrink: 0,
400
- children: displayIcon
490
+ gap: config.gap,
491
+ paddingHorizontal: config.paddingHorizontal,
492
+ paddingVertical: config.paddingVertical,
493
+ children: [
494
+ shouldShowIcon && /* @__PURE__ */ jsx4(
495
+ Box,
496
+ {
497
+ width: config.iconSize,
498
+ height: config.iconSize,
499
+ alignItems: "center",
500
+ justifyContent: "center",
501
+ flexShrink: 0,
502
+ children: icon === true || icon === void 0 ? displayIcon : /* @__PURE__ */ jsx4(Icon, { size: config.iconSize, color: iconColor, children: displayIcon })
503
+ }
504
+ ),
505
+ /* @__PURE__ */ jsxs(Box, { flex: 1, minWidth: 0, gap: 2, children: [
506
+ title && /* @__PURE__ */ jsx4(
507
+ Text,
508
+ {
509
+ color: colorScheme.text,
510
+ fontSize: config.fontSize,
511
+ lineHeight: config.lineHeight,
512
+ fontWeight: "500",
513
+ numberOfLines: 1,
514
+ children: title
515
+ }
516
+ ),
517
+ description && /* @__PURE__ */ jsx4(
518
+ Text,
519
+ {
520
+ color: colorScheme.descriptionText,
521
+ fontSize: 14,
522
+ lineHeight: 18,
523
+ numberOfLines: 1,
524
+ children: description
525
+ }
526
+ )
527
+ ] }),
528
+ hasActions && /* @__PURE__ */ jsxs(
529
+ Box,
530
+ {
531
+ height: 32,
532
+ flexDirection: "row",
533
+ alignItems: "center",
534
+ gap: config.gap,
535
+ flexShrink: 0,
536
+ children: [
537
+ renderedAction,
538
+ hasAction && hasCloseButton && /* @__PURE__ */ jsx4(
539
+ Box,
540
+ {
541
+ width: 1,
542
+ height: "100%",
543
+ backgroundColor: colorScheme.divider,
544
+ testID: "toast-divider"
545
+ }
546
+ ),
547
+ hasCloseButton && /* @__PURE__ */ jsx4(
548
+ Box,
549
+ {
550
+ onPress: handleClose,
551
+ width: config.closeButtonSize,
552
+ height: config.closeButtonSize,
553
+ alignItems: "center",
554
+ justifyContent: "center",
555
+ flexShrink: 0,
556
+ role: "button",
557
+ "aria-label": "Dismiss notification",
558
+ children: /* @__PURE__ */ jsx4(
559
+ Remove,
560
+ {
561
+ variant: "line",
562
+ size: config.closeIconSize,
563
+ color: colorScheme.text
564
+ }
565
+ )
566
+ }
567
+ )
568
+ ]
569
+ }
570
+ )
571
+ ]
401
572
  }
402
573
  ),
403
- /* @__PURE__ */ jsx4(Box, { flex: 1, minWidth: 0, children: /* @__PURE__ */ jsx4(
404
- Text,
405
- {
406
- color: theme.colors.content.inverse,
407
- fontSize: config.fontSize,
408
- lineHeight: config.lineHeight,
409
- fontWeight: "500",
410
- numberOfLines: 2,
411
- children: message
412
- }
413
- ) }),
414
- onClose && /* @__PURE__ */ jsx4(
574
+ progress && /* @__PURE__ */ jsx4(
415
575
  Box,
416
576
  {
417
- onPress: handleClose,
418
- width: config.closeButtonSize,
419
- height: config.closeButtonSize,
420
- alignItems: "center",
421
- justifyContent: "center",
422
- flexShrink: 0,
423
- role: "button",
424
- "aria-label": "Dismiss toast",
425
- children: /* @__PURE__ */ jsx4(X, { size: config.closeIconSize, color: theme.colors.content.inverse })
577
+ position: "absolute",
578
+ left: 0,
579
+ right: 0,
580
+ bottom: 0,
581
+ height: PROGRESS_HEIGHT,
582
+ backgroundColor: iconColor
426
583
  }
427
584
  )
428
585
  ]
@@ -436,6 +593,10 @@ import { memo } from "react";
436
593
  import ReactDOM from "react-dom";
437
594
  import { useResolvedTheme as useResolvedTheme2 } from "@xsolla/xui-core";
438
595
  import { jsx as jsx5 } from "react/jsx-runtime";
596
+ var TOAST_GROUP_CONFIG = {
597
+ containerPadding: 12,
598
+ groupGap: 8
599
+ };
439
600
  var ToastGroup = memo(
440
601
  ({
441
602
  toasts,
@@ -443,11 +604,12 @@ var ToastGroup = memo(
443
604
  align = "center",
444
605
  maxWidth,
445
606
  onDismiss,
607
+ testID,
446
608
  themeMode,
447
609
  themeProductContext
448
610
  }) => {
449
- const { theme } = useResolvedTheme2({ themeMode, themeProductContext });
450
- const config = theme.sizing.toast();
611
+ useResolvedTheme2({ themeMode, themeProductContext });
612
+ const config = TOAST_GROUP_CONFIG;
451
613
  if (toasts.length === 0 || typeof document === "undefined") {
452
614
  return null;
453
615
  }
@@ -461,6 +623,7 @@ var ToastGroup = memo(
461
623
  /* @__PURE__ */ jsx5(
462
624
  Box,
463
625
  {
626
+ testID,
464
627
  position: "fixed",
465
628
  left: 0,
466
629
  right: 0,
@@ -480,9 +643,13 @@ var ToastGroup = memo(
480
643
  Toast,
481
644
  {
482
645
  id: toast.id,
483
- variant: toast.variant,
484
- message: toast.message,
646
+ type: toast.type,
647
+ title: toast.title,
648
+ description: toast.description,
485
649
  icon: toast.icon,
650
+ action: toast.action,
651
+ showCloseButton: toast.showCloseButton,
652
+ progress: toast.progress,
486
653
  duration: toast.duration,
487
654
  onClose: () => onDismiss(toast.id)
488
655
  },
@@ -516,7 +683,8 @@ var ToastProvider = ({
516
683
  position = "top",
517
684
  align = "center",
518
685
  defaultDuration = 5e3,
519
- maxWidth
686
+ maxWidth,
687
+ testID
520
688
  }) => {
521
689
  const [toasts, setToasts] = useState2([]);
522
690
  const dismissToast = useCallback((id) => {
@@ -531,9 +699,13 @@ var ToastProvider = ({
531
699
  const duration = options.duration ?? defaultDuration;
532
700
  const newToast = {
533
701
  id,
534
- variant: options.variant ?? "info",
535
- message: options.message,
702
+ type: options.type ?? "neutral",
703
+ title: options.title,
704
+ description: options.description,
536
705
  icon: options.icon,
706
+ action: options.action,
707
+ showCloseButton: options.showCloseButton,
708
+ progress: options.progress,
537
709
  duration
538
710
  };
539
711
  setToasts((prev) => [...prev, newToast]);
@@ -559,7 +731,8 @@ var ToastProvider = ({
559
731
  position,
560
732
  align,
561
733
  maxWidth,
562
- onDismiss: dismissToast
734
+ onDismiss: dismissToast,
735
+ testID
563
736
  }
564
737
  )
565
738
  ] });
@@ -579,27 +752,27 @@ var useToast = () => {
579
752
  },
580
753
  [addToast]
581
754
  );
582
- const success = useCallback2(
583
- (message, options) => {
584
- return addToast({ ...options, message, variant: "success" });
755
+ const alert = useCallback2(
756
+ (options) => {
757
+ return addToast({ ...options, type: "alert" });
585
758
  },
586
759
  [addToast]
587
760
  );
588
- const info = useCallback2(
589
- (message, options) => {
590
- return addToast({ ...options, message, variant: "info" });
761
+ const success = useCallback2(
762
+ (options) => {
763
+ return addToast({ ...options, type: "success" });
591
764
  },
592
765
  [addToast]
593
766
  );
594
- const warning = useCallback2(
595
- (message, options) => {
596
- return addToast({ ...options, message, variant: "warning" });
767
+ const neutral = useCallback2(
768
+ (options) => {
769
+ return addToast({ ...options, type: "neutral" });
597
770
  },
598
771
  [addToast]
599
772
  );
600
- const error = useCallback2(
601
- (message, options) => {
602
- return addToast({ ...options, message, variant: "error" });
773
+ const warning = useCallback2(
774
+ (options) => {
775
+ return addToast({ ...options, type: "warning" });
603
776
  },
604
777
  [addToast]
605
778
  );
@@ -614,10 +787,10 @@ var useToast = () => {
614
787
  }, [dismissAllToasts]);
615
788
  return {
616
789
  toast,
790
+ alert,
617
791
  success,
618
- info,
792
+ neutral,
619
793
  warning,
620
- error,
621
794
  dismiss,
622
795
  dismissAll
623
796
  };