diff --git a/src/packages/imagepreview/__test__/imagepreview.spec.tsx b/src/packages/imagepreview/__test__/imagepreview.spec.tsx index aa6429bf81..c2023e4c52 100644 --- a/src/packages/imagepreview/__test__/imagepreview.spec.tsx +++ b/src/packages/imagepreview/__test__/imagepreview.spec.tsx @@ -1,148 +1,169 @@ import * as React from 'react' -import { render, waitFor, act } from '@testing-library/react' +import { render, screen, fireEvent } from '@testing-library/react' import '@testing-library/jest-dom' import { ImagePreview } from '../imagepreview' +import { triggerDrag } from '@/utils/test/event' -const images = [ - { - src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/18629/34/3378/144318/5c263f64Ef0e2bff0/0d650e0aa2e852ee.jpg', - }, - { - src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/26597/30/4870/174583/5c35c5d2Ed55eedc6/50e27870c25e7a82.png', - }, - { - src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/9542/17/12873/201687/5c3c4362Ea9eb757d/60026b40a9d60d85.jpg', - }, - { - src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/30042/36/427/82951/5c3bfdabE3faf2f66/9adca782661c988c.jpg', - }, -] - -const videos = [ - { - source: { - src: 'https://storage.jd.com/about/big-final.mp4?Expires=3730193075&AccessKey=3LoYX1dQWa6ZXzQl&Signature=ViMFjz%2BOkBxS%2FY1rjtUVqbopbJI%3D', - type: 'video/mp4', +describe('ImagePreview Component', () => { + const images = [ + { + src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/18629/34/3378/144318/5c263f64Ef0e2bff0/0d650e0aa2e852ee.jpg', }, - options: { - muted: true, - controls: true, + { + src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/26597/30/4870/174583/5c35c5d2Ed55eedc6/50e27870c25e7a82.png', }, - }, - { - source: { - src: 'https://storage.jd.com/about/big-final.mp4?Expires=3730193075&AccessKey=3LoYX1dQWa6ZXzQl&Signature=ViMFjz%2BOkBxS%2FY1rjtUVqbopbJI%3D', - type: 'video/mp4', + { + src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/9542/17/12873/201687/5c3c4362Ea9eb757d/60026b40a9d60d85.jpg', }, - options: { - muted: true, - controls: true, + { + src: '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/30042/36/427/82951/5c3bfdabE3faf2f66/9adca782661c988c.jpg', }, - }, -] - -function sleep(delay = 0): Promise { - return new Promise((resolve) => { - setTimeout(resolve, delay) - }) -} + ] -test('basic usage test', () => { - const { container } = render() + const videos = [ + { + source: { + src: 'https://storage.jd.com/about/big-final.mp4?Expires=3730193075&AccessKey=3LoYX1dQWa6ZXzQl&Signature=ViMFjz%2BOkBxS%2FY1rjtUVqbopbJI%3D', + type: 'video/mp4', + }, + options: { + muted: true, + controls: true, + }, + }, + { + source: { + src: 'https://storage.jd.com/about/big-final.mp4?Expires=3730193075&AccessKey=3LoYX1dQWa6ZXzQl&Signature=ViMFjz%2BOkBxS%2FY1rjtUVqbopbJI%3D', + type: 'video/mp4', + }, + options: { + muted: true, + controls: true, + }, + }, + ] + + const mockOnChange = vi.fn() + const mockOnClose = vi.fn() + + const setup = (props = {}) => { + render( + + ) + } - const element = container.querySelector( - '.nut-imagepreview-pop' - ) as HTMLElement - expect(element.style.display).toEqual('') -}) + afterEach(() => { + vi.clearAllMocks() + }) -test('test autoPlay', async () => { - let _container: any - act(() => { + test('renders correctly when visible', async () => { const { container } = render( - + + ) + expect(screen.getByText('1/6')).toBeInTheDocument() // Assuming pagination is shown + expect((await container).getElementsByTagName('img')[0]).toHaveAttribute( + 'src', + '//m.360buyimg.com/mobilecms/s750x366_jfs/t1/18629/34/3378/144318/5c263f64Ef0e2bff0/0d650e0aa2e852ee.jpg' ) - _container = container }) - const element = _container.querySelector( - '.nut-imagepreview-pop .nut-imagepreview-index' - ) as HTMLElement - expect(element).toHaveTextContent('1') - - await waitFor( - async () => { - await sleep(1100) - expect(element).toHaveTextContent('2') - }, - { - timeout: 2000, - } - ) -}) - -test('init page No.', async () => { - const { container } = render( - - ) - - const element = container.querySelector( - '.nut-imagepreview-pop .nut-imagepreview-index' - ) as HTMLElement - expect(element).toHaveTextContent('3/4') -}) - -test('customize indicator and color', async () => { - const { container } = render( - - ) - - const swiperIndicator = container.querySelector('.nut-imagepreview-swiper') - expect(swiperIndicator).toHaveAttribute( - 'style', - '--nutui-indicator-color: red;' - ) -}) - -test('video surported in H5 env', async () => { - const { container } = render( - - ) - - const nutVideoPlayer = container.querySelector('.nut-video-player') - expect(nutVideoPlayer).toBeInTheDocument() -}) - -test('closeIcon = true', async () => { - const { container } = render( - - ) + test('calls onClose when close icon is clicked', async () => { + const { container } = render( + + ) + const closeIcon = container.querySelector('.nut-imagepreview-close') + expect(closeIcon).toBeInTheDocument() + expect(closeIcon?.classList).toContain('top-right') + fireEvent.click(closeIcon as Element) + expect(mockOnClose).toHaveBeenCalledTimes(1) + }) - const closeIcon = container.querySelector('.nut-imagepreview-close') - expect(closeIcon).toBeInTheDocument() - expect(closeIcon?.classList).toContain('top-right') -}) + test('closes on content click if closeOnContentClick is true', async () => { + const { container } = render( + + ) + const imageElement = container.querySelector('.nut-image-default') + fireEvent.click(imageElement as Element) + expect(mockOnClose).toHaveBeenCalledTimes(1) + }) -test('custom closeIcon', async () => { - const { container } = render( - - ) + test('init page No.', async () => { + const { container } = render( + + ) + const element = container.querySelector( + '.nut-imagepreview-pop .nut-imagepreview-index' + ) as HTMLElement + expect(element).toHaveTextContent('3/4') + }) - const closeIcon = container.querySelector('.nut-imagepreview-close') - expect(closeIcon?.innerHTML).toContain('close') -}) + test('does not close on content click if closeOnContentClick is false', () => { + const { container } = render( + + ) + const imageElement = container.querySelector('.nut-image-default') + fireEvent.click(imageElement as Element) + expect(mockOnClose).toHaveBeenCalledTimes(0) + }) -test('closeIconPosition', async () => { - const { container } = render( - - ) + test('handles zooming in and out on touch events', () => { + const { container } = render() + const swiperIndicator = container.querySelector( + '.nut-imagepreview' + ) as Element + + // Simulate touch start for zoom in + fireEvent.touchStart(swiperIndicator, { + touches: [ + { pageX: 100, pageY: 100 }, + { pageX: 200, pageY: 200 }, + ], + }) + + // Simulate touch move for zooming + fireEvent.touchMove(swiperIndicator, { + touches: [ + { pageX: 100, pageY: 100 }, + { pageX: 300, pageY: 300 }, + ], + }) + + // Verify that scale function has been called or scale state has changed + // Since we don't expose the scale, we may need to check the style if set + expect((swiperIndicator as HTMLElement).style.transform).toContain('scale(') + }) - const closeIcon = container.querySelector('.nut-imagepreview-close') - expect(closeIcon?.classList).toContain('bottom') + test('autoPlay', async () => { + const { container } = render( + + ) + const swiper = container.querySelectorAll('.nut-swiper')[0] + const swiperItem = container.querySelector('.nut-swiper-slide') + triggerDrag(swiper, 220, 0) + expect(swiperItem).toHaveStyle({ + transform: 'translate3d(100%,0,0)', + }) + }) }) diff --git a/src/packages/imagepreview/imagepreview.scss b/src/packages/imagepreview/imagepreview.scss index 48d69e47ef..1587f2886a 100644 --- a/src/packages/imagepreview/imagepreview.scss +++ b/src/packages/imagepreview/imagepreview.scss @@ -62,11 +62,12 @@ } &-pop { + width: 100%; height: 100%; + max-width: 100% !important; background: transparent !important; display: flex; align-items: center; - width: 100%; } &-swiper { diff --git a/src/packages/imagepreview/imagepreview.taro.tsx b/src/packages/imagepreview/imagepreview.taro.tsx index 3c1185f6a8..70128ccb82 100644 --- a/src/packages/imagepreview/imagepreview.taro.tsx +++ b/src/packages/imagepreview/imagepreview.taro.tsx @@ -76,7 +76,7 @@ const defaultProps = { closeIcon: false, closeIconPosition: 'top-right', showMenuByLongpress: false, - onChange: (value: number) => {}, + onChange: () => {}, onClose: () => {}, } as ImagePreviewProps export const ImagePreview: FunctionComponent> = ( @@ -102,24 +102,22 @@ export const ImagePreview: FunctionComponent> = ( onChange, } = { ...defaultProps, ...props } const classPrefix = 'nut-imagepreview' - const ref = useRef(null) + const ref = useRef(null) const [innerNo, setInnerNo] = usePropsValue({ value, defaultValue, finalValue: defaultValue, - onChange: (val: number) => { - onChange?.(val) - }, + onChange, }) const [showPop, setShowPop] = useState(visible) const [active, setActive] = useState(0) - const [maxNo, setMaxNo] = useState( - images?.length || 0 + (videos?.length || 0) - ) - const [store, setStore] = useState({ + const [maxNo, setMaxNo] = useState(images.length + videos.length) + const [store, setStore] = useState({ scale: 1, moveable: false, + oriDistance: 0, + originScale: 1, }) const [lastTouchEndTime, setLastTouchEndTime] = useState(0) // 用来辅助监听双击 const onTouchStart = (event: TouchEvent) => { @@ -128,79 +126,49 @@ export const ImagePreview: FunctionComponent> = ( const events2 = touches[1] // 如果已经放大,双击应变回原尺寸;如果是原尺寸,双击应放大 - const curTouchTime = new Date().getTime() + const curTouchTime = Date.now() if (curTouchTime - lastTouchEndTime < 300) { const store1 = store - if (store1.scale > 1) { - store1.scale = 1 - } else if (store1.scale === 1) { - store1.scale = 2 - } + store1.scale = store1.scale === 1 ? 2 : 1 scaleNow() } - const store1 = store as Store + const store1 = store store1.moveable = true if (events2) { // 如果开始两指操作,记录初始时刻两指间的距离 - store1.oriDistance = getDistance( - { - x: events.pageX, - y: events.pageY, - }, - { - x: events2.pageX, - y: events2.pageY, - } - ) + store1.oriDistance = getDistance(events, events2) } // 取到开始两指操作时的放大(缩小比例),store.scale 存储的是当前的放缩比(相对于标准大小 scale 为 1 的情况的放大缩小比) - store1.originScale = store1.scale || 1 + store1.originScale = store1.scale } const onTouchMove = (event: TouchEvent) => { + if (!store.moveable) return const touches = event.touches const events = touches[0] const events2 = touches[1] - if (!store.moveable) { - return - } - const store1 = store as Store + const store1 = store // 双指移动 if (events2) { - // 获得当前两点间的距离 - const curDistance = getDistance( - { - x: events.pageX, - y: events.pageY, - }, - { - x: events2.pageX, - y: events2.pageY, - } - ) - + const curDistance = getDistance(events, events2) /** 此处计算倍数,距离放大(缩小) k 倍则 scale 也 扩大(缩小) k 倍。距离放大(缩小)倍数 = 结束时两点距离 除以 开始时两点距离 * 注意此处的 scale 变化是基于 store.scale 的。 * store.scale 是一个暂存值,比如第一次放大 2 倍,则 store.scale 为 2。 * 再次两指触碰的时候,store.originScale 就为 store.scale 的值,基于此时的 store.scale 继续放大缩小。 * */ const curScale = curDistance / store1.oriDistance - store1.scale = store1.originScale * curScale - // 最大放大 3 倍,缩小后松手要弹回原比例 - if (store1.scale > 3) { - store1.scale = 3 - } + store1.scale = Math.min(store1.originScale * curScale, 3) scaleNow() } } const onTouchEnd = () => { - setLastTouchEndTime(new Date().getTime()) - const store1 = store as Store + setLastTouchEndTime(Date.now()) + const store1 = store store1.moveable = false if ((store1.scale < 1.1 && store1.scale > 1) || store1.scale < 1) { store1.scale = 1 @@ -229,28 +197,25 @@ export const ImagePreview: FunctionComponent> = ( }, [innerNo]) useEffect(() => { - setMaxNo(images?.length || 0 + (videos?.length || 0)) + setMaxNo(images.length + videos.length) }, [images, videos]) const scaleNow = () => { - if (ref.current as any) { - ;(ref.current as any).style.transform = `scale(${store.scale})` + if (ref.current) { + ref.current.style.transform = `scale(${store.scale})` } } - // 计算两个点的距离 const getDistance = (first: any, second: any) => { - // 计算两个点起始时刻的距离和终止时刻的距离,终止时刻距离变大了则放大,变小了则缩小 - // 放大 k 倍则 scale 也 扩大 k 倍 return Math.hypot( - Math.abs(second.x - first.x), - Math.abs(second.y - first.y) + Math.abs(second.pageX - first.pageX), + Math.abs(second.pageY - first.pageY) ) } const slideChangeEnd = (page: number) => { setActive(page + 1) - onChange?.(page + 1) + onChange && onChange(page + 1) } const onCloseInner = (e: ITouchEvent | React.MouseEvent) => { e.stopPropagation() @@ -264,18 +229,15 @@ export const ImagePreview: FunctionComponent> = ( }) } const closeOnImg = (e: ITouchEvent | React.MouseEvent) => { - // 点击内容区域的图片是否可以关闭弹层(视频区域由于nut-video做了限制,无法关闭弹层) e.stopPropagation() - if (closeOnContentClick) { - onCloseInner(e) - } + // 点击内容区域的图片是否可以关闭弹层(视频区域由于nut-video做了限制,无法关闭弹层) + if (closeOnContentClick) onCloseInner(e) } return ( > = ( style={style} ref={ref} onTouchStart={onTouchStart as any} + onTouchMove={onTouchMove as any} + onTouchEnd={onTouchEnd} + onTouchCancel={onTouchEnd} > > = ( defaultValue={innerNo && (innerNo > maxNo ? maxNo - 1 : innerNo - 1)} indicator={indicator} > - {(videos ?? []) - .map( - (item) => - ({ type: 'video', data: item }) as { - type: 'video' | 'image' - data: ImageOption | VideoOption - } - ) - .concat( - (images ?? []).map((item) => ({ type: 'image', data: item })) - ) + {[ + ...videos.map((item) => ({ type: 'video', data: item })), + ...images.map((item) => ({ type: 'image', data: item })), + ] .sort((a, b) => (a.data?.index ?? 0) - (b.data?.index ?? 0)) - .map((item, index) => { - if (item.type === 'video') { - const { source, options } = item.data as VideoOption - return ( - - - - ) - } - if (item.type === 'image') { - const { src } = item.data as ImageOption - return ( - - - - ) - } - return null - })} + .map((item, index) => ( + + {item.type === 'video' ? ( + + ) : ( + + )} + + ))} - {pagination ? ( + {pagination && ( - {active}/{(images ? images.length : 0) + (videos ? videos.length : 0)} + {active}/{maxNo} - ) : null} - {closeIcon !== false ? ( + )} + {closeIcon !== false && ( {closeIcon === true ? : closeIcon} - ) : null} + )} ) } diff --git a/src/packages/imagepreview/imagepreview.tsx b/src/packages/imagepreview/imagepreview.tsx index 6fa6c844c7..61cddf5881 100644 --- a/src/packages/imagepreview/imagepreview.tsx +++ b/src/packages/imagepreview/imagepreview.tsx @@ -43,19 +43,8 @@ export interface VideoOption { } export interface ImagePreviewProps extends BasicComponent { - images: Array<{ - src: string - }> - videos: Array<{ - source: { - src: string - type: string - } - options: { - muted: boolean - controls: boolean - } - }> + images: ImageOption[] + videos: VideoOption[] visible: boolean autoPlay: number | string value?: number @@ -70,7 +59,7 @@ export interface ImagePreviewProps extends BasicComponent { onClose: () => void } -const defaultProps = { +const defaultProps: ImagePreviewProps = { ...ComponentDefaults, images: [], videos: [], @@ -83,9 +72,9 @@ const defaultProps = { indicatorColor: '#fff', closeIcon: false, closeIconPosition: 'top-right', - onChange: (value: number) => {}, + onChange: () => {}, onClose: () => {}, -} as ImagePreviewProps +} export const ImagePreview: FunctionComponent> = ( props ) => { @@ -108,105 +97,76 @@ export const ImagePreview: FunctionComponent> = ( onChange, } = { ...defaultProps, ...props } const classPrefix = 'nut-imagepreview' - const ref = useRef(null) + const ref = useRef(null) const [innerNo, setInnerNo] = usePropsValue({ value, defaultValue, finalValue: defaultValue, - onChange: (val: number) => { - onChange?.(val) - }, + onChange, }) + console.log('innner0', innerNo, value, defaultValue) + const [showPop, setShowPop] = useState(visible) const [active, setActive] = useState(0) - const [maxNo, setMaxNo] = useState( - images?.length || 0 + (videos?.length || 0) - ) - const [store, setStore] = useState({ + const [maxNo, setMaxNo] = useState(images.length + videos.length) + const [store, setStore] = useState({ scale: 1, moveable: false, + oriDistance: 0, + originScale: 1, }) const [lastTouchEndTime, setLastTouchEndTime] = useState(0) // 用来辅助监听双击 const onTouchStart = (event: TouchEvent) => { - const touches = event.touches + const { touches } = event const events = touches[0] const events2 = touches[1] - // 如果已经放大,双击应变回原尺寸;如果是原尺寸,双击应放大 - const curTouchTime = new Date().getTime() + // 如果是原尺寸,双击放大;否则回到原尺寸。 + const curTouchTime = Date.now() if (curTouchTime - lastTouchEndTime < 300) { const store1 = store - if (store1.scale > 1) { - store1.scale = 1 - } else if (store1.scale === 1) { - store1.scale = 2 - } + store1.scale = store1.scale === 1 ? 2 : 1 scaleNow() } - const store1 = store as Store + const store1 = store store1.moveable = true if (events2) { // 如果开始两指操作,记录初始时刻两指间的距离 - store1.oriDistance = getDistance( - { - x: events.pageX, - y: events.pageY, - }, - { - x: events2.pageX, - y: events2.pageY, - } - ) + store1.oriDistance = getDistance(events, events2) } // 取到开始两指操作时的放大(缩小比例),store.scale 存储的是当前的放缩比(相对于标准大小 scale 为 1 的情况的放大缩小比) - store1.originScale = store1.scale || 1 + store1.originScale = store1.scale } const onTouchMove = (event: TouchEvent) => { - const touches = event.touches + if (!store.moveable) return + + const { touches } = event const events = touches[0] const events2 = touches[1] - if (!store.moveable) { - return - } - const store1 = store as Store + const store1 = store // 双指移动 if (events2) { - // 获得当前两点间的距离 - const curDistance = getDistance( - { - x: events.pageX, - y: events.pageY, - }, - { - x: events2.pageX, - y: events2.pageY, - } - ) - + const curDistance = getDistance(events, events2) /** 此处计算倍数,距离放大(缩小) k 倍则 scale 也 扩大(缩小) k 倍。距离放大(缩小)倍数 = 结束时两点距离 除以 开始时两点距离 * 注意此处的 scale 变化是基于 store.scale 的。 * store.scale 是一个暂存值,比如第一次放大 2 倍,则 store.scale 为 2。 * 再次两指触碰的时候,store.originScale 就为 store.scale 的值,基于此时的 store.scale 继续放大缩小。 * */ const curScale = curDistance / store1.oriDistance - store1.scale = store1.originScale * curScale - // 最大放大 3 倍,缩小后松手要弹回原比例 - if (store1.scale > 3) { - store1.scale = 3 - } + store1.scale = Math.min(store1.originScale * curScale, 3) scaleNow() } } const onTouchEnd = () => { - setLastTouchEndTime(new Date().getTime()) - const store1 = store as Store + setLastTouchEndTime(Date.now()) + const store1 = store store1.moveable = false if ((store1.scale < 1.1 && store1.scale > 1) || store1.scale < 1) { store1.scale = 1 @@ -237,28 +197,26 @@ export const ImagePreview: FunctionComponent> = ( }, [innerNo]) useEffect(() => { - setMaxNo(images?.length || 0 + (videos?.length || 0)) + setMaxNo(images.length + videos.length) }, [images, videos]) const scaleNow = () => { - if (ref.current as any) { - ;(ref.current as any).style.transform = `scale(${store.scale})` + if (ref.current) { + ref.current.style.transform = `scale(${store.scale})` } } - // 计算两个点的距离 + // 用于查找给定数字的斜边。起止两点间距离。 const getDistance = (first: any, second: any) => { - // 计算两个点起始时刻的距离和终止时刻的距离,终止时刻距离变大了则放大,变小了则缩小 - // 放大 k 倍则 scale 也 扩大 k 倍 return Math.hypot( - Math.abs(second.x - first.x), - Math.abs(second.y - first.y) + Math.abs(second.pageX - first.pageX), + Math.abs(second.pageY - first.pageY) ) } const slideChangeEnd = (page: number) => { setActive(page + 1) - onChange?.(page + 1) + onChange && onChange(page + 1) } const onCloseInner = (e: React.MouseEvent) => { @@ -276,16 +234,13 @@ export const ImagePreview: FunctionComponent> = ( const closeOnImg = (e: any) => { e.stopPropagation() // 点击内容区域的图片是否可以关闭弹层(视频区域由于nut-video做了限制,无法关闭弹层) - if (closeOnContentClick) { - onCloseInner(e) - } + if (closeOnContentClick) onCloseInner(e) } const duration = typeof autoPlay === 'string' ? parseInt(autoPlay) : autoPlay return (
> = ( ref={ref} onTouchStart={onTouchStart as any} > - {showPop ? ( + {showPop && ( > = ( }} direction="horizontal" onChange={(page) => slideChangeEnd(page)} - defaultValue={ - innerNo && (innerNo > maxNo ? maxNo - 1 : innerNo - 1) - } + defaultValue={innerNo > maxNo ? maxNo - 1 : innerNo - 1} indicator={indicator} > - {(videos ?? []) - .map( - (item) => - ({ type: 'video', data: item }) as { - type: 'video' | 'image' - data: ImageOption | VideoOption - } - ) - .concat( - (images ?? []).map((item) => ({ type: 'image', data: item })) - ) - .sort((a, b) => (a.data?.index ?? 0) - (b.data?.index ?? 0)) - .map((item, index) => { - if (item.type === 'video') { - const { source, options } = item.data as VideoOption - return ( - - - ) - } - if (item.type === 'image') { - const { src } = item.data as ImageOption - return ( - - - - ) - } - return null - })} + {[ + ...videos.map((item) => ({ type: 'video', data: item })), + ...images.map((item) => ({ type: 'image', data: item })), + ] + .sort((a, b) => (a.data.index ?? 0) - (b.data.index ?? 0)) + .map((item, index) => ( + + {item.type === 'video' ? ( + + ))} - ) : null} + )}
- {pagination ? ( + {pagination && (
- {active}/{(images ? images.length : 0) + (videos ? videos.length : 0)} + {active}/{maxNo}
- ) : null} - {closeIcon !== false ? ( + )} + {closeIcon !== false && (
{closeIcon === true ? : closeIcon}
- ) : null} + )}
) } diff --git a/src/packages/notify/Notification.tsx b/src/packages/notify/Notification.tsx index 599bb3fd01..7e308dcd6c 100644 --- a/src/packages/notify/Notification.tsx +++ b/src/packages/notify/Notification.tsx @@ -114,7 +114,7 @@ export default class Notification extends React.PureComponent< Notification.newInstance = (properties, callback) => { const element = document.createElement('div') - const id = properties.id ? properties.id : `${new Date().getTime()}` + const id = properties.id ? properties.id : `${Date.now()}` element.id = id properties.id = id diff --git a/src/packages/toast/Notification.tsx b/src/packages/toast/Notification.tsx index 733128dc3e..aa3fe7abff 100644 --- a/src/packages/toast/Notification.tsx +++ b/src/packages/toast/Notification.tsx @@ -169,7 +169,7 @@ export default class Notification extends React.PureComponent< Notification.newInstance = (properties, callback) => { const element = document.createElement('div') - const id = properties.id ? properties.id : `${new Date().getTime()}` + const id = properties.id ? properties.id : `${Date.now()}` element.id = id properties.id = id document.body.appendChild(element)