Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(Toast): resume timers if no longer over toast region after a toast is removed #7681

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

reidbarber
Copy link
Member

@reidbarber reidbarber commented Jan 28, 2025

Closes #7024

✅ Pull Request Checklist:

  • Included link to corresponding React Spectrum GitHub Issue.
  • Added/updated unit tests and storybook for this change (for new code or code which already has tests).
  • Filled out test instructions.
  • Updated documentation (if it already exists for this component).
  • Looked at the Accessibility Practices for this feature - Aria Practices

📝 Test Instructions:

  1. In the Toast story with a timeout enabled, open two or more toasts
  2. Close the top one and keep your mouse where it is
  3. Confirm that the remaining toast(s) close after a few seconds due to the timeout. Previously they would not due to the timer not resuming, due to no pointerleave event being fired in this case.

🧢 Your Project:

@reidbarber reidbarber changed the title fix(Toast): check pointer position and resume toast timers if no longer over region fix(Toast): resume timers if no longer over toast region after a toast is removed Jan 28, 2025
@rspbot
Copy link

rspbot commented Jan 28, 2025

@reidbarber reidbarber changed the title fix(Toast): resume timers if no longer over toast region after a toast is removed WIP: fix(Toast): resume timers if no longer over toast region after a toast is removed Jan 28, 2025
@reidbarber reidbarber changed the title WIP: fix(Toast): resume timers if no longer over toast region after a toast is removed fix(Toast): resume timers if no longer over toast region after a toast is removed Jan 30, 2025
@rspbot
Copy link

rspbot commented Jan 30, 2025

Copy link
Member

@snowystinger snowystinger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should get a test for this

}
}
prevToastCount.current = currentCount;
}, [ref, state]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}, [ref, state]);
}, [ref, state.visibleToasts, state.resumeAll]);

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eslint[react-hooks/exhaustive-deps] still wants state here 🤔

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

huh.... ok then i guess, that's so weird
could always pull them off the state object beforehand, the unfortunate part is that the state object will likely always be new, at least, until the react compiler can run on that file

return () => {
document.removeEventListener('pointermove', onPointerMove);
};
}, [state.visibleToasts.length]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}, [state.visibleToasts.length]);
}, [state.visibleToasts]);

just in case there's some situation where one is removed and one is added at the same time?

@rspbot
Copy link

rspbot commented Feb 4, 2025

@rspbot
Copy link

rspbot commented Feb 6, 2025

@rspbot
Copy link

rspbot commented Feb 6, 2025

## API Changes

@react-aria/dnd

