Skip to content

Commit 75057e6

Browse files
xiaoyatongMiles-hxyYONGQIRyan-CW-Code
authored
feat(popup): 增加一些新属性,顺便解决了下input的只读无法点击、焦点等问题 (#3342)
* chore(release): v3.0.18 * fix(swiper): duration属性透传 (#3337) * feat: 修复属性透传 * feat: 直接删除duration * fix(range): taro环境异步渲染useReady不会触发 (#3297) * fix(range): taro环境异步渲染useReady不会触发 * refactor: 将组件中使用的useReady替换为useLayoutEffect * chore: 升级版本号 * feat(popup): 增加上下滑动修改高度 * fix(input): 兼容h5和小程序获取原生input标签 (#3341) * feat: inputRef获取真实input-dom * feat: 兼容小程序和h5获取input标签 * feat: 取消?问好,出错直接抛出 * feat(Popup): 新增弹层可上下滑动 (#3340) * feat: 支持popup 高度可以伸缩 * feat: 适配小程序 * feat: 修改文档 * fix: 默认值不需要,走样式 * feat: 增加使用的限制条件 * docs: 增加文档 * fix: 适配鸿蒙,初始值重置修改 * test: 添加单测 * fix: 增加h5 的初始值 * fix: 增加高度下限约束 * test: fix 单测 * feat(popup): 添加自定义顶部 * fix(input): taro 下只读可以点击 --------- Co-authored-by: Alex.hxy <1872591453@qq.com> Co-authored-by: YONGQI <holyfata@qq.com> Co-authored-by: RyanCW <75795462+Ryan-CW-Code@users.noreply.github.com>
1 parent 7ee836a commit 75057e6

File tree

20 files changed

+471
-89
lines changed

20 files changed

+471
-89
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
# v3.0.18
2+
3+
`2025-08-15`
4+
5+
- 🏡 chore: 升级icon库 (#3330)
6+
- 🏡 chore: 发布taro下的样式按需插件
7+
- 📖 docs: 更新介绍部分内容 (#3324)
8+
- :sparkles: feat: Ellipsis校验越界不走缓存配置 (#3329)
9+
- :sparkles: feat(price): 支持自定义颜色&数据原样输出 (#3328)
10+
- :sparkles: feat(notify): 支持promise调用notice (#3319)
11+
- :bug: fix(noticebar): 适配鸿蒙样式修复 (#3332)
12+
- :bug: Fix icons svg (#3331)
13+
114
# v3.0.17
215

316
`2025-08-01`

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@nutui/nutui-react-taro",
3-
"version": "3.0.18-cpp.beta.0",
3+
"version": "3.0.18-cpp",
44
"style": "dist/style.css",
55
"main": "dist/nutui.react.umd.js",
66
"module": "dist/es/packages/nutui.react.build.js",

src/packages/input/input.taro.tsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,16 +77,28 @@ export const Input = forwardRef((props: Partial<TaroInputProps>, ref) => {
7777
const inputRef = useRef<HTMLInputElement>(null)
7878
const [active, setActive] = useState(false)
7979

80+
// 兼容H5和小程序获取原生input标签
81+
const getNativeInput = () => {
82+
if (Taro.getEnv() === 'WEB') {
83+
const taroInputCoreEl = inputRef.current as HTMLElement
84+
const inputEl = taroInputCoreEl.querySelector('input')
85+
return inputEl
86+
}
87+
return inputRef.current
88+
}
89+
8090
useImperativeHandle(ref, () => {
8191
return {
8292
clear: () => {
8393
setValue('')
8494
},
8595
focus: () => {
86-
inputRef.current?.focus()
96+
const nativeInput = getNativeInput()
97+
nativeInput?.focus()
8798
},
8899
blur: () => {
89-
inputRef.current?.blur()
100+
const nativeInput = getNativeInput()
101+
nativeInput?.blur()
90102
},
91103
get nativeElement() {
92104
return inputRef.current
@@ -183,7 +195,7 @@ export const Input = forwardRef((props: Partial<TaroInputProps>, ref) => {
183195
placeholder === undefined ? locale.placeholder : placeholder
184196
}
185197
placeholderClass={`${classPrefix}-placeholder`}
186-
disabled={disabled || readOnly}
198+
disabled={disabled}
187199
value={value}
188200
focus={autoFocus || focus}
189201
confirmType={confirmType}

src/packages/popup/__tests__/popup.spec.tsx

Lines changed: 61 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,22 @@
11
import * as React from 'react'
2-
import { render, fireEvent } from '@testing-library/react'
2+
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
33
import '@testing-library/jest-dom'
44
import { Popup } from '../popup'
55

6-
test('should change z-index when using z-index prop', () => {
7-
const { container } = render(<Popup visible zIndex={99} />)
8-
const element = container.querySelector('.nut-popup') as HTMLElement
9-
expect(element.style.zIndex).toEqual('99')
6+
test('renders without crashing', () => {
7+
render(<Popup visible>Test Content</Popup>)
8+
expect(screen.getByText('Test Content')).toBeInTheDocument()
109
})
1110

12-
test('prop overlay-class test', async () => {
13-
const { container } = render(<Popup visible overlayClassName="testclas" />)
14-
const overlay = container.querySelector('.nut-overlay') as HTMLElement
15-
expect(overlay).toHaveClass('testclas')
16-
})
11+
test('opens and closes correctly', () => {
12+
const { rerender } = render(<Popup visible={false}>Test Content</Popup>)
1713

18-
test('prop overlay-style test', async () => {
19-
const { container } = render(
20-
<Popup visible overlayStyle={{ color: 'red' }} />
21-
)
22-
const overlay = container.querySelector('.nut-overlay') as HTMLElement
23-
expect(overlay).toHaveStyle({
24-
color: 'red',
25-
})
26-
})
14+
// Initially, it should not be visible
15+
expect(screen.queryByText('Test Content')).not.toBeInTheDocument()
2716

28-
test('should lock scroll when showed', async () => {
29-
const { rerender } = render(<Popup visible={false} />)
30-
rerender(<Popup visible />)
31-
expect(document.body.classList.contains('nut-overflow-hidden')).toBe(true)
17+
// Rerender with visible true
18+
rerender(<Popup visible>Test Content</Popup>)
19+
expect(screen.getByText('Test Content')).toBeInTheDocument()
3220
})
3321

3422
test('should not render overlay when overlay prop is false', () => {
@@ -91,6 +79,14 @@ test('pop description', () => {
9179
expect(title).toHaveTextContent('副标题')
9280
})
9381

82+
test('pop minHeight', () => {
83+
const { container } = render(
84+
<Popup minHeight="30%" visible position="bottom" />
85+
)
86+
const node = container.querySelector('.nut-popup') as HTMLElement
87+
expect(node).toHaveStyle({ minHeight: '30%' })
88+
})
89+
9490
test('should render close icon when using closeable prop', () => {
9591
const { container } = render(<Popup visible closeable />)
9692
const closeIcon = container.querySelector(
@@ -145,11 +141,15 @@ test('event click-title-right icon and keep overlay test ', () => {
145141
expect(overlay2).toBeNull()
146142
})
147143

148-
test('should emit open event when prop visible is set to true', () => {
144+
test('should emit open event when prop visible is set to true', async () => {
149145
const onOpen = vi.fn()
150146
const { rerender } = render(<Popup visible={false} onOpen={onOpen} />)
151-
rerender(<Popup visible onOpen={onOpen} />)
152-
expect(onOpen).toBeCalled()
147+
rerender(
148+
<Popup visible onOpen={onOpen} closeOnOverlayClick>
149+
test
150+
</Popup>
151+
)
152+
await waitFor(() => expect(onOpen).toBeCalled())
153153
})
154154

155155
test('event click-overlay test', async () => {
@@ -171,3 +171,38 @@ test('pop destroyOnClose', () => {
171171
fireEvent.click(overlay)
172172
expect(onClose).toBeCalled()
173173
})
174+
175+
test('handles touch events correctly', () => {
176+
const handleTouchStart = vi.fn()
177+
const handleTouchMove = vi.fn()
178+
const handleTouchEnd = vi.fn()
179+
180+
render(
181+
<Popup
182+
visible
183+
resizable
184+
position="bottom"
185+
// minHeight="400px"
186+
onTouchStart={handleTouchStart}
187+
onTouchMove={handleTouchMove}
188+
onTouchEnd={handleTouchEnd}
189+
>
190+
Test Content
191+
</Popup>
192+
)
193+
194+
const popup = document.body.querySelector('.nut-popup') as HTMLElement
195+
196+
// Simulate touch events
197+
fireEvent.touchStart(popup, { touches: [{ pageY: 400 }] })
198+
expect(handleTouchStart).toHaveBeenCalled()
199+
200+
fireEvent.touchMove(popup, { touches: [{ pageY: 50 }] })
201+
expect(handleTouchMove).toHaveBeenCalled()
202+
203+
fireEvent.touchMove(popup, { touches: [{ pageY: 450 }] })
204+
expect(handleTouchMove).toHaveBeenCalled()
205+
206+
fireEvent.touchEnd(popup)
207+
expect(handleTouchEnd).toHaveBeenCalled()
208+
})

src/packages/popup/demos/h5/demo1.tsx

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,53 @@ import React, { useState } from 'react'
22
import { Popup, Cell } from '@nutui/nutui-react'
33

44
const Demo = () => {
5-
const [showIcon, setShowIcon] = useState(false)
5+
const [showPopup, setShowPopup] = useState(false)
6+
const [showPopupResiable, setShowPopupResiable] = useState(false)
67

78
return (
89
<>
910
<Cell
1011
title="基础弹框"
1112
onClick={() => {
12-
setShowIcon(true)
13+
setShowPopup(true)
14+
}}
15+
/>
16+
<Cell
17+
title="基础弹框:可上下滑动"
18+
onClick={() => {
19+
setShowPopupResiable(true)
1320
}}
1421
/>
1522
<Popup
1623
closeable
17-
visible={showIcon}
24+
visible={showPopup}
1825
title="标题"
1926
description="这里是副标题这是副标题"
2027
position="bottom"
2128
onClose={() => {
22-
setShowIcon(false)
29+
setShowPopup(false)
30+
}}
31+
/>
32+
<Popup
33+
closeable
34+
resizable
35+
minHeight="10%"
36+
style={{ height: '60%' }}
37+
visible={showPopupResiable}
38+
title="上下滑动"
39+
description="弹层区域滑动起来"
40+
position="bottom"
41+
onClose={() => {
42+
setShowPopupResiable(false)
43+
}}
44+
onTouchMove={(height, e, direction) => {
45+
console.log('onTouchMove', height, e, direction)
46+
}}
47+
onTouchStart={(height, e) => {
48+
console.log('onTouchStart', height, e)
49+
}}
50+
onTouchEnd={(height, e) => {
51+
console.log('onTouchEnd', height, e)
2352
}}
2453
/>
2554
</>

src/packages/popup/demos/h5/demo2.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ const Demo2 = () => {
4444
visible={showTop}
4545
destroyOnClose
4646
position="top"
47+
resizable
4748
onClose={() => {
4849
setShowTop(false)
4950
}}

src/packages/popup/demos/taro/demo1.tsx

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,53 @@ import React, { useState } from 'react'
22
import { Popup, Cell } from '@nutui/nutui-react-taro'
33

44
const Demo = () => {
5-
const [showIcon, setShowIcon] = useState(false)
5+
const [showPopup, setShowPopup] = useState(false)
6+
const [showPopupResiable, setShowPopupResiable] = useState(false)
67

78
return (
89
<>
910
<Cell
1011
title="基础弹框"
1112
onClick={() => {
12-
setShowIcon(true)
13+
setShowPopup(true)
14+
}}
15+
/>
16+
<Cell
17+
title="基础弹框:可上下滑动"
18+
onClick={() => {
19+
setShowPopupResiable(true)
1320
}}
1421
/>
1522
<Popup
1623
closeable
17-
visible={showIcon}
24+
visible={showPopup}
1825
title="标题"
1926
description="这里是副标题这是副标题"
2027
position="bottom"
2128
onClose={() => {
22-
setShowIcon(false)
29+
setShowPopup(false)
30+
}}
31+
/>
32+
<Popup
33+
closeable
34+
resizable
35+
minHeight="10%"
36+
style={{ height: '60%' }}
37+
visible={showPopupResiable}
38+
title="上下滑动"
39+
description="弹层区域滑动起来"
40+
position="bottom"
41+
onClose={() => {
42+
setShowPopupResiable(false)
43+
}}
44+
onTouchMove={(height, e, direction) => {
45+
console.log('onTouchMove', height, e, direction)
46+
}}
47+
onTouchStart={(height, e) => {
48+
console.log('onTouchStart', height, e)
49+
}}
50+
onTouchEnd={(height, e) => {
51+
console.log('onTouchEnd', height, e)
2352
}}
2453
/>
2554
</>

src/packages/popup/doc.en-US.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,19 +87,25 @@ import { Popup } from '@nutui/nutui-react'
8787
| closeable | whether to show the close button | `boolean` | `false` |
8888
| closeIconPosition | close button position | `top-left` \| `top-right` \| `bottom-left` \| `bottom-right` | `top-right` |
8989
| closeIcon | Custom Icon | `ReactNode` | `close` |
90+
| resizable | Enable vertical resizing of the popup | `boolean` | `false` |
91+
| minHeight | Minimum height of the popup | `string` | `26%` |
9092
| left | The left of title | `ReactNode` | `-` |
9193
| title | The center of title | `ReactNode` | `-` |
94+
| top | The top of popup | `ReactNode` | `-` |
9295
| description | The subtitle/description | `ReactNode` | `-` |
9396
| destroyOnClose | Whether to close after the component is destroyed | `boolean` | `false` |
9497
| round | Whether to show rounded corners | `boolean` | `false` |
9598
| portal | Mount the specified node | `HTMLElement` \| `(() => HTMLElement)` \| null` | `null` |
99+
| afterShow | afterShow from `Overlay`, Fired when the mask opening animation ends | `event: HTMLElement` | `-` |
100+
| afterClose | afterClose from `Overlay`, Fired when the mask closing animation ends | `event: HTMLElement` | `-` |
96101
| onClick | Triggered when the popup is clicked | `event: MouseEvent` | `-` |
97102
| onCloseIconClick | Fired when the close icon is clicked | `event: MouseEvent` | `-` |
98103
| onOpen | Triggered when the popup is opened | `-` | `-` |
99104
| onClose | Fired when the popup is closed | `-` | `-` |
100-
| afterShow | afterShow from `Overlay`, Fired when the mask opening animation ends | `event: HTMLElement` | `-` |
101-
| afterClose | afterClose from `Overlay`, Fired when the mask closing animation ends | `event: HTMLElement` | `-` |
102105
| onOverlayClick | Click on the mask to trigger | `event: MouseEvent` | `-` |
106+
| onTouchStart | triggered when starting to touch | `(height: number, event: TouchEvent<HTMLDivElement>) => void` | `-` |
107+
| onTouchMove | triggered while moving | `(height: number, event: TouchEvent<HTMLDivElement>, direction: 'up' \| 'down') => void` | `-` |
108+
| onTouchEnd | triggered when finishing to touch | `(height: number, event: TouchEvent<HTMLDivElement>) => void` | `-` |
103109

104110
## Theming
105111

src/packages/popup/doc.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,19 +87,25 @@ import { Popup } from '@nutui/nutui-react'
8787
| closeable | 是否显示关闭按钮 | `boolean` | `false` |
8888
| closeIconPosition | 关闭按钮位置 | `top-left` \| `top-right` \| `bottom-left` \| `bottom-right` | `top-right` |
8989
| closeIcon | 自定义 Icon | `ReactNode` | `close` |
90+
| resizable | 上下滑动调整高度,当前只支持从底部弹出 | `boolean` | `false` |
91+
| minHeight | 设置最小高度 | `string` | `26%` |
9092
| left | 标题左侧部分 | `ReactNode` | `-` |
9193
| title | 标题中间部分 | `ReactNode` | `-` |
94+
| top | 顶部占位 | `ReactNode` | `-` |
9295
| description | 子标题/描述部分 | `ReactNode` | `-` |
9396
| destroyOnClose | 组件不可见时,卸载内容 | `boolean` | `false` |
9497
| round | 是否显示圆角 | `boolean` | `false` |
9598
| portal | 指定节点挂载 | `HTMLElement` \| `(() => HTMLElement)` \| null` | `null` |
99+
| afterShow | 继承于`Overlay`, 遮罩打开动画结束时触发 | `event: HTMLElement` | `-` |
100+
| afterClose | 继承于`Overlay`, 遮罩关闭动画结束时触发 | `event: HTMLElement` | `-` |
96101
| onClick | 点击弹框时触发 | `event: MouseEvent` | `-` |
97102
| onCloseIconClick | 点击关闭图标时触发 | `event: MouseEvent` | `-` |
98103
| onOpen | 打开弹框时触发 | `-` | `-` |
99104
| onClose | 关闭弹框时触发 | `-` | `-` |
100-
| afterShow | 继承于`Overlay`, 遮罩打开动画结束时触发 | `event: HTMLElement` | `-` |
101-
| afterClose | 继承于`Overlay`, 遮罩关闭动画结束时触发 | `event: HTMLElement` | `-` |
102105
| onOverlayClick | 点击遮罩触发 | `event: MouseEvent` | `-` |
106+
| onTouchStart | 开始触碰时触发 | `(height: number, event: TouchEvent<HTMLDivElement>) => void` | `-` |
107+
| onTouchMove | 滑动时触发 | `(height: number, event: TouchEvent<HTMLDivElement>, direction: 'up' \| 'down') => void` | `-` |
108+
| onTouchEnd | 结束触碰时触发 | `(height: number, event: TouchEvent<HTMLDivElement>) => void` | `-` |
103109

104110
## 主题定制
105111

src/packages/popup/doc.taro.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,19 +97,25 @@ import { Popup } from '@nutui/nutui-react-taro'
9797
| closeable | 是否显示关闭按钮 | `boolean` | `false` |
9898
| closeIconPosition | 关闭按钮位置 | `top-left` \| `top-right` \| `bottom-left` \| `bottom-right` | `top-right` |
9999
| closeIcon | 自定义 Icon | `ReactNode` | `close` |
100+
| resizable | 上下滑动调整高度,当前只支持从底部弹出 | `boolean` | `false` |
101+
| minHeight | 设置最小高度 | `string` | `26%` |
100102
| left | 标题左侧部分 | `ReactNode` | `-` |
101103
| title | 标题中间部分 | `ReactNode` | `-` |
104+
| top | 頂部佔位 | `ReactNode` | `-` |
102105
| description | 子标题/描述部分 | `ReactNode` | `-` |
103106
| destroyOnClose | 组件不可见时,卸载内容 | `boolean` | `false` |
104107
| round | 是否显示圆角 | `boolean` | `false` |
105108
| portal | 指定节点挂载 | ``HTMLElement` \| `(() => HTMLElement)` \| null`` | `null` |
109+
| afterShow | 继承于`Overlay`, 遮罩打开动画结束时触发 | `event: HTMLElement` | `-` |
110+
| afterClose | 继承于`Overlay`, 遮罩关闭动画结束时触发 | `event: HTMLElement` | `-` |
106111
| onClick | 点击弹框时触发 | `event: MouseEvent` | `-` |
107112
| onCloseIconClick | 点击关闭图标时触发 | `event: MouseEvent` | `-` |
108113
| onOpen | 打开弹框时触发 | `-` | `-` |
109114
| onClose | 关闭弹框时触发 | `-` | `-` |
110-
| afterShow | 继承于`Overlay`, 遮罩打开动画结束时触发 | `event: HTMLElement` | `-` |
111-
| afterClose | 继承于`Overlay`, 遮罩关闭动画结束时触发 | `event: HTMLElement` | `-` |
112115
| onOverlayClick | 点击遮罩触发 | `event: MouseEvent` | `-` |
116+
| onTouchStart | 开始触碰时触发 | `(height: number, event: ITouchEvent) => void` | `-` |
117+
| onTouchMove | 滑动时触发 | `(height: number, event: ITouchEvent, direction: 'up' \| 'down') => void` | `-` |
118+
| onTouchEnd | 结束触碰时触发 | `(height: number, event: ITouchEvent) => void` | `-` |
113119

114120
## 主题定制
115121

0 commit comments

Comments
 (0)