Browse Source

Merge pull request #16769 from overleaf/jel-scroll-to-notification

[web] Add scroll to notification component

GitOrigin-RevId: 096f9f42344729464e7fb38e4f6542cb2e891918
Jessica Lawshe 2 năm trước cách đây
mục cha
commit
f79f534d9f

+ 46 - 0
services/web/frontend/js/shared/components/notification-scrolled-to.tsx

@@ -0,0 +1,46 @@
+import Notification, {
+  NotificationProps,
+} from '@/shared/components/notification'
+import { useEffect } from 'react'
+
+function elementIsInView(el: HTMLElement) {
+  const scroll = window.scrollY
+  const boundsTop = el.getBoundingClientRect().top + scroll
+
+  const viewport = {
+    top: scroll,
+    bottom: scroll + window.innerHeight,
+  }
+
+  const bounds = {
+    top: boundsTop,
+    bottom: boundsTop + el.clientHeight,
+  }
+
+  return (
+    (bounds.bottom >= viewport.top && bounds.bottom <= viewport.bottom) ||
+    (bounds.top <= viewport.bottom && bounds.top >= viewport.top)
+  )
+}
+
+function NotificationScrolledTo({ ...props }: NotificationProps) {
+  useEffect(() => {
+    if (props.id) {
+      const alert = document.getElementById(props.id)
+      if (alert && !elementIsInView(alert)) {
+        alert.scrollIntoView({ behavior: 'smooth' })
+      }
+    }
+  }, [props])
+
+  const notificationProps = { ...props }
+
+  if (!notificationProps.className) {
+    notificationProps.className = ''
+  }
+
+  notificationProps.className = `${notificationProps.className} notification-with-scroll-margin`
+
+  return <Notification {...notificationProps} />
+}
+export default NotificationScrolledTo

+ 4 - 1
services/web/frontend/js/shared/components/notification.tsx

@@ -10,7 +10,7 @@ export type NotificationType =
   | 'error'
   | 'offer'
 
-type NotificationProps = {
+export type NotificationProps = {
   action?: React.ReactElement
   ariaLive?: 'polite' | 'off' | 'assertive'
   className?: string
@@ -21,6 +21,7 @@ type NotificationProps = {
   onDismiss?: () => void
   title?: string
   type: NotificationType
+  id?: string
 }
 
 function NotificationIcon({
@@ -57,6 +58,7 @@ function Notification({
   onDismiss,
   title,
   type,
+  id,
 }: NotificationProps) {
   type = type || 'info'
   const { t } = useTranslation()
@@ -83,6 +85,7 @@ function Notification({
       className={notificationClassName}
       aria-live={ariaLive || 'off'}
       role="alert"
+      id={id}
     >
       <NotificationIcon notificationType={type} customIcon={customIcon} />
 

+ 0 - 9
services/web/frontend/stylesheets/components/forms.less

@@ -192,15 +192,6 @@ input[type='date'] {
   margin-bottom: @form-group-margin-bottom;
 }
 
-// Form alert
-//
-// adds top padding/mergin so that element has spacing when scrolled into
-// view, but no vertical spacing is applied to layout
-.form-group#form-alert {
-  padding-top: @form-group-margin-bottom;
-  margin-top: -@form-group-margin-bottom;
-}
-
 // Checkboxes and radios
 //
 // Indent the labels to position radios/checkboxes as hanging controls.

+ 4 - 0
services/web/frontend/stylesheets/components/notifications.less

@@ -180,6 +180,10 @@
   }
 }
 
+.notification-with-scroll-margin {
+  scroll-margin: 16px;
+}
+
 .notification-list {
   .notification {
     margin-bottom: @margin-md;