/@react-aria/dnd:ClipboardProps

 ClipboardProps {
-  getItems?: ({
-    type: 'cut' | 'copy'
-}) => Array<DragItem>
+  getItems?: () => Array<DragItem>
   isDisabled?: boolean
   onCopy?: () => void
   onCut?: () => void
   onPaste?: (Array<DropItem>) => void

@react-aria/utils

/@react-aria/utils:createShadowTreeWalker

-createShadowTreeWalker {
-  doc: Document
-  root: Node
-  whatToShow?: number
-  filter?: NodeFilter | null
-  returnVal: undefined
-}

/@react-aria/utils:ShadowTreeWalker

-ShadowTreeWalker {
-  constructor: (Document, Node, number, NodeFilter | null) => void
-  currentNode: Node
-  doc: Document
-  filter: NodeFilter | null
-  firstChild: () => Node | null
-  lastChild: () => Node | null
-  nextNode: () => Node | null
-  previousNode: () => Node | null
-  root: Node
-  whatToShow: number
-}

/@react-aria/utils:getActiveElement

-getActiveElement {
-  doc: Document
-  returnVal: undefined
-}

/@react-aria/utils:getEventTarget

-getEventTarget {
-  event: any
-  returnVal: undefined
-}

/@react-aria/utils:nodeContains

-nodeContains {
-  node: Node | null | undefined
-  otherNode: Node | null | undefined
-  returnVal: undefined
-}

/@react-aria/utils:isShadowRoot

-isShadowRoot {
-  node: Node | null
-  returnVal: undefined
-}

@react-spectrum/s2

/@react-spectrum/s2:Heading

 Heading {
   UNSAFE_className?: string
   UNSAFE_style?: CSSProperties
   children?: ReactNode
-  id?: string
   isHidden?: boolean
   level?: number
   slot?: string | null
   styles?: StyleString

/@react-spectrum/s2:Header

 Header {
   UNSAFE_className?: string
   UNSAFE_style?: CSSProperties
   children?: ReactNode
-  id?: string
   isHidden?: boolean
   slot?: string | null
   styles?: StyleString
 }

/@react-spectrum/s2:Content

 Content {
   UNSAFE_className?: string
   UNSAFE_style?: CSSProperties
   children?: ReactNode
-  id?: string
   isHidden?: boolean
   slot?: string | null
   styles?: StyleString
 }

/@react-spectrum/s2:Footer

 Footer {
   UNSAFE_className?: string
   UNSAFE_style?: CSSProperties
   children?: ReactNode
-  id?: string
   isHidden?: boolean
   slot?: string | null
   styles?: StyleString
 }

/@react-spectrum/s2:Text

 Text {
   UNSAFE_className?: string
   UNSAFE_style?: CSSProperties
   children?: ReactNode
-  id?: string
   isHidden?: boolean
   slot?: string | null
   styles?: StyleString
 }

/@react-spectrum/s2:Keyboard

 Keyboard {
   UNSAFE_className?: string
   UNSAFE_style?: CSSProperties
   children?: ReactNode
-  id?: string
   isHidden?: boolean
   slot?: string | null
   styles?: StyleString
 }

/@react-spectrum/s2:Tabs

 Tabs {
   UNSAFE_className?: string
   UNSAFE_style?: CSSProperties
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   children?: ReactNode
   defaultSelectedKey?: Key
   density?: 'compact' | 'regular' = 'regular'
   disabledKeys?: Iterable<Key>
   id?: string
   isDisabled?: boolean
   keyboardActivation?: 'automatic' | 'manual' = 'automatic'
-  labelBehavior?: 'show' | 'hide' = 'show'
   onSelectionChange?: (Key) => void
   orientation?: Orientation = 'horizontal'
   selectedKey?: Key | null
   slot?: string | null
 }

/@react-spectrum/s2:TabList

 TabList <T extends {}> {
   UNSAFE_className?: string
   UNSAFE_style?: CSSProperties
   aria-describedby?: string
   aria-details?: string
-  children?: ReactNode | (T) => ReactNode
+  aria-label?: string
+  aria-labelledby?: string
+  children?: ReactNode
   dependencies?: Array<any>
   items?: Iterable<T>
   styles?: StylesProp
 }

/@react-spectrum/s2:Tab

 Tab {
   UNSAFE_className?: string
   UNSAFE_style?: CSSProperties
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
-  children: ReactNode
+  children?: ReactNode
   download?: boolean | string
   href?: Href
   hrefLang?: string
   id?: Key
   onHoverChange?: (boolean) => void
   onHoverEnd?: (HoverEvent) => void
   onHoverStart?: (HoverEvent) => void
   ping?: string
   referrerPolicy?: HTMLAttributeReferrerPolicy
   rel?: string
   routerOptions?: RouterOptions
   styles?: StylesProp
   target?: HTMLAttributeAnchorTarget
 }

/@react-spectrum/s2:ImageProps

 ImageProps {
   UNSAFE_className?: string
   UNSAFE_style?: CSSProperties
   alt?: string
   crossOrigin?: 'anonymous' | 'use-credentials'
   decoding?: 'async' | 'auto' | 'sync'
-  fetchPriority?: 'high' | 'low' | 'auto'
   group?: ImageGroup
   loading?: 'eager' | 'lazy'
   referrerPolicy?: HTMLAttributeReferrerPolicy
   renderError?: () => ReactNode
   src?: string
   styles?: StyleString
 }

/@react-spectrum/s2:TabsProps

 TabsProps {
   UNSAFE_className?: string
   UNSAFE_style?: CSSProperties
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   children?: ReactNode
   defaultSelectedKey?: Key
   density?: 'compact' | 'regular' = 'regular'
   disabledKeys?: Iterable<Key>
   id?: string
   isDisabled?: boolean
   keyboardActivation?: 'automatic' | 'manual' = 'automatic'
-  labelBehavior?: 'show' | 'hide' = 'show'
   onSelectionChange?: (Key) => void
   orientation?: Orientation = 'horizontal'
   selectedKey?: Key | null
   slot?: string | null
 }

/@react-spectrum/s2:TabProps

 TabProps {
   UNSAFE_className?: string
   UNSAFE_style?: CSSProperties
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
-  children: ReactNode
+  children?: ReactNode
   download?: boolean | string
   href?: Href
   hrefLang?: string
   id?: Key
   onHoverChange?: (boolean) => void
   onHoverEnd?: (HoverEvent) => void
   onHoverStart?: (HoverEvent) => void
   ping?: string
   referrerPolicy?: HTMLAttributeReferrerPolicy
   rel?: string
   routerOptions?: RouterOptions
   styles?: StylesProp
   target?: HTMLAttributeAnchorTarget
 }

/@react-spectrum/s2:TabListProps

 TabListProps <T> {
   UNSAFE_className?: string
   UNSAFE_style?: CSSProperties
   aria-describedby?: string
   aria-details?: string
-  children?: ReactNode | (T) => ReactNode
+  aria-label?: string
+  aria-labelledby?: string
+  children?: ReactNode
   dependencies?: Array<any>
   items?: Iterable<T>
   styles?: StylesProp
 }

@react-stately/data

/@react-stately/data:TreeData

 TreeData <T extends {}> {
   append: (Key | null, Array<{}>) => void
   getItem: (Key) => TreeNode<{}> | undefined
   insert: (Key | null, number, Array<{}>) => void
   insertAfter: (Key, Array<{}>) => void
   insertBefore: (Key, Array<{}>) => void
   items: Array<TreeNode<{}>>
   move: (Key, Key | null, number) => void
-  moveAfter: (Key, Key | null, number) => void
-  moveBefore: (Key, Key | null, number) => void
   prepend: (Key | null, Array<{}>) => void
   remove: (Array<Key>) => void
   removeSelectedItems: () => void
   selectedKeys: Set<Key>
   update: (Key, {}) => void
 }

@react-stately/flags

/@react-stately/flags:enableShadowDOM

-enableShadowDOM {
-  returnVal: undefined
-}

/@react-stately/flags:shadowDOM

-shadowDOM {
-  returnVal: undefined
-}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Multiple auto-dismiss toasts
3 participants