diff --git a/web/app/components/document/sidebar/related-resources.ts b/web/app/components/document/sidebar/related-resources.ts index e81294c08..d8d513d79 100644 --- a/web/app/components/document/sidebar/related-resources.ts +++ b/web/app/components/document/sidebar/related-resources.ts @@ -19,6 +19,7 @@ import { assert } from "@ember/debug"; import HermesFlashMessagesService from "hermes/services/flash-messages"; import { FLASH_MESSAGES_LONG_TIMEOUT } from "hermes/utils/ember-cli-flash/timeouts"; import updateRelatedResourcesSortOrder from "hermes/utils/update-related-resources-sort-order"; +import highlightElement from "hermes/utils/ember-animated/highlight-element"; import scrollIntoViewIfNeeded from "hermes/utils/scroll-into-view-if-needed"; export interface DocumentSidebarRelatedResourcesComponentArgs { @@ -260,30 +261,7 @@ export default class DocumentSidebarRelatedResourcesComponent extends Component< }); }); - const highlight = document.createElement("div"); - highlight.classList.add("highlight-affordance"); - target.insertBefore(highlight, target.firstChild); - - const fadeInAnimation = highlight.animate( - [{ opacity: 0 }, { opacity: 1 }], - { duration: 50 }, - ); - - await timeout(Ember.testing ? 0 : 2000); - - const fadeOutAnimation = highlight.animate( - [{ opacity: 1 }, { opacity: 0 }], - { duration: Ember.testing ? 50 : 400 }, - ); - - try { - await fadeInAnimation.finished; - await fadeOutAnimation.finished; - } finally { - fadeInAnimation.cancel(); - fadeOutAnimation.cancel(); - highlight.remove(); - } + highlightElement(target); }); }, ); diff --git a/web/app/utils/ember-animated/highlight-element.ts b/web/app/utils/ember-animated/highlight-element.ts new file mode 100644 index 000000000..e9f5b1584 --- /dev/null +++ b/web/app/utils/ember-animated/highlight-element.ts @@ -0,0 +1,38 @@ +import Ember from "ember"; +import { timeout } from "ember-concurrency"; + +/** + * Adds a temporary highlight to a relatively positioned element. + * Used to draw attention to an item, such as a related resource + * that's been added or modified. + */ + +export default async function highlightElement(target: Element) { + const highlight = document.createElement("div"); + + highlight.setAttribute("aria-hidden", "true"); + highlight.classList.add("highlight-affordance"); + + target.appendChild(highlight); + + const fadeInAnimation = highlight.animate([{ opacity: 0 }, { opacity: 1 }], { + duration: Ember.testing ? 0 : 50, + fill: "forwards", + }); + + await timeout(Ember.testing ? 0 : 2000); + + const fadeOutAnimation = highlight.animate([{ opacity: 1 }, { opacity: 0 }], { + duration: Ember.testing ? 0 : 400, + fill: "forwards", + }); + + try { + await fadeInAnimation.finished; + await fadeOutAnimation.finished; + } finally { + fadeInAnimation.cancel(); + fadeOutAnimation.cancel(); + highlight.remove(); + } +}