Toast.svelte 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. <script>
  2. import Loading from '../loading/Loading.svelte';
  3. import Icon from '../icon/Icon.svelte';
  4. import Mask from '../mask/Mask.svelte';
  5. import Transition from './Transition.svelte';
  6. /** @typedef {import('../../index.d').Toast} ToastProps */
  7. /** @type {ToastProps} */
  8. let {
  9. message = '',
  10. visible = $bindable(false),
  11. duration = 2000,
  12. position = 'center',
  13. py = '0',
  14. radius = 'base',
  15. transitionType = 'scale',
  16. transitionParams = {},
  17. outDuration = 0,
  18. zIndex = 1000,
  19. type = '',
  20. mask = {},
  21. loading = {},
  22. icon = { name: '' },
  23. clickable = false,
  24. dynamicFixed = true,
  25. children,
  26. onopen,
  27. onclose,
  28. } = $props();
  29. $effect(() => {
  30. if (visible) {
  31. if (duration === 0) {
  32. //不自动关闭 not auto close
  33. } else {
  34. setTimeout(() => {
  35. visible = false;
  36. onclose && onclose();
  37. }, duration);
  38. }
  39. } else {
  40. onopen && onopen();
  41. }
  42. });
  43. const typeObj = { success: 'checkbox-circle', error: 'close-circle', warning: 'error-warning', info: 'information' };
  44. const positionClass = { center: ' justify-center', top: ' justify-start', bottom: ' justify-end' };
  45. const pyClass = { '0': ' py-0', '10': ' py-10', '20': ' py-20', '40': ' py-40', '60': ' py-60', '80': ' py-80' };
  46. const radiusClass = {
  47. base: ' rounded',
  48. full: ' rounded-full',
  49. none: ' rounded-none',
  50. sm: ' rounded-sm',
  51. md: ' rounded-md',
  52. lg: ' rounded-lg',
  53. xl: ' rounded-xl',
  54. '2xl': ' rounded-2xl',
  55. };
  56. //解决 Safari 和 Chrome 或其他浏览器滚动时工具栏隐藏与显示引发的窗口高度变化问题
  57. // First we get the viewport height and we multiple it by 1% to get a value for a vh unit
  58. // let vh = window.innerHeight * 0.01;
  59. // // Then we set the value in the --vh custom property to the root of the document
  60. // document.documentElement.style.setProperty('--vh', `${vh}px`);
  61. // // We listen to the resize event
  62. // window.addEventListener('resize', () => {
  63. // // We execute the same script as before
  64. // let vh = window.innerHeight * 0.01;
  65. // document.documentElement.style.setProperty('--vh', `${vh}px`);
  66. // });
  67. let innerHeight = $state(0);
  68. $effect(() => {
  69. innerHeight = window.innerHeight;
  70. });
  71. if (dynamicFixed) {
  72. //解决 Safari 和 Chrome 或其他浏览器滚动时工具栏隐藏与显示引发的窗口高度变化问题
  73. // First we get the viewport height and we multiple it by 1% to get a value for a vh unit
  74. window.addEventListener('resize', () => {
  75. innerHeight = window.innerHeight;
  76. });
  77. }
  78. </script>
  79. {#if visible}
  80. <Mask {visible} {clickable} opacity={0} {...mask} {outDuration} />
  81. {/if}
  82. {#if visible}
  83. <div
  84. class={`fixed w-screen h-screen inset-0 flex flex-col${positionClass[position] || positionClass['center']}${
  85. position === 'center' ? '' : pyClass[py] || pyClass['20']
  86. } w-full h-full${clickable ? ' pointer-events-none' : ''}`}
  87. style={`z-index:${zIndex};height:${innerHeight}px`}
  88. >
  89. <Transition {visible} {transitionType} {transitionParams} {outDuration}>
  90. <div class="flex justify-center px-10">
  91. <div
  92. class={`inline-block bg-black/90 dark:bg-white/90 text-center p-4${
  93. radiusClass[radius] || radiusClass['base']
  94. } text-white dark:text-black`}
  95. >
  96. {#if children}
  97. {@render children()}
  98. {:else}
  99. {#if type !== ''}
  100. <div class="mb-2">
  101. {#if type === 'loading'}
  102. <Loading inverse {...loading} />
  103. {:else}
  104. <Icon
  105. name={type === 'success' || type === 'error' || type === 'warning' || type === 'info'
  106. ? `ri-${typeObj[type]}-line`
  107. : type}
  108. size={30}
  109. {...icon}
  110. />
  111. {/if}
  112. </div>
  113. {/if}
  114. <div>
  115. {message}
  116. </div>
  117. {/if}
  118. </div>
  119. </div>
  120. </Transition>
  121. </div>
  122. {/if}