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

feat: v15 popup #2844

Merged
merged 19 commits into from
Dec 24, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28,078 changes: 28,078 additions & 0 deletions pnpm-lock.pr!oasis-cloud!2842.yaml
Copy link
Collaborator

Choose a reason for hiding this comment

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

这个文件不提交

Large diffs are not rendered by default.

Large diffs are not rendered by default.

43 changes: 43 additions & 0 deletions src/packages/address/__test__/address.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useRef } from 'react'
import { fireEvent, render, waitFor } from '@testing-library/react'
import '@testing-library/jest-dom'
import { Star } from '@nutui/icons-react'
import { Address } from '../address'

const existList = [
Expand Down Expand Up @@ -117,6 +118,48 @@ test('Address: show custom', async () => {
expect(container.innerHTML).toMatchSnapshot()
})

test('Address: show custom', async () => {
const { container } = render(
<Address visible options={optionsDemo1} custom title="选择地址" />
)
expect(container.innerHTML).toMatchSnapshot()
})

test('Address: show custom icon', async () => {
const { container } = render(
<Address
visible
options={optionsDemo1}
custom
backIcon={<Star />}
title="选择地址"
/>
)
expect(container.innerHTML).toMatchSnapshot()
})

test('Address: show custom icon', async () => {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

注意:测试用例命名重复

存在两个同名的测试用例 "Address: show custom icon",这可能会导致测试结果的混淆。建议为第二个测试用例使用更具描述性的名称。

-test('Address: show custom icon', async () => {
+test('Address: show custom icon with exist address', async () => {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
test('Address: show custom icon', async () => {
test('Address: show custom icon with exist address', async () => {

const onExistSelect = vi.fn()
const onSwitch = vi.fn()
const { container } = render(
<Address
visible
type="exist"
existList={existList}
options={optionsDemo1}
custom="选择其他地址"
onExistSelect={onExistSelect}
onSwitch={onSwitch}
/>
)
expect(container.innerHTML).toMatchSnapshot()
const btn = container.querySelector('.nut-address-footer-btn') as Element
fireEvent.click(btn)
const leftIcon = container.querySelector('.nut-address-left-icon') as Element
expect(leftIcon).toBeTruthy()
fireEvent.click(leftIcon)
})
Comment on lines +141 to +161
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

建议优化事件处理函数的测试

当前测试中的事件处理函数 onExistSelectonSwitch 虽然被模拟,但没有验证它们是否被正确调用。建议添加相应的断言。

 test('Address: show custom icon', async () => {
   const onExistSelect = vi.fn()
   const onSwitch = vi.fn()
   const { container } = render(
     <Address
       visible
       type="exist"
       existList={existList}
       options={optionsDemo1}
       custom="选择其他地址"
       onExistSelect={onExistSelect}
       onSwitch={onSwitch}
     />
   )
   expect(container.innerHTML).toMatchSnapshot()
   const btn = container.querySelector('.nut-address-footer-btn') as Element
   fireEvent.click(btn)
+  expect(onSwitch).toHaveBeenCalled()
   const leftIcon = container.querySelector('.nut-address-left-icon') as Element
   expect(leftIcon).toBeTruthy()
   fireEvent.click(leftIcon)
+  expect(onExistSelect).toHaveBeenCalled()
 })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
test('Address: show custom icon', async () => {
const onExistSelect = vi.fn()
const onSwitch = vi.fn()
const { container } = render(
<Address
visible
type="exist"
existList={existList}
options={optionsDemo1}
custom="选择其他地址"
onExistSelect={onExistSelect}
onSwitch={onSwitch}
/>
)
expect(container.innerHTML).toMatchSnapshot()
const btn = container.querySelector('.nut-address-footer-btn') as Element
fireEvent.click(btn)
const leftIcon = container.querySelector('.nut-address-left-icon') as Element
expect(leftIcon).toBeTruthy()
fireEvent.click(leftIcon)
})
test('Address: show custom icon', async () => {
const onExistSelect = vi.fn()
const onSwitch = vi.fn()
const { container } = render(
<Address
visible
type="exist"
existList={existList}
options={optionsDemo1}
custom="选择其他地址"
onExistSelect={onExistSelect}
onSwitch={onSwitch}
/>
)
expect(container.innerHTML).toMatchSnapshot()
const btn = container.querySelector('.nut-address-footer-btn') as Element
fireEvent.click(btn)
expect(onSwitch).toHaveBeenCalled()
const leftIcon = container.querySelector('.nut-address-left-icon') as Element
expect(leftIcon).toBeTruthy()
fireEvent.click(leftIcon)
expect(onExistSelect).toHaveBeenCalled()
})


test('Address: options disabled', async () => {
const { container } = render(<Address visible options={optionsDemo1} />)
const items = container.querySelectorAll('.nut-cascader-item')
Expand Down
25 changes: 12 additions & 13 deletions src/packages/address/address.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,19 +121,18 @@ export const InternalAddress: ForwardRefRenderFunction<
}

const renderLeftOnCustomSwitch = () => {
return (
<>
{custom && (
<div className={`${classPrefix}-left-icon`} onClick={onSwitchModule}>
{React.isValidElement(backIcon) ? (
backIcon
) : (
<ArrowLeft color="#cccccc" />
)}
</div>
)}
</>
)
if (custom) {
return (
<div className={`${classPrefix}-left-icon`} onClick={onSwitchModule}>
{React.isValidElement(backIcon) ? (
backIcon
) : (
<ArrowLeft color="#cccccc" />
)}
</div>
)
}
return null
Comment on lines +124 to +135
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

建议:在回调中使用最新状态以避免逻辑错误

当前的 onSwitchModule 函数在更新 currentType 之后,才调用了 onSwitch 回调,但回调参数仍然是之前旧的 currentType 值,这可能导致不符合预期的行为。建议先用一个局部变量存储新的类型,再统一更新并调用回调,以确保回调函数拿到最新的类型值。

可以参考以下修正示例:

-const onSwitchModule = () => {
-  if (currentType === 'exist') {
-    setCurrentType('custom')
-  } else {
-    setCurrentType('exist')
-  }
-  onSwitch && onSwitch({ type: currentType })
+const onSwitchModule = () => {
+  const newType = currentType === 'exist' ? 'custom' : 'exist'
+  setCurrentType(newType)
+  onSwitch && onSwitch({ type: newType })
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (custom) {
return (
<div className={`${classPrefix}-left-icon`} onClick={onSwitchModule}>
{React.isValidElement(backIcon) ? (
backIcon
) : (
<ArrowLeft color="#cccccc" />
)}
</div>
)
}
return null
if (custom) {
return (
<div className={`${classPrefix}-left-icon`} onClick={onSwitchModule}>
{React.isValidElement(backIcon) ? (
backIcon
) : (
<ArrowLeft color="#cccccc" />
)}
</div>
)
}
return null

}

const selectedExistItem = (data: AddressList) => {
Expand Down
1 change: 0 additions & 1 deletion src/packages/cascader/cascader.taro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,6 @@ const InternalCascader: ForwardRefRenderFunction<
{...popupProps}
visible={innerVisible}
position="bottom"
style={{ overflowY: 'hidden' }}
round
closeIcon={closeIcon}
closeable={closeable}
Expand Down
12 changes: 6 additions & 6 deletions src/packages/overlay/overlay.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,6 @@
z-index: $overlay-zIndex;
}

[dir='rtl'] .nut-overlay,
.nut-rtl .nut-overlay {
left: auto;
right: 0;
}

.nut-overflow-hidden {
overflow: hidden !important;
}
Expand Down Expand Up @@ -67,3 +61,9 @@
animation-duration: $overlay-animation-duration;
}
}

[dir='rtl'] .nut-overlay,
.nut-rtl .nut-overlay {
left: auto;
right: 0;
}
33 changes: 32 additions & 1 deletion src/packages/popup/__tests__/popup.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,28 @@ test('pop from right', () => {
expect(pop).toBeTruthy()
})

test('pop title', () => {
const { container } = render(<Popup title="标题" visible position="bottom" />)
const title = container.querySelector('.nut-popup-title-title') as HTMLElement
expect(title).toHaveTextContent('标题')
})

test('pop left', () => {
const { container } = render(<Popup left="返回" visible position="bottom" />)
const title = container.querySelector('.nut-popup-title-left') as HTMLElement
expect(title).toHaveTextContent('返回')
})

test('pop description', () => {
const { container } = render(
<Popup description="副标题" visible position="bottom" />
)
const title = container.querySelector(
'.nut-popup-title-description'
) as HTMLElement
expect(title).toHaveTextContent('副标题')
})

test('should render close icon when using closeable prop', () => {
const { container } = render(<Popup visible closeable />)
const closeIcon = container.querySelector(
Expand Down Expand Up @@ -117,7 +139,6 @@ test('event click-title-right icon and keep overlay test ', () => {
const closeIcon = container.querySelector(
'.nut-popup-title-right'
) as HTMLElement
const overlay = container.querySelector('.nut-overlay') as Element
fireEvent.click(closeIcon)
expect(onCloseIconClick).toBeCalled()
const overlay2 = container.querySelector('.hidden-render') as Element
Expand All @@ -140,3 +161,13 @@ test('event click-overlay test', async () => {
fireEvent.click(overlay)
expect(onOverlayClick).toBeCalled()
})

test('pop destroyOnClose', () => {
const onClose = vi.fn()
const { container } = render(
<Popup visible destroyOnClose onClose={onClose} />
)
const overlay = container.querySelector('.nut-overlay') as Element
fireEvent.click(overlay)
expect(onClose).toBeCalled()
})
4 changes: 1 addition & 3 deletions src/packages/popup/demo.taro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,7 @@ const PopupDemo = () => {
return (
<>
<Header />
<ScrollView
className={`${!harmonyAndRn() ? `demo ${Taro.getEnv() === 'WEB' ? 'web' : ''}` : ''}`}
>
<ScrollView className={`demo ${Taro.getEnv() === 'WEB' ? 'web' : ''}`}>
<View className="h2">{translated.ce5c5446}</View>
<Demo1 />

Expand Down
21 changes: 12 additions & 9 deletions src/packages/popup/demos/h5/demo1.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
import React, { useState } from 'react'
import { Popup, Cell } from '@nutui/nutui-react'

const Demo1 = () => {
const [showBasic, setShowBasic] = useState(false)
const Demo = () => {
const [showIcon, setShowIcon] = useState(false)

return (
<>
<Cell
title="展示弹出层"
title="基础弹框"
onClick={() => {
setShowBasic(true)
setShowIcon(true)
}}
/>
<Popup
zIndex={2000}
visible={showBasic}
style={{ padding: '30px 50px' }}
closeable
visible={showIcon}
title="标题"
description="这里是副标题这是副标题"
position="bottom"
onClose={() => {
setShowBasic(false)
setShowIcon(false)
}}
/>
</>
)
}
export default Demo1
export default Demo
24 changes: 22 additions & 2 deletions src/packages/popup/demos/h5/demo2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const Demo2 = () => {
const [showBottom, setShowBottom] = useState(false)
const [showLeft, setShowLeft] = useState(false)
const [showRight, setShowRight] = useState(false)
const [showText, setShowText] = useState(false)

return (
<>
Expand Down Expand Up @@ -33,6 +34,12 @@ const Demo2 = () => {
setShowRight(true)
}}
/>
<Cell
title="居中弹出"
onClick={() => {
setShowText(true)
}}
/>
<Popup
visible={showTop}
destroyOnClose
Expand All @@ -50,20 +57,33 @@ const Demo2 = () => {
/>
<Popup
visible={showLeft}
style={{ width: '40%', height: '100%' }}
position="left"
onClose={() => {
setShowLeft(false)
}}
/>
<Popup
visible={showRight}
style={{ width: '40%', height: '100%' }}
position="right"
onClose={() => {
setShowRight(false)
}}
/>
<Popup
visible={showText}
style={{ padding: '30px 50px' }}
onClose={() => {
setShowText(false)
}}
>
<div style={{ height: '100px', overflowY: 'auto' }}>
{Array.from({ length: 10 })
.fill('')
.map((_, i) => (
<Cell key={i}>正文</Cell>
))}
</div>
</Popup>
</>
)
}
Expand Down
33 changes: 13 additions & 20 deletions src/packages/popup/demos/taro/demo1.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,28 @@
import React, { useState } from 'react'
import { Popup, Cell } from '@nutui/nutui-react-taro'
import { ScrollView, Text } from '@tarojs/components'

const Demo1 = () => {
const [showBasic, setShowBasic] = useState(false)
const Demo = () => {
const [showIcon, setShowIcon] = useState(false)

return (
<>
<Cell
title="展示弹出层"
title="基础弹框"
onClick={() => {
setShowBasic(true)
setShowIcon(true)
}}
/>
<Popup
visible={showBasic}
style={{ padding: '30px 50px' }}
closeable
visible={showIcon}
title="标题"
description="这里是副标题这是副标题"
position="bottom"
onClose={() => {
setShowBasic(false)
setShowIcon(false)
}}
>
<ScrollView style={{ height: '200px', overflowY: 'scroll' }}>
{Array.from({ length: 1 })
.fill('')
.map((_, i) => (
<Cell key={i}>
<Text>正文</Text>
</Cell>
))}
</ScrollView>
</Popup>
/>
</>
)
}
export default Demo1
export default Demo
Loading
Loading