- {{#if @showProgressBar}}
-
- {{/if}}
- {{#if @data.icon}}
-
- {{icon @data.icon}}
-
- {{/if}}
-
-
- {{#if @data.title}}
-
- {{@data.title}}
-
- {{/if}}
- {{#if @data.message}}
-
- {{@data.message}}
-
- {{/if}}
-
+export default class DDefaultToast extends Component {
+ @service site;
- {{#if @data.actions}}
-
- {{#each @data.actions as |toastAction|}}
- {{#if toastAction.action}}
-
- {{/if}}
- {{/each}}
+
+
+ {{#if @showProgressBar}}
+
+ {{/if}}
+ {{#if @data.icon}}
+
+ {{icon @data.icon}}
{{/if}}
-
-
-
-
-
-;
+
+
+ {{#if @data.title}}
+
+ {{@data.title}}
+
+ {{/if}}
+ {{#if @data.message}}
+
+ {{@data.message}}
+
+ {{/if}}
+
-export default DDefaultToast;
+ {{#if @data.actions}}
+
+ {{#each @data.actions as |toastAction|}}
+ {{#if toastAction.action}}
+
+ {{/if}}
+ {{/each}}
+
+ {{/if}}
+
+
+
+
+
+
+}
diff --git a/app/assets/javascripts/float-kit/addon/components/d-toast.gjs b/app/assets/javascripts/float-kit/addon/components/d-toast.gjs
index 95e8a950ae7..7d97a3551ce 100644
--- a/app/assets/javascripts/float-kit/addon/components/d-toast.gjs
+++ b/app/assets/javascripts/float-kit/addon/components/d-toast.gjs
@@ -1,129 +1,95 @@
import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
-import { registerDestructor } from "@ember/destroyable";
import { action } from "@ember/object";
-import { cancel } from "@ember/runloop";
-import Modifier from "ember-modifier";
+import { service } from "@ember/service";
import { and } from "truth-helpers";
import concatClass from "discourse/helpers/concat-class";
-import discourseLater from "discourse-common/lib/later";
-import { bind } from "discourse-common/utils/decorators";
+import swipe from "discourse/modifiers/swipe";
+import autoCloseToast from "float-kit/modifiers/auto-close-toast";
-const CSS_TRANSITION_DELAY_MS = 300;
-const TRANSITION_CLASS = "-fade-out";
-
-class AutoCloseToast extends Modifier {
- element;
- close;
- duration;
- transitionLaterHandler;
- closeLaterHandler;
- progressBar;
- progressAnimation;
-
- constructor(owner, args) {
- super(owner, args);
-
- registerDestructor(this, (instance) => instance.cleanup());
- }
-
- modify(element, _, { close, duration, progressBar }) {
- this.element = element;
- this.close = close;
- this.duration = duration;
- this.timeRemaining = duration;
- this.progressBar = progressBar;
- this.element.addEventListener("mouseenter", this.stopTimer, {
- passive: true,
- });
- this.element.addEventListener("mouseleave", this.startTimer, {
- passive: true,
- });
- this.startTimer();
- }
-
- @bind
- startTimer() {
- this.startProgressAnimation();
-
- this.transitionLaterHandler = discourseLater(() => {
- this.element.classList.add(TRANSITION_CLASS);
-
- this.closeLaterHandler = discourseLater(() => {
- this.close();
- }, CSS_TRANSITION_DELAY_MS);
- }, this.timeRemaining);
- }
-
- @bind
- stopTimer() {
- this.pauseProgressAnimation();
- cancel(this.transitionLaterHandler);
- cancel(this.closeLaterHandler);
- }
-
- @bind
- startProgressAnimation() {
- if (!this.progressBar) {
- return;
- }
-
- if (this.progressAnimation) {
- this.progressAnimation.play();
- this.progressBar.style.opacity = 1;
- return;
- }
-
- this.progressAnimation = this.progressBar.animate(
- { transform: `scaleX(0)` },
- { duration: this.duration, fill: "forwards" }
- );
- }
-
- @bind
- pauseProgressAnimation() {
- if (
- !this.progressAnimation ||
- this.progressAnimation.currentTime === this.duration
- ) {
- return;
- }
-
- this.progressAnimation.pause();
- this.progressBar.style.opacity = 0.5;
- this.timeRemaining = this.duration - this.progressAnimation.currentTime;
- }
-
- cleanup() {
- this.stopTimer();
- this.element.removeEventListener("mouseenter", this.stopTimer);
- this.element.removeEventListener("mouseleave", this.startTimer);
- this.progressBar = null;
- }
-}
+const CLOSE_SWIPE_THRESHOLD = 50;
export default class DToast extends Component {
+ @service site;
+
@tracked progressBar;
+ animating = false;
+
@action
registerProgressBar(element) {
this.progressBar = element;
}
+ @action
+ async handleSwipe(state) {
+ if (this.animating) {
+ return;
+ }
+
+ if (state.deltaY < 0) {
+ this.#animateWrapperPosition(state.element, 0);
+ return;
+ }
+
+ if (state.deltaY > CLOSE_SWIPE_THRESHOLD) {
+ this.#close(state.element);
+ } else {
+ await this.#animateWrapperPosition(state.element, state.deltaY);
+ }
+ }
+
+ @action
+ async handleSwipeEnded(state) {
+ if (state.deltaY > CLOSE_SWIPE_THRESHOLD) {
+ this.#close(state.element);
+ } else {
+ await this.#animateWrapperPosition(state.element, 0);
+ }
+ }
+
+ async #close(element) {
+ await this.#closeWrapperAnimation(element);
+ this.args.toast.close();
+ }
+
+ async #closeWrapperAnimation(element) {
+ this.animating = true;
+
+ await element.animate([{ transform: "translateY(-150px)" }], {
+ fill: "forwards",
+ duration: 250,
+ }).finished;
+
+ this.animating = false;
+ }
+
+ async #animateWrapperPosition(element, position) {
+ this.animating = true;
+
+ await element.animate([{ transform: `translateY(${-position}px)` }], {
+ fill: "forwards",
+ }).finished;
+
+ this.animating = false;
+ }
+