toasters.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. const container = document.getElementById("toasts-content");
  2. let incrementer = 0;
  3. export default class Toast {
  4. // should add type checking
  5. constructor({ content, persistent, interactable, timeout }) {
  6. this.identifier = `toast-${incrementer}`;
  7. incrementer++;
  8. this.visible = false;
  9. this.content = content;
  10. this.persistent = persistent !== undefined ? persistent : false;
  11. this.timeout = timeout ? timeout : 6000;
  12. this.interactable = interactable !== undefined ? interactable : true;
  13. if (!this.persistent) this.startTimer();
  14. if (this.interactable) this.dragListener();
  15. }
  16. get content() {
  17. return this._content;
  18. }
  19. set content(value) {
  20. this._content = value;
  21. if (!this.visible) {
  22. container.insertAdjacentHTML("beforeend", `<div class="toast ${this.identifier}">${this.content}</div>`);
  23. this.find();
  24. } else
  25. this.element.innerHTML = this.content;
  26. this.visible = true;
  27. }
  28. startTimer() {
  29. setTimeout(this.destroy.bind(this), this.timeout);
  30. }
  31. dragListener() {
  32. /** handles mouse drag **/
  33. this.element.addEventListener("mousedown", event => {
  34. const initialX = this.element.getBoundingClientRect().x;
  35. let shiftX = event.clientX - initialX;
  36. const move = ({ pageX }) => {
  37. let opacity = 1.2 - Math.abs(pageX - shiftX - initialX) / 100;
  38. this.element.style.opacity = opacity;
  39. this.element.style.left = `${pageX - shiftX - initialX}px`;
  40. }
  41. window.addEventListener("mousemove", move, false);
  42. window.addEventListener("mouseup", () => {
  43. this.handleInputLoss();
  44. window.removeEventListener("mousemove", move, false);
  45. }, false);
  46. }, false);
  47. /** handles touch devices **/
  48. this.element.addEventListener("touchstart", event => {
  49. const initialX = this.element.getBoundingClientRect().x;
  50. let shiftX = event.touches[0].clientX - initialX;
  51. const move = ({ touches }) => {
  52. // if multiple touches on device, none are registered to the toast anymore
  53. if (touches.length === 1) {
  54. let pageX = touches[0].pageX
  55. let opacity = 1.2 - Math.abs(pageX - shiftX - initialX) / 100;
  56. this.element.style.opacity = opacity;
  57. this.element.style.left = `${pageX - shiftX - initialX}px`;
  58. }
  59. }
  60. window.addEventListener("touchmove", move, false);
  61. window.addEventListener("touchend", () => {
  62. this.handleInputLoss();
  63. window.removeEventListener("touchmove", move, false);
  64. }, false);
  65. }, false);
  66. }
  67. handleInputLoss() {
  68. if (this.element.style.opacity < 0.15) return this.destroy();
  69. else {
  70. this.element.style.opacity = 1;
  71. this.element.style.left = 0;
  72. this.element.style.transition = "opacity .2s linear, left .2s linear";
  73. setTimeout(() => {
  74. this.element.style.transition = null;
  75. }, 200)
  76. }
  77. }
  78. find() {
  79. for (let i = 0; i < container.childNodes.length; i++)
  80. if (container.childNodes[i].classList.contains(this.identifier))
  81. return this.element = container.childNodes[i];
  82. }
  83. destroy() {
  84. this.element.remove();
  85. }
  86. show() {
  87. if (!this.visible) {
  88. this.element.style.display = "block";
  89. this.visible = true;
  90. }
  91. }
  92. hide() {
  93. if (this.visible) {
  94. this.element.style.display = "none";
  95. this.visible = false;
  96. }
  97. }
  98. }