diff --git a/scripts/harmony/update-taro-entry.js b/scripts/harmony/update-taro-entry.js index f46c0b1c74..88a92e77aa 100644 --- a/scripts/harmony/update-taro-entry.js +++ b/scripts/harmony/update-taro-entry.js @@ -21,7 +21,7 @@ const isShow = (item) => { // 更新 app.config.ts 文件 const createConfig = async () => { - const configRef = [] + let configRef = [] return new Promise((res, rej) => { config.nav.map((item) => { @@ -29,8 +29,8 @@ const createConfig = async () => { root: item.enName, pages: [], } - if(paramG) { - if(paramG === item.enName){ + if (paramG) { + if (paramG === item.enName) { item.packages.map((it) => { if (isShow(it)) { co.pages.push(`pages/${it.name.toLowerCase()}/index`) @@ -49,6 +49,10 @@ const createConfig = async () => { co = { ...co, pages: co.pages.sort() } configRef.push(co) }) + + // 如果 pages 数据为空,则删除该项 + configRef = configRef.filter((item) => item.pages.length !== 0) + res(configRef) }) } diff --git a/src/packages/configprovider/types.ts b/src/packages/configprovider/types.ts index 02ce83e765..51b299fb93 100644 --- a/src/packages/configprovider/types.ts +++ b/src/packages/configprovider/types.ts @@ -655,11 +655,12 @@ export type NutCSSVariables = | 'nutuiSearchbarBackground' | 'nutuiSearchbarColor' | 'nutuiSearchbarGap' + | 'nutuiSearchbarInnerGap' | 'nutuiSearchbarFontSize' - | 'nutuiSearchbarContentPadding' | 'nutuiSearchbarContentBackground' | 'nutuiSearchbarContentBorderRadius' | 'nutuiSearchbarContentRoundBorderRadius' + | 'nutuiSearchbarIconSize' | 'nutuiSearchbarInputHeight' | 'nutuiSearchbarInputPadding' | 'nutuiSearchbarInputTextColor' diff --git a/src/packages/searchbar/__tests__/searchbar.spec.tsx b/src/packages/searchbar/__tests__/searchbar.spec.tsx index 0ed6bf7f3a..e50c5eb4d9 100644 --- a/src/packages/searchbar/__tests__/searchbar.spec.tsx +++ b/src/packages/searchbar/__tests__/searchbar.spec.tsx @@ -1,28 +1,24 @@ import * as React from 'react' -import { fireEvent, render } from '@testing-library/react' +import { render, fireEvent, waitFor } from '@testing-library/react' import '@testing-library/jest-dom' +import { useState } from 'react' import SearchBar from '@/packages/searchbar' -test('basic usage', () => { - const { container } = render() - expect(container.querySelector('.nut-searchbar-input')).toHaveAttribute( - 'placeholder', - '请输入文字' +test('should render with placeholder', () => { + const { getByPlaceholderText } = render( + ) + expect(getByPlaceholderText('请输入文字')).toBeInTheDocument() }) test('should limit maxlength of input value when using maxlength prop', () => { const { container } = render() - expect(container.querySelector('.nut-searchbar-input')).toHaveAttribute( - 'maxlength', - '5' - ) - expect(container.querySelector('.nut-searchbar-content')).toHaveClass( - 'nut-searchbar-round' - ) + const input = container.querySelector('.nut-searchbar-input') + expect(input).toHaveAttribute('maxlength', '5') + expect(input?.parentNode).toHaveClass('nut-searchbar-round') }) -test('Search box text settings', () => { +test('should display left and right text', () => { const { container } = render() expect(container.querySelector('.nut-searchbar-left')?.innerHTML).toBe('文本') expect(container.querySelector('.nut-searchbar-right')?.innerHTML).toBe( @@ -30,15 +26,64 @@ test('Search box text settings', () => { ) }) -test('Search clear & change', () => { - const change = vi.fn() - const { container } = render( - - ) - const input = container.querySelector('.nut-searchbar-input') - expect(input?.getAttribute('value')).toBe('123') - const clear = container.querySelector('.nut-searchbar-clear') - fireEvent.click(clear as Element) - expect(change).toBeCalledWith('') - expect(input?.getAttribute('value')).toBe('') +test('should render with tags', () => { + const { container } = render() + const dvalues = container.querySelectorAll('.nut-searchbar-value') + expect(dvalues.length).toBe(2) +}) + +test('should render right-in element', () => { + const { container, rerender } = render() + const rightin = container.querySelectorAll('.nut-searchbar-rightin') + expect(rightin.length).toBe(1) + rerender(搜索} />) + const test = container.querySelectorAll('.test') + expect(test.length).toBe(1) +}) + +test('should handle all events correctly', async () => { + const handleChange = vi.fn() + const handleFocus = vi.fn() + const handleBlur = vi.fn() + const handleClick = vi.fn() + const handleClear = vi.fn() + const Demo = () => { + const [value, setValue] = useState('奶茶') + const onChange = (newValue: string) => { + setValue(newValue) // 更新状态 + handleChange(newValue) // 调用传入的 onChange 处理函数 + } + return ( + + ) + } + + const { container } = render() + const inputEl = container.querySelector('.nut-searchbar-input') as Element + expect(inputEl).toHaveValue('奶茶') + fireEvent.click(inputEl) + expect(handleClick).toHaveBeenCalledTimes(1) + fireEvent.change(inputEl, { target: { value: '冰激凌' } }) + + await waitFor(() => { + expect(handleFocus).toHaveBeenCalledTimes(1) + expect(handleChange).toHaveBeenCalledTimes(1) + expect(inputEl).toHaveValue('冰激凌') + fireEvent.blur(inputEl) + expect(handleBlur).toHaveBeenCalled() + }) + + const clear = container.querySelector('.nut-searchbar-clear') as Element + fireEvent.click(clear) + await waitFor(() => { + expect(inputEl).toHaveValue('') + }) }) diff --git a/src/packages/searchbar/demo.taro.tsx b/src/packages/searchbar/demo.taro.tsx index 679f03f7dc..7e06e80f08 100644 --- a/src/packages/searchbar/demo.taro.tsx +++ b/src/packages/searchbar/demo.taro.tsx @@ -12,11 +12,13 @@ import Demo4 from './demos/taro/demo4' import Demo5 from './demos/taro/demo5' import Demo6 from './demos/taro/demo6' import Demo7 from './demos/taro/demo7' +import Demo10 from './demos/taro/demo10' const SearchBarDemo = () => { const [translated] = useTranslate({ 'zh-CN': { title1: '基础用法', + title10: '默认值、受控', title2: '搜索框形状及最大长度', title3: '搜索框内外背景设置', title4: '搜索框文本设置', @@ -26,6 +28,7 @@ const SearchBarDemo = () => { }, 'zh-TW': { title1: '基礎用法', + title10: '默認值、受控', title2: '蒐索框形狀及最大長度', title3: '蒐索框內外背景設定', title4: '蒐索框文字設定', @@ -35,6 +38,7 @@ const SearchBarDemo = () => { }, 'en-US': { title1: 'Basic Usage', + title10: 'DefaultValue and controlled mode', title2: 'Search Box Shape And Maximum Length', title3: 'Background Settings Inside And Outside The Search Box', title4: 'Search Box Text Settings', @@ -42,15 +46,6 @@ const SearchBarDemo = () => { title6: 'Data Change Monitoring', title7: 'Custom Settings', }, - 'id-ID': { - title1: 'penggunaan dasar', - title2: 'bentuk kotak pencarian dan panjang maksimum', - title3: 'pengaturan latar belakang di dalam dan diluar kotak pencarian', - title4: 'tetapan teks kotak pencarian', - title5: 'pengaturan ikon suai', - title6: 'Monitor perubahan data', - title7: 'pengaturan suai', - }, }) return ( @@ -59,6 +54,8 @@ const SearchBarDemo = () => { {translated.title1} + {translated.title10} + {translated.title2} {translated.title3} diff --git a/src/packages/searchbar/demo.tsx b/src/packages/searchbar/demo.tsx index 5a5fe879d0..c51863b781 100644 --- a/src/packages/searchbar/demo.tsx +++ b/src/packages/searchbar/demo.tsx @@ -8,11 +8,13 @@ import Demo4 from './demos/h5/demo4' import Demo5 from './demos/h5/demo5' import Demo6 from './demos/h5/demo6' import Demo7 from './demos/h5/demo7' +import Demo10 from './demos/h5/demo10' const SearchBarDemo = () => { const [translated] = useTranslate({ 'zh-CN': { title1: '基础用法', + title10: '默认值、受控', title2: '搜索框形状及最大长度', title3: '搜索框内外背景设置', title4: '搜索框文本设置', @@ -22,6 +24,7 @@ const SearchBarDemo = () => { }, 'zh-TW': { title1: '基礎用法', + title10: '默認值、受控', title2: '蒐索框形狀及最大長度', title3: '蒐索框內外背景設定', title4: '蒐索框文字設定', @@ -31,6 +34,7 @@ const SearchBarDemo = () => { }, 'en-US': { title1: 'Basic Usage', + title10: 'DefaultValue and controlled mode', title2: 'Search Box Shape And Maximum Length', title3: 'Background Settings Inside And Outside The Search Box', title4: 'Search Box Text Settings', @@ -38,15 +42,6 @@ const SearchBarDemo = () => { title6: 'Data Change Monitoring', title7: 'Custom Settings', }, - 'id-ID': { - title1: 'penggunaan dasar', - title2: 'bentuk kotak pencarian dan panjang maksimum', - title3: 'pengaturan latar belakang di dalam dan diluar kotak pencarian', - title4: 'tetapan teks kotak pencarian', - title5: 'pengaturan ikon suai', - title6: 'Monitor perubahan data', - title7: 'pengaturan suai', - }, }) return ( @@ -54,6 +49,8 @@ const SearchBarDemo = () => {

{translated.title1}

+

{translated.title10}

+

{translated.title2}

{translated.title3}

diff --git a/src/packages/searchbar/demos/h5/demo1.tsx b/src/packages/searchbar/demos/h5/demo1.tsx index c9ffdbff10..563bc43653 100644 --- a/src/packages/searchbar/demos/h5/demo1.tsx +++ b/src/packages/searchbar/demos/h5/demo1.tsx @@ -1,10 +1,22 @@ import React from 'react' -import { SearchBar } from '../../searchbar' +import { Photograph, Scan } from '@nutui/icons-react' +import { SearchBar, Divider } from '@nutui/nutui-react' const Demo1 = () => { return ( <> - + + } + placeholder="华为Mate 70" + rightIn={ +
+ console.log('拍照购')} /> + + 搜索 +
+ } + /> ) } diff --git a/src/packages/searchbar/demos/h5/demo10.tsx b/src/packages/searchbar/demos/h5/demo10.tsx new file mode 100644 index 0000000000..33cd5cbbd6 --- /dev/null +++ b/src/packages/searchbar/demos/h5/demo10.tsx @@ -0,0 +1,57 @@ +import React, { useState } from 'react' +import { SearchBar, Button } from '@nutui/nutui-react' +import { Photograph, Category } from '@nutui/icons-react' + +const Demo = () => { + const [value, setValue] = useState('醋溜土豆丝') + const [value1, setValue1] = useState('西红柿,铁皮') + return ( + <> + { + console.log('click', val) + const arr = value1.split(',') + const newArr = arr.filter((item: string) => item !== val) + const newVal = newArr.length > 1 ? newArr.join(',') : newArr.join('') + setValue1(newVal) + }} + onFocus={(val: string) => { + console.log('focus value', val) + setValue1(val.split(',').join('')) + }} + onChange={(val) => { + console.log('onChange', val) + setValue1(val) + }} + rightIn={ +
+ +
+ } + right={} + /> + { + setValue(val) + }} + autoFocus + rightIn={ +
+ + +
+ } + /> + + ) +} +export default Demo diff --git a/src/packages/searchbar/demos/h5/demo2.tsx b/src/packages/searchbar/demos/h5/demo2.tsx index 7130330f02..4408c74c39 100644 --- a/src/packages/searchbar/demos/h5/demo2.tsx +++ b/src/packages/searchbar/demos/h5/demo2.tsx @@ -1,5 +1,5 @@ import React from 'react' -import { SearchBar } from '../../searchbar' +import { SearchBar } from '@nutui/nutui-react' const Demo2 = () => { return ( diff --git a/src/packages/searchbar/demos/h5/demo3.tsx b/src/packages/searchbar/demos/h5/demo3.tsx index debda1aff0..6787fedf9b 100644 --- a/src/packages/searchbar/demos/h5/demo3.tsx +++ b/src/packages/searchbar/demos/h5/demo3.tsx @@ -1,7 +1,5 @@ import React from 'react' -import { SearchBar } from '../../searchbar' -import ConfigProvider from '../../../configprovider' -import Toast from '../../../toast' +import { SearchBar, ConfigProvider, Toast } from '@nutui/nutui-react' const Demo3 = () => { return ( @@ -9,7 +7,7 @@ const Demo3 = () => { diff --git a/src/packages/searchbar/demos/h5/demo4.tsx b/src/packages/searchbar/demos/h5/demo4.tsx index c6b63af04f..4c96fca687 100644 --- a/src/packages/searchbar/demos/h5/demo4.tsx +++ b/src/packages/searchbar/demos/h5/demo4.tsx @@ -1,6 +1,5 @@ import React from 'react' -import { SearchBar } from '../../searchbar' -import Toast from '../../../toast' +import { SearchBar, Toast } from '@nutui/nutui-react' const Demo4 = () => { return ( diff --git a/src/packages/searchbar/demos/h5/demo5.tsx b/src/packages/searchbar/demos/h5/demo5.tsx index e35f8ec58c..6ec0d38c9b 100644 --- a/src/packages/searchbar/demos/h5/demo5.tsx +++ b/src/packages/searchbar/demos/h5/demo5.tsx @@ -1,6 +1,6 @@ import React from 'react' import { ArrowLeft, Photograph, More, Close, Star } from '@nutui/icons-react' -import { SearchBar } from '../../searchbar' +import { SearchBar } from '@nutui/nutui-react' const Demo5 = () => { return ( @@ -8,26 +8,22 @@ const Demo5 = () => { - - + + } right={ <> - + } rightIn={ { console.log('Photograph right in') }} diff --git a/src/packages/searchbar/demos/h5/demo6.tsx b/src/packages/searchbar/demos/h5/demo6.tsx index 47bb48f986..355b15a6fe 100644 --- a/src/packages/searchbar/demos/h5/demo6.tsx +++ b/src/packages/searchbar/demos/h5/demo6.tsx @@ -1,7 +1,6 @@ import React, { useState } from 'react' import { ArrowDown } from '@nutui/icons-react' -import { SearchBar } from '../../searchbar' -import PopOver from '../../../popover' +import { SearchBar, Popover } from '@nutui/nutui-react' const Demo6 = () => { const itemList = [ @@ -14,7 +13,7 @@ const Demo6 = () => { <> { lightTheme ? setLightTheme(false) : setLightTheme(true) @@ -25,7 +24,7 @@ const Demo6 = () => { 更多
- + } /> diff --git a/src/packages/searchbar/demos/h5/demo7.tsx b/src/packages/searchbar/demos/h5/demo7.tsx index 7fa543d515..cc14be40c5 100644 --- a/src/packages/searchbar/demos/h5/demo7.tsx +++ b/src/packages/searchbar/demos/h5/demo7.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react' -import { SearchBar } from '../../searchbar' +import { SearchBar } from '@nutui/nutui-react' const Demo7 = () => { const [value, setValue] = useState('') diff --git a/src/packages/searchbar/demos/taro/demo1.tsx b/src/packages/searchbar/demos/taro/demo1.tsx index 2723d9fd4b..c133adba89 100644 --- a/src/packages/searchbar/demos/taro/demo1.tsx +++ b/src/packages/searchbar/demos/taro/demo1.tsx @@ -1,11 +1,23 @@ import React from 'react' -import { SearchBar } from '@nutui/nutui-react-taro' +import { SearchBar, Divider } from '@nutui/nutui-react-taro' +import { Photograph, Scan } from '@nutui/icons-react-taro' -const Demo1 = () => { +const Demo = () => { return ( <> - + + } + placeholder="华为Mate 70" + rightIn={ +
+ console.log('拍照购')} /> + + 搜索 +
+ } + /> ) } -export default Demo1 +export default Demo diff --git a/src/packages/searchbar/demos/taro/demo10.tsx b/src/packages/searchbar/demos/taro/demo10.tsx new file mode 100644 index 0000000000..e68915ffcc --- /dev/null +++ b/src/packages/searchbar/demos/taro/demo10.tsx @@ -0,0 +1,57 @@ +import React, { useState } from 'react' +import { SearchBar } from '@nutui/nutui-react-taro' +import { Photograph, Category } from '@nutui/icons-react-taro' + +const Demo = () => { + const [value, setValue] = useState('醋溜土豆丝') + const [value1, setValue1] = useState('西红柿,铁皮') + return ( + <> + { + console.log('click', val) + const arr = value1.split(',') + const newArr = arr.filter((item: string) => item !== val) + const newVal = newArr.length > 1 ? newArr.join(',') : newArr.join('') + setValue1(newVal) + }} + onFocus={(val: string) => { + console.log('focus value', val) + setValue1(val.split(',').join('')) + }} + onChange={(val) => { + console.log('onChange', val) + setValue1(val) + }} + rightIn={ +
+ +
+ } + right={} + /> + {/* { + setValue(val) + }} + // autoFocus + rightIn={ +
+ + +
+ } + /> */} + + ) +} +export default Demo diff --git a/src/packages/searchbar/demos/taro/demo5.tsx b/src/packages/searchbar/demos/taro/demo5.tsx index a3e10a597f..b58c0507bd 100644 --- a/src/packages/searchbar/demos/taro/demo5.tsx +++ b/src/packages/searchbar/demos/taro/demo5.tsx @@ -14,24 +14,22 @@ const Demo5 = () => { - - + + } right={ <> - + } rightIn={ { console.log('Photograph right in') }} diff --git a/src/packages/searchbar/doc.en-US.md b/src/packages/searchbar/doc.en-US.md index acdd99af30..81f2089885 100644 --- a/src/packages/searchbar/doc.en-US.md +++ b/src/packages/searchbar/doc.en-US.md @@ -20,6 +20,14 @@ import { SearchBar } from '@nutui/nutui-react' ::: +### DefaultValue And Controlled + +:::demo + + + +::: + ### Search box shape and maximum length `SearchBar`'s `shape` Attribute supports defining fillet right angles,`maxLength` Can control the maximum length of input characters。 diff --git a/src/packages/searchbar/doc.md b/src/packages/searchbar/doc.md index 2e27cc0dbd..eca6026a15 100644 --- a/src/packages/searchbar/doc.md +++ b/src/packages/searchbar/doc.md @@ -12,14 +12,20 @@ import { SearchBar } from '@nutui/nutui-react' ### 基础用法 -`SearchBar` 的 `placeholder` 属性支持自定义。 - :::demo ::: +### 默认值、受控模式 + +:::demo + + + +::: + ### 搜索框形状及最大长度 `SearchBar` 的 `shape` 属性支持定义圆角直角,`maxLength` 可控制输入字符的最大长度。 @@ -86,7 +92,8 @@ import { SearchBar } from '@nutui/nutui-react' | 属性 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | -| value | 当前输入的值 | `string` | `-` | +| value | 当前输入的值,受控 | `string` | `-` | +| defaultValue | 当前默认值,支持通过','分割成多个 | `string` | `-` | | placeholder | 输入框默认暗纹 | `string` | `请输入` | | shape | 搜索框形状,可选值为 `round` | `string` | `square` | | disabled | 是否禁用输入框 | `boolean` | `false` | @@ -97,7 +104,7 @@ import { SearchBar } from '@nutui/nutui-react' | backable | 是否展示返回按钮 | `boolean` | `false` | | left | 搜索框左侧区域 | `ReactNode` | `-` | | right | 搜搜框右侧区域 | `ReactNode` | `-` | -| leftIn | 输入框内左侧区域 | `ReactNode` | `` | +| leftIn | 输入框内左侧区域 | `ReactNode` | `` | | rightIn | 输入框内右侧区域 | `ReactNode` | `-` | | onChange | 输入内容时触发 | `(value: string, event: ChangeEvent) => void` | `-` | | onFocus | 聚焦时触发 | `(value: string, event: FocusEvent) => void` | `-` | @@ -105,6 +112,7 @@ import { SearchBar } from '@nutui/nutui-react' | onClear | 点击清空时触发 | `(event: MouseEvent) => void` | `-` | | onSearch | 确定搜索时触发 | `(val: string) => void` | `-` | | onInputClick | 点击输入区域时触发 | `(event: MouseEvent) => void` | `-` | +| onItemClick | 点击默认值的x号触发 | `(value: string) => void` | `-` | ## 主题定制 @@ -115,17 +123,17 @@ import { SearchBar } from '@nutui/nutui-react' | 名称 | 说明 | 默认值 | | --- | --- | --- | | \--nutui-searchbar-width | 搜索框的宽度 | `100%` | -| \--nutui-searchbar-padding | 搜索框的padding值 | `6px 16px` | -| \--nutui-searchbar-background | 搜索框背景色 | `$color-background` | +| \--nutui-searchbar-padding | 搜索框的padding值 | `1px 8px` | +| \--nutui-searchbar-background | 搜索框背景色 | `$color-background-sunken` | | \--nutui-searchbar-color | 搜索框字色 | `$color-title` | -| \--nutui-searchbar-gap | 搜索框各个间距 | `16px` | +| \--nutui-searchbar-gap | 搜索框外部/大间距 | `12px` | +| \--nutui-searchbar-inner-gap | 搜索框内部元素间的间距 | `12px` | | \--nutui-searchbar-font-size | 搜索框字号 | `$font-size-base` | -| \--nutui-searchbar-content-padding | 搜索框中间内容区的padding值 | `0px 12px` | | \--nutui-searchbar-content-background | 搜索框中间内容区的背景色 | `$color-background-overlay` | -| \--nutui-searchbar-content-border-radius | 搜索框内容区圆角 | `4px` | -| \--nutui-searchbar-content-round-border-radius | 搜索框内容区在round模式下的圆角 | `18px` | -| \--nutui-searchbar-input-height | 搜索框输入区高度 | `32px` | -| \--nutui-searchbar-input-padding | 搜索框输入区padding | `0 4px` | +| \--nutui-searchbar-content-border-radius | 搜索框内容区圆角 | `8px` | +| \--nutui-searchbar-content-round-border-radius | 搜索框内容区在round模式下的圆角 | `19px` | +| \--nutui-searchbar-input-height | 搜索框输入区高度 | `38px` | +| \--nutui-searchbar-input-padding | 搜索框输入区padding | `0 0 0 8px` | | \--nutui-searchbar-input-text-color | 搜索框输入区字色 | `$color-title` | | \--nutui-searchbar-input-curror-color | 搜索框输入区输入色 | `$color-title` | | \--nutui-searchbar-input-text-align | 搜索框输入区对齐方式 | `left` | diff --git a/src/packages/searchbar/doc.taro.md b/src/packages/searchbar/doc.taro.md index 8de25fb373..88e64d1e28 100644 --- a/src/packages/searchbar/doc.taro.md +++ b/src/packages/searchbar/doc.taro.md @@ -20,6 +20,14 @@ import { SearchBar } from '@nutui/nutui-react-taro' ::: +### 默认值、受控模式 + +:::demo + + + +::: + ### 搜索框形状及最大长度 `SearchBar` 的 `shape` 属性支持定义圆角直角,`maxLength` 可控制输入字符的最大长度。 @@ -86,7 +94,8 @@ import { SearchBar } from '@nutui/nutui-react-taro' | 属性 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | -| value | 当前输入的值 | `string` | `-` | +| value | 当前输入的值,受控 | `string` | `-` | +| defaultValue | 当前默认值,支持通过','分割成多个 | `string` | `-` | | placeholder | 输入框默认暗纹 | `string` | `请输入` | | shape | 搜索框形状,可选值为 `round` | `string` | `square` | | disabled | 是否禁用输入框 | `boolean` | `false` | @@ -97,7 +106,7 @@ import { SearchBar } from '@nutui/nutui-react-taro' | backable | 是否展示返回按钮 | `boolean` | `false` | | left | 搜索框左侧区域 | `ReactNode` | `-` | | right | 搜搜框右侧区域 | `ReactNode` | `-` | -| leftIn | 输入框内左侧区域 | `ReactNode` | `` | +| leftIn | 输入框内左侧区域 | `ReactNode` | `` | | rightIn | 输入框内右侧区域 | `ReactNode` | `-` | | onChange | 输入内容时触发 | `(value: string, event: ChangeEvent) => void` | `-` | | onFocus | 聚焦时触发 | `(value: string, event: FocusEvent) => void` | `-` | @@ -105,6 +114,7 @@ import { SearchBar } from '@nutui/nutui-react-taro' | onClear | 点击清空时触发 | `(event: MouseEvent) => void` | `-` | | onSearch | 确定搜索时触发 | `(val: string) => void` | `-` | | onInputClick | 点击输入区域时触发 | `(event: MouseEvent) => void` | `-` | +| onItemClick | 点击默认值的x号触发 | `(value: string) => void` | `-` | ## 主题定制 @@ -115,17 +125,17 @@ import { SearchBar } from '@nutui/nutui-react-taro' | 名称 | 说明 | 默认值 | | --- | --- | --- | | \--nutui-searchbar-width | 搜索框的宽度 | `100%` | -| \--nutui-searchbar-padding | 搜索框的padding值 | `6px 16px` | -| \--nutui-searchbar-background | 搜索框背景色 | `$color-background` | +| \--nutui-searchbar-padding | 搜索框的padding值 | `1px 8px` | +| \--nutui-searchbar-background | 搜索框背景色 | `$color-background-sunken` | | \--nutui-searchbar-color | 搜索框字色 | `$color-title` | -| \--nutui-searchbar-gap | 搜索框各个间距 | `16px` | +| \--nutui-searchbar-gap | 搜索框外部/大间距 | `12px` | +| \--nutui-searchbar-inner-gap | 搜索框内部元素间的间距 | `12px` | | \--nutui-searchbar-font-size | 搜索框字号 | `$font-size-base` | -| \--nutui-searchbar-content-padding | 搜索框中间内容区的padding值 | `0px 12px` | | \--nutui-searchbar-content-background | 搜索框中间内容区的背景色 | `$color-background-overlay` | -| \--nutui-searchbar-content-border-radius | 搜索框内容区圆角 | `4px` | -| \--nutui-searchbar-content-round-border-radius | 搜索框内容区在round模式下的圆角 | `18px` | -| \--nutui-searchbar-input-height | 搜索框输入区高度 | `32px` | -| \--nutui-searchbar-input-padding | 搜索框输入区padding | `0 4px` | +| \--nutui-searchbar-content-border-radius | 搜索框内容区圆角 | `8px` | +| \--nutui-searchbar-content-round-border-radius | 搜索框内容区在round模式下的圆角 | `19px` | +| \--nutui-searchbar-input-height | 搜索框输入区高度 | `38px` | +| \--nutui-searchbar-input-padding | 搜索框输入区padding | `0 0 0 8px` | | \--nutui-searchbar-input-text-color | 搜索框输入区字色 | `$color-title` | | \--nutui-searchbar-input-curror-color | 搜索框输入区输入色 | `$color-title` | | \--nutui-searchbar-input-text-align | 搜索框输入区对齐方式 | `left` | diff --git a/src/packages/searchbar/doc.zh-TW.md b/src/packages/searchbar/doc.zh-TW.md index 9e2ec4a93a..270bdca29c 100644 --- a/src/packages/searchbar/doc.zh-TW.md +++ b/src/packages/searchbar/doc.zh-TW.md @@ -20,6 +20,14 @@ import { SearchBar } from '@nutui/nutui-react' ::: +### 默認值、受控 + +:::demo + + + +::: + ### 搜索框形狀及最大長度 `SearchBar` 的 `shape` 屬性支持定義圓角直角,`maxLength` 可控制輸入字符的最大長度。 @@ -86,7 +94,8 @@ import { SearchBar } from '@nutui/nutui-react' | 屬性 | 說明 | 類型 | 默認值 | | --- | --- | --- | --- | -| value | 當前輸入的值 | `string` | `-` | +| value | 當前輸入的值,受控 | `string` | `-` | +| defaultValue | 當前默認值,支持通過','分割成多個 | `string` | `-` | | placeholder | 輸入框默認暗紋 | `string` | `請輸入` | | shape | 搜索框形狀,可選值為 `round` | `string` | `square` | | disabled | 是否禁用輸入框 | `boolean` | `false` | @@ -94,10 +103,10 @@ import { SearchBar } from '@nutui/nutui-react' | maxLength | 最大輸入長度 | `number` | `9999` | | clearable | 是否展示清除按鈕 | `boolean` | `true` | | autoFocus | 是否自動聚焦 | `boolean` | `false` | -| backable | 是否展示返回按钮 | `boolean` | `false` | +| backable | 是否展示返回按鈕 | `boolean` | `false` | | left | 搜索框左側區域 | `ReactNode` | `-` | | right | 搜搜框右側區域 | `ReactNode` | `-` | -| leftIn | 輸入框內左側區域 | `ReactNode` | `` | +| leftIn | 輸入框內左側區域 | `ReactNode` | `` | | rightIn | 輸入框內右側區域 | `ReactNode` | `-` | | onChange | 輸入內容時觸發 | `(value: string, event: ChangeEvent) => void` | `-` | | onFocus | 聚焦時觸發 | `(value: string, event: FocusEvent) => void` | `-` | @@ -105,6 +114,7 @@ import { SearchBar } from '@nutui/nutui-react' | onClear | 點擊清空時觸發 | `(event: MouseEvent) => void` | `-` | | onSearch | 確定搜索時觸發 | `(val: string) => void` | `-` | | onInputClick | 點擊輸入區域時觸發 | `(event: MouseEvent) => void` | `-` | +| onItemClick | 點擊默認值的x號觸發 | `(value: string) => void` | `-` | ## 主題定制 @@ -115,17 +125,17 @@ import { SearchBar } from '@nutui/nutui-react' | 名稱 | 說明 | 默認值 | | --- | --- | --- | | \--nutui-searchbar-width | 搜索框的寬度 | `100%` | -| \--nutui-searchbar-padding | 搜索框的padding值 | `6px 16px` | -| \--nutui-searchbar-background | 搜索框背景色 | `$color-background` | +| \--nutui-searchbar-padding | 搜索框的padding值 | `1px 8px` | +| \--nutui-searchbar-background | 搜索框背景色 | `$color-background-sunken` | | \--nutui-searchbar-color | 搜索框字色 | `$color-title` | -| \--nutui-searchbar-gap | 搜索框各個間距 | `16px` | +| \--nutui-searchbar-gap | 搜索框外部/大間距 | `12px` | +| \--nutui-searchbar-inner-gap | 搜索框內部元素間的間距 | `12px` | | \--nutui-searchbar-font-size | 搜索框字號 | `$font-size-base` | -| \--nutui-searchbar-content-padding | 搜索框中間內容區的padding值 | `0px 12px` | | \--nutui-searchbar-content-background | 搜索框中間內容區的背景色 | `$color-background-overlay` | -| \--nutui-searchbar-content-border-radius | 搜索框內容區圓角 | `4px` | -| \--nutui-searchbar-content-round-border-radius | 搜索框內容區在round模式下的圓角 | `18px` | -| \--nutui-searchbar-input-height | 搜索框輸入區高度 | `32px` | -| \--nutui-searchbar-input-padding | 搜索框輸入區padding | `0 4px` | +| \--nutui-searchbar-content-border-radius | 搜索框內容區圓角 | `8px` | +| \--nutui-searchbar-content-round-border-radius | 搜索框內容區在round模式下的圓角 | `19px` | +| \--nutui-searchbar-input-height | 搜索框輸入區高度 | `38px` | +| \--nutui-searchbar-input-padding | 搜索框輸入區padding | `0 0 0 8px` | | \--nutui-searchbar-input-text-color | 搜索框輸入區字色 | `$color-title` | | \--nutui-searchbar-input-curror-color | 搜索框輸入區輸入色 | `$color-title` | | \--nutui-searchbar-input-text-align | 搜索框輸入區對齊方式 | `left` | diff --git a/src/packages/searchbar/searchbar.scss b/src/packages/searchbar/searchbar.scss index 31b7cda15a..eb5c68211f 100644 --- a/src/packages/searchbar/searchbar.scss +++ b/src/packages/searchbar/searchbar.scss @@ -9,28 +9,108 @@ box-sizing: border-box; justify-content: center; + .nut-icon { + width: $searchbar-icon-size; + height: $searchbar-icon-size; + font-size: $searchbar-icon-size; + } + &-content { + position: relative; flex: 1; display: flex; align-items: center; justify-content: center; - padding: $searchbar-content-padding; + padding: 0 $searchbar-gap; height: $searchbar-input-height; background: $searchbar-content-background; border-radius: $searchbar-content-border-radius; + border: 1px solid $color-primary; } &-icon { display: flex; justify-content: center; align-items: center; + color: $color-primary; + } + + &-leftin { + margin-right: $searchbar-inner-gap; } - &-clear, &-rightin { - width: 16px; - height: 16px; - color: var(--nutui-black-5); + font-size: 15px; + font-weight: 500; + color: $color-primary; + + &.nut-searchbar-icon { + color: var(--nutui-black-5); + } + } + + &-input-box, + &-input { + display: flex; + align-items: center; + flex: 1; + } + + &-input { + border: 0; + outline: 0; + box-sizing: border-box; + width: 100%; + padding: 0; + margin: 0; + font-size: $searchbar-font-size; + color: $searchbar-input-text-color; + caret-color: $searchbar-input-curror-color; + background: transparent; + text-align: $searchbar-input-text-align; + } + + &-clear { + width: 20px; + height: 20px; + &.nut-searchbar-icon { + .nut-icon { + width: 12px; + height: 12px; + color: var(--nutui-black-5); + margin-right: $searchbar-inner-gap; + } + } + } + + &-values { + position: absolute; + display: flex; + flex-direction: row; + z-index: 2; + background-color: #fff; + top: 9px; + left: 6px; + font-size: 12px; + line-height: 12px; + + .nut-searchbar-value { + display: flex; + flex-direction: row; + align-items: center; + padding: 4px 8px; + background-color: #f7f8fc; + border-radius: 4px; + margin-right: 2px; + } + + .nut-icon { + width: 6px; + height: 6px; + font-size: 6px; + color: #c2c4cc; + margin-left: 4px; + } } &-left, @@ -93,26 +173,6 @@ } } - &-input-box, - &-input { - display: flex; - align-items: center; - flex: 1; - } - - &-input { - border: 0; - outline: 0; - box-sizing: border-box; - width: 100%; - padding: $searchbar-input-padding; - font-size: $searchbar-font-size; - color: $searchbar-input-text-color; - caret-color: $searchbar-input-curror-color; - background: transparent; - text-align: $searchbar-input-text-align; - } - &-round { border-radius: $searchbar-content-round-border-radius; } @@ -120,6 +180,14 @@ &-disabled { cursor: not-allowed; } + + &-focus { + padding: 5px $searchbar-gap; + + .nut-searchbar-content { + border: 0.5px solid #ff5c67; + } + } } [dir='rtl'] .nut-searchbar, diff --git a/src/packages/searchbar/searchbar.taro.tsx b/src/packages/searchbar/searchbar.taro.tsx index 21e87d39d6..4beb2afe63 100644 --- a/src/packages/searchbar/searchbar.taro.tsx +++ b/src/packages/searchbar/searchbar.taro.tsx @@ -1,5 +1,12 @@ import Taro from '@tarojs/taro' -import React, { FunctionComponent, useEffect, useRef, useState } from 'react' +import React, { + FunctionComponent, + useCallback, + useEffect, + useRef, + useState, + useMemo, +} from 'react' import { Input as TaroInput, ITouchEvent, @@ -7,10 +14,12 @@ import { View, BaseEventOrig, } from '@tarojs/components' -import { ArrowLeft, MaskClose, Search } from '@nutui/icons-react-taro' +import { ArrowLeft, Close, MaskClose, Search } from '@nutui/icons-react-taro' +import classNames from 'classnames' import { useConfig } from '@/packages/configprovider/index.taro' import { ComponentDefaults } from '@/utils/typings' import { TaroSearchBarProps } from '@/types' +import { usePropsValue } from '@/hooks/use-props-value' const defaultProps = { ...ComponentDefaults, @@ -25,7 +34,8 @@ const defaultProps = { left: '', right: '', rightIn: '', - leftIn: , + leftIn: , + tag: false, } as TaroSearchBarProps export const SearchBar: FunctionComponent< Partial & @@ -35,12 +45,11 @@ export const SearchBar: FunctionComponent< > > = (props) => { const classPrefix = 'nut-searchbar' - const { locale } = useConfig() - const searchRef = useRef(null) - + const searchInputRef = useRef(null) const { value: outerValue, + defaultValue, style, placeholder, shape, @@ -55,137 +64,241 @@ export const SearchBar: FunctionComponent< left, leftIn, rightIn, + tag, onChange, onFocus, onBlur, onClear, onSearch, onInputClick, + onItemClick, } = { ...defaultProps, ...props, } - const [value, setValue] = useState(() => outerValue) + const [value, setValue] = usePropsValue({ + value: outerValue, + defaultValue, + finalValue: '', + }) + + const [innerTag, setInnerTag] = useState(tag) + + const forceFocus = useCallback(() => { + searchInputRef.current?.focus() + }, []) + + const handleInput = useCallback( + (event: BaseEventOrig) => { + const eventValue = event.detail?.value + if (value === eventValue) return + onChange && onChange(eventValue, event) + setValue(eventValue) + eventValue === '' && forceFocus() + }, + [onChange, setValue, forceFocus, value] + ) + + const handleFocus = useCallback( + (event: BaseEventOrig) => { + onFocus && onFocus(event.detail?.value, event) + setInnerTag(false) + }, + [onFocus] + ) + + const handleBlur = useCallback( + (event: BaseEventOrig | any) => { + searchInputRef.current?.blur() + onBlur && onBlur(event.detail?.value, event) + setTimeout(() => { + if (Taro.getEnv() === 'WEB') { + setInnerTag(event.target?.value ? tag : false) + } else { + setInnerTag(tag) + } + }, 200) + }, + [onBlur, tag, value] + ) + + const clearaVal = useCallback( + (event: ITouchEvent) => { + if (disabled || readOnly) return + setValue('') + forceFocus() + onChange && onChange('') + onClear && onClear(event) + }, + [disabled, readOnly, onChange, onClear, setValue] + ) + + const cls = useMemo( + () => + classNames( + classPrefix, + { + [`${classPrefix}-disabled`]: disabled, + [`${classPrefix}-focus`]: left || backable, + }, + className + ), + [disabled, backable, left, className] + ) - const forceFocus = () => { - const searchSelf: HTMLInputElement | null = searchRef.current - searchSelf && searchSelf.focus() - } - const onInput = (event: BaseEventOrig) => { - const eventValue = event?.detail?.value - if (value === eventValue) return - onChange && onChange?.(eventValue, event) - setValue(eventValue) - eventValue === '' && forceFocus() - } - const focus = (event: BaseEventOrig) => { - onFocus && onFocus(event?.detail?.value, event) - } - const blur = (event: BaseEventOrig) => { - const searchSelf: HTMLInputElement | null = searchRef.current - searchSelf && searchSelf.blur() - onBlur && onBlur(event?.detail?.value, event) - } - useEffect(() => { - setValue(outerValue || '') - }, [outerValue]) useEffect(() => { - if (Taro.getEnv() === 'WEB') { - autoFocus && forceFocus() + if (autoFocus) { + forceFocus() } - }, [autoFocus]) + if (tag && !innerTag) { + forceFocus() + } + }, [autoFocus, forceFocus, innerTag]) + const renderField = () => { + const inputCls = classNames(`${classPrefix}-input`) return ( - + <> + {Taro.getEnv() === 'WEB' ? ( + + ) : ( + + )} + ) } - const clickInput = (e: ITouchEvent) => { - onInputClick && onInputClick(e) - } - const renderLeftIn = () => { + + const renderValueByTags = useCallback(() => { + if (!innerTag) return null + if (!value) { + setTimeout(() => { + forceFocus() + }, 0) + return null + } + const list = value.split(',') + if (!list) return null + return ( + + {list.map((item, index) => ( + onItemClick?.(item, e)} + > + {item} + + + ))} + + ) + }, [value, onItemClick, innerTag]) + + const renderLeftIn = useCallback(() => { if (!leftIn) return null return ( {leftIn} ) - } - const renderLeft = () => { + }, [leftIn]) + + const renderLeft = useCallback(() => { if (!backable && !left) return null return ( - {backable ? : left} + {backable ? : left} ) - } - const renderRightIn = () => { + }, [backable, left]) + + const renderRightIn = useCallback(() => { if (!rightIn) return null return ( - - {rightIn} - + <> + {React.isValidElement(rightIn) ? ( + + {rightIn} + + ) : ( + {rightIn} + )} + ) - } - const renderRight = () => { + }, [rightIn]) + + const renderRight = useCallback(() => { if (!right) return null return {right} - } - const handleClear = () => { + }, [right]) + + const renderClear = useCallback(() => { return ( clearaVal(e)} + className={`${classPrefix}-clear ${classPrefix}-icon`} + style={{ + visibility: `${!innerTag && value && clearable ? 'visible' : 'hidden'}`, + }} + onClick={clearaVal} + aria-label="清除" > - + ) - } - const clearaVal = (event: ITouchEvent) => { - if (disabled || readOnly) { - return - } - setValue('') - forceFocus() - onChange && onChange?.('') - onClear && onClear(event) - } + }, [value, clearable, clearaVal, innerTag]) + const onConfirm = () => { onSearch && onSearch(value as string) } + return ( - + {renderLeft()} {renderLeftIn()} {renderField()} - {clearable && !value && renderRightIn()} - {clearable && value && handleClear()} + {renderValueByTags()} + {renderClear()} + {renderRightIn()} {renderRight()} diff --git a/src/packages/searchbar/searchbar.tsx b/src/packages/searchbar/searchbar.tsx index 52860afab4..8e417e8acf 100644 --- a/src/packages/searchbar/searchbar.tsx +++ b/src/packages/searchbar/searchbar.tsx @@ -1,9 +1,18 @@ import type { ChangeEvent, FocusEvent, MouseEvent } from 'react' -import React, { FunctionComponent, useEffect, useRef, useState } from 'react' -import { ArrowLeft, MaskClose, Search } from '@nutui/icons-react' +import React, { + FunctionComponent, + useCallback, + useEffect, + useRef, + useState, + useMemo, +} from 'react' +import { ArrowLeft, Close, MaskClose, Search } from '@nutui/icons-react' +import classNames from 'classnames' import { useConfig } from '@/packages/configprovider' import { ComponentDefaults } from '@/utils/typings' import { WebSearchBarProps } from '@/types' +import { usePropsValue } from '@/hooks/use-props-value' const defaultProps = { ...ComponentDefaults, @@ -18,7 +27,8 @@ const defaultProps = { left: '', right: '', rightIn: '', - leftIn: , + leftIn: , + tag: false, } as WebSearchBarProps export const SearchBar: FunctionComponent< Partial & @@ -28,12 +38,11 @@ export const SearchBar: FunctionComponent< > > = (props) => { const classPrefix = 'nut-searchbar' - const { locale } = useConfig() - const searchRef = useRef(null) - + const searchInputRef = useRef(null) const { value: outerValue, + defaultValue, style, placeholder, shape, @@ -48,147 +57,215 @@ export const SearchBar: FunctionComponent< left, leftIn, rightIn, + tag, onChange, onFocus, onBlur, onClear, onSearch, onInputClick, + onItemClick, } = { ...defaultProps, ...props, } - const [value, setValue] = useState(() => outerValue) + const [value, setValue] = usePropsValue({ + value: outerValue, + defaultValue, + finalValue: '', + }) - const forceFocus = () => { - const searchSelf: HTMLInputElement | null = searchRef.current - searchSelf && searchSelf.focus() - } - const change = (event: ChangeEvent) => { - const { value } = event.target - onChange && onChange?.(value, event) - setValue(value) - } - const focus = (event: FocusEvent) => { - const { value } = event.target - onFocus && onFocus?.(value, event) - } - const blur = (event: FocusEvent) => { - const searchSelf: HTMLInputElement | null = searchRef.current - searchSelf && searchSelf.blur() - const { value } = event.target - onBlur && onBlur?.(value, event) - } - useEffect(() => { - setValue(outerValue) - }, [outerValue]) + const [innerTag, setInnerTag] = useState(tag) + + const forceFocus = useCallback(() => { + searchInputRef.current?.focus() + }, []) + + const handleChange = useCallback( + (event: ChangeEvent) => { + const { value } = event.target + onChange && onChange(value, event) + setValue(value) + }, + [onChange, setValue] + ) + + const handleInputClick = useCallback( + (event: MouseEvent) => { + onInputClick?.(event) + }, + [onInputClick] + ) + + const handleFocus = useCallback( + (event: FocusEvent) => { + onFocus && onFocus(event.target?.value, event) + setInnerTag(false) + }, + [onFocus] + ) + + const handleBlur = useCallback( + (event: FocusEvent) => { + searchInputRef.current?.blur() + onBlur && onBlur(event.target?.value, event) + setTimeout(() => { + setInnerTag(event.target?.value ? tag : false) + }, 150) + }, + [onBlur, tag, value] + ) + const clearaVal = useCallback( + (event: MouseEvent) => { + if (disabled || readOnly) return + setValue('') + forceFocus() + onChange && onChange('') + onClear && onClear(event) + }, + [disabled, readOnly, onChange, onClear, setValue] + ) + + const onKeydown = useCallback( + (e: React.KeyboardEvent) => { + if (e.key === 'Enter') { + const event = e.nativeEvent + if (typeof event.cancelable !== 'boolean' || event.cancelable) { + event.preventDefault() + } + onSearch && onSearch(value as string) + } + }, + [onSearch, value] + ) + + const cls = useMemo( + () => + classNames( + classPrefix, + { + [`${classPrefix}-disabled`]: disabled, + [`${classPrefix}-focus`]: left || backable, + }, + className + ), + [disabled, backable, left, className] + ) useEffect(() => { - autoFocus && forceFocus() - }, [autoFocus]) + if (autoFocus) { + forceFocus() + } + }, [autoFocus, forceFocus]) + const renderField = () => { + const inputCls = classNames(`${classPrefix}-input`) return ( change(e)} - onFocus={(e) => focus(e)} - onBlur={(e) => blur(e)} - onClick={(e) => clickInput(e)} + onChange={handleChange} + onFocus={handleFocus} + onBlur={handleBlur} + onClick={handleInputClick} /> ) } - const clickInput = (e: MouseEvent) => { - onInputClick && onInputClick(e) - } - const renderLeftIn = () => { + const renderValueByTags = useCallback(() => { + if (!value) { + setTimeout(() => { + forceFocus() + }, 0) + return null + } + const list = value.split(',') + if (!list) return null + return ( +
+ {list.map((item, index) => ( +
onItemClick?.(item, e)} + > + {item} + +
+ ))} +
+ ) + }, [value, onItemClick]) + + const renderLeftIn = useCallback(() => { if (!leftIn) return null return (
{leftIn}
) - } - const renderLeft = () => { + }, [leftIn]) + + const renderLeft = useCallback(() => { if (!backable && !left) return null return (
- {backable ? : left} + {backable ? : left}
) - } + }, [backable, left]) - const renderRightIn = () => { + const renderRightIn = useCallback(() => { if (!rightIn) return null return ( -
- {rightIn} -
+ <> + {React.isValidElement(rightIn) ? ( +
+ {rightIn} +
+ ) : ( +
{rightIn}
+ )} + ) - } + }, [rightIn]) - const renderRight = () => { + const renderRight = useCallback(() => { if (!right) return null return
{right}
- } + }, [right]) - const handleClear = () => { + const renderClear = useCallback(() => { + if (!value || !clearable) return null return (
clearaVal(e)} + onClick={clearaVal} + aria-label="清除" >
) - } - - const clearaVal = (event: MouseEvent) => { - if (disabled || readOnly) { - return - } - setValue('') - onChange && onChange?.('') - onClear && onClear(event) - forceFocus() - } - - const onKeydown = (e: React.KeyboardEvent) => { - if (e.key === 'Enter') { - const event = e.nativeEvent - if (typeof event.cancelable !== 'boolean' || event.cancelable) { - event.preventDefault() - } - onSearch && onSearch(value as string) - } - } + }, [value, clearable, clearaVal]) return ( -
+
{renderLeft()}
{renderLeftIn()} {renderField()} - {clearable && !value && renderRightIn()} - {clearable && value && handleClear()} + {innerTag ? renderValueByTags() : renderClear()} + {renderRightIn()}
{renderRight()}
diff --git a/src/sites/sites-react/doc/docs/react/migrate-from-v2.md b/src/sites/sites-react/doc/docs/react/migrate-from-v2.md index cf2fd267e5..efffad7b12 100644 --- a/src/sites/sites-react/doc/docs/react/migrate-from-v2.md +++ b/src/sites/sites-react/doc/docs/react/migrate-from-v2.md @@ -180,7 +180,12 @@ plugins: [ - 新增 size 属性,控制图标的大小 - 新增 showScore 属性,展示评分文案 -[//]: # '#### SearchBar' +#### SearchBar + +- `value` 属性,支持受控 +- 新增 `defaultValue` 属性,用于搜索默认值,支持以','分割的字符串,用以展示为多个 +- 新增 `onItemClick` 属性,用于点击展示默认值时的x号,支持回调处理 + [//]: # '#### ShortPassword' #### TextArea diff --git a/src/sites/sites-react/doc/docs/taro/migrate-from-v2.md b/src/sites/sites-react/doc/docs/taro/migrate-from-v2.md index 8e5f97ab0c..a9b98e450d 100644 --- a/src/sites/sites-react/doc/docs/taro/migrate-from-v2.md +++ b/src/sites/sites-react/doc/docs/taro/migrate-from-v2.md @@ -179,7 +179,12 @@ plugins: [ - 新增 size 属性,控制图标的大小 - 新增 showScore 属性,展示评分文案 -[//]: # '#### SearchBar' +#### SearchBar + +- `value` 属性,支持受控 +- 新增 `defaultValue` 属性,用于搜索默认值,支持以','分割的字符串,用以展示为多个 +- 新增 `onItemClick` 属性,用于点击展示默认值时的x号,支持回调处理 + [//]: # '#### ShortPassword' #### TextArea diff --git a/src/styles/variables-jmapp.scss b/src/styles/variables-jmapp.scss index c84de5194a..f8ef54982f 100644 --- a/src/styles/variables-jmapp.scss +++ b/src/styles/variables-jmapp.scss @@ -2040,14 +2040,11 @@ $searchbar-background: var( ) !default; $searchbar-color: var(--nutui-searchbar-color, $color-title) !default; $searchbar-gap: var(--nutui-searchbar-gap, 16px) !default; +$searchbar-inner-gap: var(--nutui-searchbar-inner-gap, 8px) !default; $searchbar-font-size: var( --nutui-searchbar-font-size, $font-size-base ) !default; -$searchbar-content-padding: var( - --nutui-searchbar-content-padding, - 0 12px -) !default; $searchbar-content-background: var( --nutui-searchbar-content-background, $color-default-light @@ -2060,6 +2057,7 @@ $searchbar-content-round-border-radius: var( --nutui-searchbar-content-round-border-radius, 18px ) !default; +$searchbar-icon-size: var(--nutui-searchbar-icon-size, 20px) !default; $searchbar-input-height: var(--nutui-searchbar-input-height, 36px) !default; $searchbar-input-padding: var( --nutui-searchbar-input-padding, diff --git a/src/styles/variables-jrkf.scss b/src/styles/variables-jrkf.scss index b5a0ba6295..534b6b8198 100644 --- a/src/styles/variables-jrkf.scss +++ b/src/styles/variables-jrkf.scss @@ -2146,14 +2146,11 @@ $searchbar-background: var( ) !default; $searchbar-color: var(--nutui-searchbar-color, $color-text-title) !default; $searchbar-gap: var(--nutui-searchbar-gap, 16px) !default; +$searchbar-inner-gap: var(--nutui-searchbar-inner-gap, 8px) !default; $searchbar-font-size: var( --nutui-searchbar-font-size, $font-size-base ) !default; -$searchbar-content-padding: var( - --nutui-searchbar-content-padding, - 0 12px -) !default; $searchbar-content-background: var( --nutui-searchbar-content-background, $color-default-light @@ -2166,6 +2163,7 @@ $searchbar-content-round-border-radius: var( --nutui-searchbar-content-round-border-radius, 18px ) !default; +$searchbar-icon-size: var(--nutui-searchbar-icon-size, 20px) !default; $searchbar-input-height: var(--nutui-searchbar-input-height, 36px) !default; $searchbar-input-padding: var( --nutui-searchbar-input-padding, diff --git a/src/styles/variables.scss b/src/styles/variables.scss index 095ae69393..3e9a8e84f3 100644 --- a/src/styles/variables.scss +++ b/src/styles/variables.scss @@ -1926,42 +1926,43 @@ $collapse-wrapper-content-background-color: var( // searchbar(✅) $searchbar-width: var(--nutui-searchbar-width, 100%) !default; -$searchbar-padding: var(--nutui-searchbar-padding, 6px 16px) !default; +$searchbar-padding: var(--nutui-searchbar-padding, 1px 8px) !default; $searchbar-background: var( --nutui-searchbar-background, - $color-background + $color-background-sunken ) !default; $searchbar-color: var(--nutui-searchbar-color, $color-title) !default; -$searchbar-gap: var(--nutui-searchbar-gap, 16px) !default; +$searchbar-gap: var(--nutui-searchbar-gap, 12px) !default; +$searchbar-inner-gap: var(--nutui-searchbar-inner-gap, 8px) !default; $searchbar-font-size: var( --nutui-searchbar-font-size, $font-size-base ) !default; -$searchbar-content-padding: var( - --nutui-searchbar-content-padding, - 0 12px -) !default; $searchbar-content-background: var( --nutui-searchbar-content-background, $color-background-overlay ) !default; $searchbar-content-border-radius: var( --nutui-searchbar-content-border-radius, - 4px + 8px ) !default; $searchbar-content-round-border-radius: var( --nutui-searchbar-content-round-border-radius, - 18px + 19px +) !default; +$searchbar-icon-size: var(--nutui-searchbar-icon-size, 20px) !default; +$searchbar-input-height: var(--nutui-searchbar-input-height, 38px) !default; +$searchbar-input-padding: var( + --nutui-searchbar-input-padding, + 0 0 0 8px ) !default; -$searchbar-input-height: var(--nutui-searchbar-input-height, 32px) !default; -$searchbar-input-padding: var(--nutui-searchbar-input-padding, 0 4px) !default; $searchbar-input-text-color: var( --nutui-searchbar-input-text-color, $color-title ) !default; $searchbar-input-curror-color: var( --nutui-searchbar-input-curror-color, - $color-title + $color-primary ) !default; $searchbar-input-text-align: var( --nutui-searchbar-input-text-align, diff --git a/src/types/spec/searchbar/base.ts b/src/types/spec/searchbar/base.ts index 378aacc871..f39550ab73 100644 --- a/src/types/spec/searchbar/base.ts +++ b/src/types/spec/searchbar/base.ts @@ -4,6 +4,7 @@ import { BaseProps } from '../../base/props' export interface BaseSearchBar extends BaseProps { value: string + defaultValue: string placeholder: string shape: UIRound disabled: boolean @@ -16,10 +17,12 @@ export interface BaseSearchBar extends BaseProps { right: ReactNode leftIn: ReactNode rightIn: ReactNode + tag: boolean onSearch: (val: string) => void onChange: (value: string, e: any) => void onFocus: (value: string, e: any) => void onBlur: (value: string, e: any) => void onClear: (e: any) => void onInputClick: (e: any) => void + onItemClick: (value: string, e: any) => void }