diff --git a/.gitignore b/.gitignore index 7c87415936..995cbd5af1 100644 --- a/.gitignore +++ b/.gitignore @@ -61,6 +61,7 @@ pnpm-lock.*.yaml # local v4 upgrade workflow (personal, not for commit) .cursor/skills/nutui-component-v4-upgrade/ .claude/commands/nutui-v4-upgrade.md +.claude/nutui-*.json # Harmony CSS files src/packages/**/*.harmony.css \ No newline at end of file diff --git a/src/config.json b/src/config.json index 4bc24265de..657dcd7832 100644 --- a/src/config.json +++ b/src/config.json @@ -1005,7 +1005,7 @@ "v15": 2, "author": "vickyYe", "dd": false, - "v16": false + "v16": true }, { "version": "3.0.0", diff --git a/src/packages/configprovider/types.ts b/src/packages/configprovider/types.ts index 2a48c1a81d..7ba1332a49 100644 --- a/src/packages/configprovider/types.ts +++ b/src/packages/configprovider/types.ts @@ -594,6 +594,7 @@ export type NutCSSVariables = | 'nutuiNoticebarHeight' | 'nutuiNoticebarBackground' | 'nutuiNoticebarColor' + | 'nutuiNoticebarIconColor' | 'nutuiNoticebarFontSize' | 'nutuiNoticebarLineHeight' | 'nutuiNoticebarBoxPadding' @@ -601,7 +602,22 @@ export type NutCSSVariables = | 'nutuiNoticebarWrapablePadding' | 'nutuiNoticebarIconGap' | 'nutuiNoticebarLeftIconWidth' + | 'nutuiNoticebarLeftIconWrapWidth' | 'nutuiNoticebarRightIconWidth' + | 'nutuiNoticebarCloseSize' + | 'nutuiNoticebarTagSize' + | 'nutuiNoticebarTagGap' + | 'nutuiNoticebarActionMaxWidth' + | 'nutuiNoticebarActionGap' + | 'nutuiNoticebarActionFontSize' + | 'nutuiNoticebarDescriptionFontSize' + | 'nutuiNoticebarDescriptionColor' + | 'nutuiNoticebarLeftIconBorderRadius' + | 'nutuiNoticebarDescriptionLineHeight' + | 'nutuiNoticebarCloseColor' + | 'nutuiNoticebarCloseIconSize' + | 'nutuiNoticebarCloseRingColor' + | 'nutuiNoticebarCloseRingShadowColor' | 'nutuiTimeselectDateWidth' | 'nutuiTimeselectDateHeight' | 'nutuiTimeselectDateActiveColor' diff --git a/src/packages/noticebar/__test__/__snapshots__/noticebar.spec.tsx.snap b/src/packages/noticebar/__test__/__snapshots__/noticebar.spec.tsx.snap index acaf070498..409f0ef031 100644 --- a/src/packages/noticebar/__test__/__snapshots__/noticebar.spec.tsx.snap +++ b/src/packages/noticebar/__test__/__snapshots__/noticebar.spec.tsx.snap @@ -23,13 +23,21 @@ exports[`align center test 1`] = `
- NutUI 是京东风格的移动端组件库,使用 Vue 语言来编写可以在 H5,小程序平台上的应用,帮助研发人员提升开发效率,改善开发体验。 +
+
+ NutUI 是京东风格的移动端组件库,使用 Vue 语言来编写可以在 H5,小程序平台上的应用,帮助研发人员提升开发效率,改善开发体验。 +
+
@@ -60,13 +68,21 @@ exports[`noticebar base test 1`] = `
- NutUI 是京东风格的移动端组件库,使用 Vue 语言来编写可以在 H5,小程序平台上的应用,帮助研发人员提升开发效率,改善开发体验。 +
+
+ NutUI 是京东风格的移动端组件库,使用 Vue 语言来编写可以在 H5,小程序平台上的应用,帮助研发人员提升开发效率,改善开发体验。 +
+
@@ -97,13 +113,21 @@ exports[`scrollable test 1`] = `
- NutUI 是京东风格的移动端组件库,使用 Vue 语言来编写可以在 H5,小程序平台上的应用,帮助研发人员提升开发效率,改善开发体验。 +
+
+ NutUI 是京东风格的移动端组件库,使用 Vue 语言来编写可以在 H5,小程序平台上的应用,帮助研发人员提升开发效率,改善开发体验。 +
+
diff --git a/src/packages/noticebar/__test__/noticebar.spec.tsx b/src/packages/noticebar/__test__/noticebar.spec.tsx index 367e19a15e..6e6c477b67 100644 --- a/src/packages/noticebar/__test__/noticebar.spec.tsx +++ b/src/packages/noticebar/__test__/noticebar.spec.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import { useState } from 'react' import { render, fireEvent, waitFor, act } from '@testing-library/react' import '@testing-library/jest-dom' -import { Fabulous } from '@nutui/icons-react' +import { Fabulous, Notice } from '@nutui/icons-react' import NoticeBar from '@/packages/noticebar' import Image from '@/packages/image' @@ -352,3 +352,79 @@ test('dynamic children update test', async () => { }) }) }) + +test('wrap mode applies wrapable class with left-icon', () => { + const { container } = render( + } /> + ) + expect(container.querySelector('.nut-noticebar-box')).toHaveClass( + 'nut-noticebar-box-wrapable' + ) + expect(container.querySelector('.nut-noticebar-box-left-icon')).toBeTruthy() +}) + +test('description prop renders sub text', () => { + const { container } = render( + + ) + const desc = container.querySelector('.nut-noticebar-box-description') + expect(desc).toBeTruthy() + expect(desc?.innerHTML).toBe('副文本内容') +}) + +test('tag prop renders info tag', () => { + const { container } = render( + } /> + ) + const tagEl = container.querySelector('.nut-noticebar-box-tag') + expect(tagEl).toBeTruthy() + expect(tagEl?.querySelector('.nut-icon')).toBeTruthy() +}) + +test('action prop renders action button', () => { + const { container } = render( + 强行动点} /> + ) + const actionEl = container.querySelector('.nut-noticebar-box-action') + expect(actionEl).toBeTruthy() + expect(actionEl?.innerHTML).toContain('强行动点') +}) + +test('content-wrapper is rendered in horizontal mode', () => { + const { container } = render( + + ) + expect( + container.querySelector('.nut-noticebar-box-content-wrapper') + ).toBeTruthy() +}) + +test('closeable renders Close icon by default', () => { + const { container } = render() + const closeIcon = container.querySelector('.nut-noticebar-box-right-icon') + expect(closeIcon).toBeTruthy() + expect(closeIcon?.querySelector('.nut-icon-Close')).toBeTruthy() +}) + +test('autoClose renders countdown ring and closes after delay', async () => { + vi.useFakeTimers() + const handleClose = vi.fn() + const { container } = render( + + ) + + expect(container.querySelector('.nut-noticebar-box')).toBeTruthy() + expect( + container.querySelector('.nut-noticebar-box-close-countdown') + ).toBeTruthy() + expect(container.querySelector('.nut-noticebar-box-close-icon')).toBeTruthy() + + act(() => { + vi.advanceTimersByTime(3000) + }) + + expect(container.querySelector('.nut-noticebar-box')).toBeFalsy() + expect(handleClose).toHaveBeenCalled() + + vi.useRealTimers() +}) diff --git a/src/packages/noticebar/demo.taro.tsx b/src/packages/noticebar/demo.taro.tsx index d88a05ef24..b12125b2cf 100644 --- a/src/packages/noticebar/demo.taro.tsx +++ b/src/packages/noticebar/demo.taro.tsx @@ -16,6 +16,9 @@ import Demo8 from './demos/taro/demo8' import Demo9 from './demos/taro/demo9' import Demo10 from './demos/taro/demo10' import Demo11 from './demos/taro/demo11' +import Demo12 from './demos/taro/demo12' +import Demo13 from './demos/taro/demo13' +import Demo14 from './demos/taro/demo14' const NoticeBarDemo = () => { const [translated] = useTranslate({ @@ -31,6 +34,9 @@ const NoticeBarDemo = () => { complexAm: '纵向模式:自定义左侧图标', customAm: '纵向模式:自定义滚动内容,动态变更滚动内容', customRightIcon: '纵向模式:自定义右侧图标', + tagAndAction: '信息标与操作按钮', + autoClose: '自动关闭', + imageIcon: '自定义配图', }, 'en-US': { basic: 'Basic Usage', @@ -44,6 +50,9 @@ const NoticeBarDemo = () => { complexAm: 'Vertical Scroll Complex Animation', customAm: 'Vertical Scroll Custom Style,Dynamic Change Scroll Content', customRightIcon: 'Vertical Scroll Custom Right Icon', + tagAndAction: 'Tag & Action Button', + autoClose: 'Auto Close', + imageIcon: 'Custom Image', }, }) @@ -82,6 +91,12 @@ const NoticeBarDemo = () => { + {translated.tagAndAction} + + {translated.imageIcon} + + {translated.autoClose} + ) diff --git a/src/packages/noticebar/demo.tsx b/src/packages/noticebar/demo.tsx index 29a1931541..eeba2c502e 100644 --- a/src/packages/noticebar/demo.tsx +++ b/src/packages/noticebar/demo.tsx @@ -12,6 +12,9 @@ import Demo8 from './demos/h5/demo8' import Demo9 from './demos/h5/demo9' import Demo10 from './demos/h5/demo10' import Demo11 from './demos/h5/demo11' +import Demo12 from './demos/h5/demo12' +import Demo13 from './demos/h5/demo13' +import Demo14 from './demos/h5/demo14' const NoticeBarDemo = () => { const [translated] = useTranslate({ @@ -27,6 +30,9 @@ const NoticeBarDemo = () => { complexAm: '纵向模式:自定义左侧图标', customAm: '纵向模式:自定义滚动内容,动态变更滚动内容', customRightIcon: '纵向模式:自定义右侧图标', + tagAndAction: '信息标与操作按钮', + autoClose: '自动关闭', + imageIcon: '自定义配图', }, 'en-US': { basic: 'Basic Usage', @@ -40,6 +46,9 @@ const NoticeBarDemo = () => { complexAm: 'Vertical Scroll Complex Animation', customAm: 'Vertical Scroll Custom Style,Dynamic Change Scroll Content', customRightIcon: 'Vertical Scroll Custom Right Icon', + tagAndAction: 'Tag & Action Button', + autoClose: 'Auto Close', + imageIcon: 'Custom Image', }, }) @@ -72,6 +81,12 @@ const NoticeBarDemo = () => {
+

{translated.tagAndAction}

+ +

{translated.imageIcon}

+ +

{translated.autoClose}

+ ) diff --git a/src/packages/noticebar/demos/h5/demo12.tsx b/src/packages/noticebar/demos/h5/demo12.tsx new file mode 100644 index 0000000000..2f009632c0 --- /dev/null +++ b/src/packages/noticebar/demos/h5/demo12.tsx @@ -0,0 +1,43 @@ +import React from 'react' +import { NoticeBar, Button } from '@nutui/nutui-react' +import { Notice } from '@nutui/icons-react' + +const Demo12 = () => { + return ( + <> + } + action={ + + } + wrap + closeable + /> +
+ } + action={ + + } + wrap + closeable + /> +
+ } + action={弱行动点 >} + /> + + ) +} +export default Demo12 diff --git a/src/packages/noticebar/demos/h5/demo13.tsx b/src/packages/noticebar/demos/h5/demo13.tsx new file mode 100644 index 0000000000..e673cc51f2 --- /dev/null +++ b/src/packages/noticebar/demos/h5/demo13.tsx @@ -0,0 +1,35 @@ +import React, { useState } from 'react' +import { NoticeBar, Button } from '@nutui/nutui-react' + +const Demo13 = () => { + const [visible, setVisible] = useState(true) + + const reset = () => { + setVisible(false) + setTimeout(() => setVisible(true), 100) + } + + return ( + <> + {visible && ( + + 强行动点 + + } + autoClose={5000} + onClose={() => {}} + wrap + /> + )} +
+ + + ) +} +export default Demo13 diff --git a/src/packages/noticebar/demos/h5/demo14.tsx b/src/packages/noticebar/demos/h5/demo14.tsx new file mode 100644 index 0000000000..3f72965e15 --- /dev/null +++ b/src/packages/noticebar/demos/h5/demo14.tsx @@ -0,0 +1,46 @@ +import React from 'react' +import { NoticeBar, Image, Button } from '@nutui/nutui-react' +import { Notice } from '@nutui/icons-react' + +const Demo14 = () => { + return ( + <> + + } + tag={} + action={ + + } + closeable + /> +
+ + } + tag={} + action={弱行动点 >} + wrap + closeable + /> + + ) +} +export default Demo14 diff --git a/src/packages/noticebar/demos/taro/demo1.tsx b/src/packages/noticebar/demos/taro/demo1.tsx index 88731496f8..15acfd561b 100644 --- a/src/packages/noticebar/demos/taro/demo1.tsx +++ b/src/packages/noticebar/demos/taro/demo1.tsx @@ -1,4 +1,5 @@ import React from 'react' +import { View } from '@tarojs/components' import { NoticeBar } from '@nutui/nutui-react-taro' const Demo1 = () => { @@ -8,7 +9,7 @@ const Demo1 = () => { return ( <> -
+ { + return ( + <> + } + action={ + + } + wrap + closeable + /> + + } + action={ + + } + wrap + closeable + /> + + } + action={弱行动点 >} + /> + + ) +} +export default Demo12 diff --git a/src/packages/noticebar/demos/taro/demo13.tsx b/src/packages/noticebar/demos/taro/demo13.tsx new file mode 100644 index 0000000000..d227a2e9a9 --- /dev/null +++ b/src/packages/noticebar/demos/taro/demo13.tsx @@ -0,0 +1,36 @@ +import React, { useState } from 'react' +import { View } from '@tarojs/components' +import { NoticeBar, Button } from '@nutui/nutui-react-taro' + +const Demo13 = () => { + const [visible, setVisible] = useState(true) + + const reset = () => { + setVisible(false) + setTimeout(() => setVisible(true), 100) + } + + return ( + <> + {visible && ( + + 强行动点 + + } + autoClose={5000} + onClose={() => {}} + wrap + /> + )} + + + + ) +} +export default Demo13 diff --git a/src/packages/noticebar/demos/taro/demo14.tsx b/src/packages/noticebar/demos/taro/demo14.tsx new file mode 100644 index 0000000000..20756bc9fc --- /dev/null +++ b/src/packages/noticebar/demos/taro/demo14.tsx @@ -0,0 +1,47 @@ +import React from 'react' +import { View } from '@tarojs/components' +import { NoticeBar, Image, Button } from '@nutui/nutui-react-taro' +import { Notice } from '@nutui/icons-react-taro' + +const Demo14 = () => { + return ( + <> + + } + tag={} + action={ + + } + closeable + /> + + + } + tag={} + action={弱行动点 >} + wrap + closeable + /> + + ) +} +export default Demo14 diff --git a/src/packages/noticebar/demos/taro/demo2.tsx b/src/packages/noticebar/demos/taro/demo2.tsx index 915d548be6..52cf69991a 100644 --- a/src/packages/noticebar/demos/taro/demo2.tsx +++ b/src/packages/noticebar/demos/taro/demo2.tsx @@ -1,4 +1,5 @@ import React from 'react' +import { View } from '@tarojs/components' import { NoticeBar } from '@nutui/nutui-react-taro' import { ArrowRight } from '@nutui/icons-react-taro' @@ -14,9 +15,9 @@ const Demo2 = () => { wrap rightIcon={} /> -
+ } /> -
+ { @@ -8,7 +9,7 @@ const Demo3 = () => { return ( <> -
+ ) diff --git a/src/packages/noticebar/demos/taro/demo4.tsx b/src/packages/noticebar/demos/taro/demo4.tsx index 8d2244632d..ae8c6b6685 100644 --- a/src/packages/noticebar/demos/taro/demo4.tsx +++ b/src/packages/noticebar/demos/taro/demo4.tsx @@ -1,4 +1,5 @@ import React from 'react' +import { View } from '@tarojs/components' import { NoticeBar, Image } from '@nutui/nutui-react-taro' import { Failure } from '@nutui/icons-react-taro' @@ -13,11 +14,11 @@ const Demo4 = () => { {text} -
+ } onClick={hello}> {text} -
+ { @@ -19,7 +20,7 @@ const Demo6 = () => { } /> -
+ + +::: + +### Custom Image + +:::demo + + + +::: + +### Auto Close + +:::demo + + + +::: + ## NoticeBar ### Props @@ -113,10 +137,14 @@ Add Right mode to set more custom content. | align | Layout mode. When the value is center, scrolling is not supported | `left` \| `center` | `left` | | direction | Rolling direction | `string` | `horizontal` | | content | Notice text content | `string` | `-` | +| description | Sub text content, displayed below the main text | `ReactNode` | `-` | +| tag | Info tag icon, displayed next to the text, size 12×12 | `ReactNode` | `-` | +| action | Action button area, supports weak action (text link) and strong action (button), max width 99px | `ReactNode` | `-` | | closeable | Whether to enable the off mode | `boolean` | `false` | +| autoClose | Auto close delay (milliseconds), 0 or unset means manual close | `number` | `0` | | leftIcon | Left Icon | `ReactNode` | `-` | -| rightIcon | Right Icon | `ReactNode` | `-` | -| right | Different from rightIcon, it is the right custom area, used by mode of direction='horizontal' | `ReactNode` | `-` | +| rightIcon | Right Icon, defaults to `` in closeable mode | `ReactNode` | `-` | +| right | ~~Deprecated, use action instead~~ Right custom area, used by mode of direction='horizontal' | `ReactNode` | `-` | | delay | Delay time | `string` \| `number` | `1` | | scrollable | Whether to scroll content | `boolean` | `true` | | speed | Scrolling speed (px/s) | `number` | `50` | @@ -143,16 +171,32 @@ The component provides the following CSS variables, which can be used to customi | Name | Description | Default Value | | --- | --- | --- | -| \--nutui-noticebar-height | noticebar height | `36px` | -| \--nutui-noticebar-background | noticebar background | `rgba(251, 248, 220, 1)` | -| \--nutui-noticebar-color | noticebar color | `#d9500b` | -| \--nutui-noticebar-font-size | noticebar font size | `$font-size-s` | -| \--nutui-noticebar-line-height | noticebar line height | `24px` | -| \--nutui-noticebar-box-padding | noticebar box padding | `0 16px` | +| \--nutui-noticebar-height | noticebar height | `40px` | +| \--nutui-noticebar-background | noticebar background | `$color-background-overlay` | +| \--nutui-noticebar-color | noticebar text color | `$color-title` | +| \--nutui-noticebar-icon-color | noticebar icon color | `$color-primary` | +| \--nutui-noticebar-font-size | noticebar font size | `$font-size-base` | +| \--nutui-noticebar-line-height | noticebar line height | `20px` | +| \--nutui-noticebar-box-padding | noticebar box padding | `2px 8px` | | \--nutui-noticebar-border-radius | noticebar border radius | `0` | -| \--nutui-noticebar-wrap-padding | noticebar wrap padding | `16px` | -| \--nutui-noticebar-icon-gap | gap of icon and text | `4px` | -| \--nutui-noticebar-left-icon-width | noticebar left icon width | `16px` | +| \--nutui-noticebar-wrap-padding | noticebar wrap padding | `9px 8px` | +| \--nutui-noticebar-icon-gap | gap of icon and text | `6px` | +| \--nutui-noticebar-left-icon-width | noticebar left icon width | `24px` | +| \--nutui-noticebar-left-icon-wrap-width | left icon width in wrap mode | `32px` | | \--nutui-noticebar-right-icon-width | noticebar right icon width | `16px` | +| \--nutui-noticebar-close-size | close button size | `20px` | +| \--nutui-noticebar-tag-size | info tag size | `12px` | +| \--nutui-noticebar-tag-gap | info tag gap | `4px` | +| \--nutui-noticebar-action-max-width | action button max width | `99px` | +| \--nutui-noticebar-action-gap | action button gap | `12px` | +| \--nutui-noticebar-action-font-size | action button font size | `$font-size-xs` | +| \--nutui-noticebar-description-font-size | description font size | `11px` | +| \--nutui-noticebar-description-color | description color | `$color-text` | +| \--nutui-noticebar-description-line-height | description line height | `16px` | +| \--nutui-noticebar-left-icon-border-radius | left icon border radius | `4px` | +| \--nutui-noticebar-close-color | close button color | `$color-text-help` | +| \--nutui-noticebar-close-icon-size | close icon size | `10px` | +| \--nutui-noticebar-close-ring-color | countdown ring progress color | `$color-text-help` | +| \--nutui-noticebar-close-ring-shadow-color | countdown ring track color | `$color-border` | diff --git a/src/packages/noticebar/doc.md b/src/packages/noticebar/doc.md index 1b5a4c219e..29fbc17fcb 100644 --- a/src/packages/noticebar/doc.md +++ b/src/packages/noticebar/doc.md @@ -104,6 +104,32 @@ import { NoticeBar } from '@nutui/nutui-react' ::: +### 信息标与操作按钮 + +:::demo + + + +::: + +### 自定义配图 + +:::demo + + + +::: + +### 自动关闭 + +通过设置 `autoClose` 属性(毫秒)可启用自动关闭模式,关闭按钮外会展示倒计时圆环动画。 + +:::demo + + + +::: + ## NoticeBar ### Props @@ -113,10 +139,14 @@ import { NoticeBar } from '@nutui/nutui-react' | align | 布局方式, 值为`center`时,不支持滚动 | `left` \| `center` | `left` | | direction | 滚动的方向,可选 horizontal、vertical | `string` | `horizontal` | | content | 提示的信息 | `string` | `-` | +| description | 副文本内容,显示在主文本下方 | `ReactNode` | `-` | +| tag | 信息标图标,显示在文案右侧,尺寸 12×12 | `ReactNode` | `-` | +| action | 操作按钮区域,支持弱行动(文字链接)和强行动(按钮),最大宽度 99px | `ReactNode` | `-` | | closeable | 是否启用关闭模式 | `boolean` | `false` | +| autoClose | 自动关闭延时(毫秒),0 或不传为手动关闭 | `number` | `0` | | leftIcon | 左边的 icon,closeable 模式下默认为空 | `ReactNode` | `-` | -| rightIcon | 右边的 icon,在 closeable 模式下默认为 `` | `ReactNode` | `-` | -| right | 区别于rightIcon,为右边自定义区域,仅用于 direction='horizontal' 模式 | `ReactNode` | `-` | +| rightIcon | 右边的 icon,在 closeable 模式下默认为 `` | `ReactNode` | `-` | +| right | ~~已废弃,建议使用 action 替代~~ 右边自定义区域,仅用于 direction='horizontal' 模式 | `ReactNode` | `-` | | delay | 延时多少秒 | `string` \| `number` | `1` | | scrollable | 是否可以滚动 | `boolean` | `true` | | speed | 滚动速率 (px/s) | `number` | `50` | @@ -143,16 +173,32 @@ import { NoticeBar } from '@nutui/nutui-react' | 名称 | 说明 | 默认值 | | --- | --- | --- | -| \--nutui-noticebar-height | 高度 | `36px` | -| \--nutui-noticebar-background | 背景色 | `rgba(251, 248, 220, 1)` | -| \--nutui-noticebar-color | 文字色 | `#d9500b` | -| \--nutui-noticebar-font-size | 字号 | `$font-size-s` | -| \--nutui-noticebar-line-height | 行高 | `24px` | -| \--nutui-noticebar-box-padding | padding值 | `0 16px` | +| \--nutui-noticebar-height | 高度 | `40px` | +| \--nutui-noticebar-background | 背景色 | `$color-background-overlay` | +| \--nutui-noticebar-color | 文字色 | `$color-title` | +| \--nutui-noticebar-icon-color | 图标色 | `$color-primary` | +| \--nutui-noticebar-font-size | 字号 | `$font-size-base` | +| \--nutui-noticebar-line-height | 行高 | `20px` | +| \--nutui-noticebar-box-padding | padding值 | `2px 8px` | | \--nutui-noticebar-border-radius | 圆角 | `0` | -| \--nutui-noticebar-wrap-padding | 多行展示的padding值 | `8px 16px` | -| \--nutui-noticebar-icon-gap | icon、text间距 | `4px` | -| \--nutui-noticebar-left-icon-width | 左侧icon的宽度和高度的设定 | `16px` | +| \--nutui-noticebar-wrap-padding | 多行展示的padding值 | `9px 8px` | +| \--nutui-noticebar-icon-gap | icon、text间距 | `6px` | +| \--nutui-noticebar-left-icon-width | 左侧icon的宽度和高度的设定 | `24px` | +| \--nutui-noticebar-left-icon-wrap-width | 双行模式下icon的宽度和高度 | `32px` | | \--nutui-noticebar-right-icon-width | 右侧icon的宽度和高度的设定 | `16px` | +| \--nutui-noticebar-close-size | 关闭按钮尺寸 | `20px` | +| \--nutui-noticebar-tag-size | 信息标尺寸 | `12px` | +| \--nutui-noticebar-tag-gap | 信息标与文本间距 | `4px` | +| \--nutui-noticebar-action-max-width | 操作按钮最大宽度 | `99px` | +| \--nutui-noticebar-action-gap | 操作按钮与文本间距 | `12px` | +| \--nutui-noticebar-action-font-size | 操作按钮字号 | `$font-size-xs` | +| \--nutui-noticebar-description-font-size | 副文本字号 | `11px` | +| \--nutui-noticebar-description-color | 副文本颜色 | `$color-text` | +| \--nutui-noticebar-description-line-height | 副文本行高 | `16px` | +| \--nutui-noticebar-left-icon-border-radius | 左侧图标圆角 | `4px` | +| \--nutui-noticebar-close-color | 关闭按钮颜色 | `$color-text-help` | +| \--nutui-noticebar-close-icon-size | 关闭图标尺寸 | `10px` | +| \--nutui-noticebar-close-ring-color | 倒计时圆环进度色 | `$color-text-help` | +| \--nutui-noticebar-close-ring-shadow-color | 倒计时圆环底色 | `$color-border` | diff --git a/src/packages/noticebar/doc.taro.md b/src/packages/noticebar/doc.taro.md index 8082268a37..8617632670 100644 --- a/src/packages/noticebar/doc.taro.md +++ b/src/packages/noticebar/doc.taro.md @@ -104,6 +104,30 @@ import { NoticeBar } from '@nutui/nutui-react-taro' ::: +### 信息标与操作按钮 + +:::demo + + + +::: + +### 自定义配图 + +:::demo + + + +::: + +### 自动关闭 + +:::demo + + + +::: + ## NoticeBar ### Props @@ -113,10 +137,14 @@ import { NoticeBar } from '@nutui/nutui-react-taro' | align | 布局方式, 值为`center`时,不支持滚动 | `left` \| `center` | `left` | | direction | 滚动的方向,可选 horizontal、vertical | `string` | `horizontal` | | content | 提示的信息 | `string` | `-` | +| description | 副文本内容,显示在主文本下方 | `ReactNode` | `-` | +| tag | 信息标图标,显示在文案右侧,尺寸 12×12 | `ReactNode` | `-` | +| action | 操作按钮区域,支持弱行动(文字链接)和强行动(按钮),最大宽度 99px | `ReactNode` | `-` | | closeable | 是否启用关闭模式 | `boolean` | `false` | +| autoClose | 自动关闭延时(毫秒),0 或不传为手动关闭 | `number` | `0` | | leftIcon | 左边的 icon,closeable 模式下默认为空 | `ReactNode` | `-` | -| rightIcon | closeable 模式下,默认为 `` | `ReactNode` | `-` | -| right | 区别于rightIcon,为右边自定义区域,仅用于 direction='horizontal' 模式 | `ReactNode` | `-` | +| rightIcon | closeable 模式下,默认为 `` | `ReactNode` | `-` | +| right | ~~已废弃,建议使用 action 替代~~ 右边自定义区域,仅用于 direction='horizontal' 模式 | `ReactNode` | `-` | | delay | 延时多少秒 | `string` \| `number` | `1` | | scrollable | 是否可以滚动 | `boolean` | `true` | | speed | 滚动速率 (px/s) | `number` | `50` | @@ -143,16 +171,32 @@ import { NoticeBar } from '@nutui/nutui-react-taro' | 名称 | 说明 | 默认值 | | --- | --- | --- | -| \--nutui-noticebar-height | 高度 | `36px` | -| \--nutui-noticebar-background | 背景色 | `rgba(251, 248, 220, 1)` | -| \--nutui-noticebar-color | 文字色 | `#d9500b` | -| \--nutui-noticebar-font-size | 字号 | `$font-size-s` | -| \--nutui-noticebar-line-height | 行高 | `24px` | -| \--nutui-noticebar-box-padding | padding值 | `0 16px` | +| \--nutui-noticebar-height | 高度 | `40px` | +| \--nutui-noticebar-background | 背景色 | `$color-background-overlay` | +| \--nutui-noticebar-color | 文字色 | `$color-title` | +| \--nutui-noticebar-icon-color | 图标色 | `$color-primary` | +| \--nutui-noticebar-font-size | 字号 | `$font-size-base` | +| \--nutui-noticebar-line-height | 行高 | `20px` | +| \--nutui-noticebar-box-padding | padding值 | `2px 8px` | | \--nutui-noticebar-border-radius | 圆角 | `0` | -| \--nutui-noticebar-wrap-padding | 多行展示的padding值 | `8px 16px` | -| \--nutui-noticebar-icon-gap | icon、text间距 | `4px` | -| \--nutui-noticebar-left-icon-width | 左侧icon的宽度和高度的设定 | `16px` | +| \--nutui-noticebar-wrap-padding | 多行展示的padding值 | `9px 8px` | +| \--nutui-noticebar-icon-gap | icon、text间距 | `6px` | +| \--nutui-noticebar-left-icon-width | 左侧icon的宽度和高度的设定 | `24px` | +| \--nutui-noticebar-left-icon-wrap-width | 双行模式下icon的宽度和高度 | `32px` | | \--nutui-noticebar-right-icon-width | 右侧icon的宽度和高度的设定 | `16px` | +| \--nutui-noticebar-close-size | 关闭按钮尺寸 | `20px` | +| \--nutui-noticebar-tag-size | 信息标尺寸 | `12px` | +| \--nutui-noticebar-tag-gap | 信息标与文本间距 | `4px` | +| \--nutui-noticebar-action-max-width | 操作按钮最大宽度 | `99px` | +| \--nutui-noticebar-action-gap | 操作按钮与文本间距 | `12px` | +| \--nutui-noticebar-action-font-size | 操作按钮字号 | `$font-size-xs` | +| \--nutui-noticebar-description-font-size | 副文本字号 | `11px` | +| \--nutui-noticebar-description-color | 副文本颜色 | `$color-text` | +| \--nutui-noticebar-description-line-height | 副文本行高 | `16px` | +| \--nutui-noticebar-left-icon-border-radius | 左侧图标圆角 | `4px` | +| \--nutui-noticebar-close-color | 关闭按钮颜色 | `$color-text-help` | +| \--nutui-noticebar-close-icon-size | 关闭图标尺寸 | `10px` | +| \--nutui-noticebar-close-ring-color | 倒计时圆环进度色 | `$color-text-help` | +| \--nutui-noticebar-close-ring-shadow-color | 倒计时圆环底色 | `$color-border` | diff --git a/src/packages/noticebar/doc.zh-TW.md b/src/packages/noticebar/doc.zh-TW.md index 4658324427..8183f1d2e9 100644 --- a/src/packages/noticebar/doc.zh-TW.md +++ b/src/packages/noticebar/doc.zh-TW.md @@ -104,6 +104,30 @@ import { NoticeBar } from '@nutui/nutui-react' ::: +### 信息標與操作按鈕 + +:::demo + + + +::: + +### 自定義配圖 + +:::demo + + + +::: + +### 自動關閉 + +:::demo + + + +::: + ## NoticeBar ### Props @@ -113,10 +137,14 @@ import { NoticeBar } from '@nutui/nutui-react' | align | 佈局方式, 值為`center`時,不支持滾動 | `left` \| `center` | `left` | | direction | 滾動的方嚮,可選 horizontal、vertical | `string` | `horizontal` | | content | 提示的信息 | `string` | `-` | +| description | 副文本內容,顯示在主文本下方 | `ReactNode` | `-` | +| tag | 信息標圖標,顯示在文案右側,尺寸 12×12 | `ReactNode` | `-` | +| action | 操作按鈕區域,支持弱行動(文字鏈接)和強行動(按鈕),最大寬度 99px | `ReactNode` | `-` | | closeable | 是否啟用關閉模式 | `boolean` | `false` | +| autoClose | 自動關閉延時(毫秒),0 或不傳為手動關閉 | `number` | `0` | | leftIcon | 左邊的 icon,closeable 模式下默認為空 | `ReactNode` | `-` | -| rightIcon | 右邊的 icon,在 closeable 模式下默認為 `` | `ReactNode` | `-` | -| right | 區別於rightIcon,為右邊自定義區域,僅用於 direction='horizontal' 模式 | `ReactNode` | `-` | +| rightIcon | 右邊的 icon,在 closeable 模式下默認為 `` | `ReactNode` | `-` | +| right | ~~已廢棄,建議使用 action 替代~~ 右邊自定義區域,僅用於 direction='horizontal' 模式 | `ReactNode` | `-` | | delay | 延時多少秒 | `string` \| `number` | `1` | | scrollable | 是否可以滾動 | `boolean` | `true` | | speed | 滾動速率 (px/s) | `number` | `50` | @@ -143,16 +171,32 @@ import { NoticeBar } from '@nutui/nutui-react' | 名稱 | 說明 | 默認值 | | --- | --- | --- | -| \--nutui-noticebar-height | 高度 | `36px` | -| \--nutui-noticebar-background | 背景色 | `rgba(251, 248, 220, 1)` | -| \--nutui-noticebar-color | 文字色 | `#d9500b` | -| \--nutui-noticebar-font-size | 字號 | `$font-size-s` | -| \--nutui-noticebar-line-height | 行高 | `24px` | -| \--nutui-noticebar-box-padding | padding值 | `0 16px` | +| \--nutui-noticebar-height | 高度 | `40px` | +| \--nutui-noticebar-background | 背景色 | `$color-background-overlay` | +| \--nutui-noticebar-color | 文字色 | `$color-title` | +| \--nutui-noticebar-icon-color | 圖標色 | `$color-primary` | +| \--nutui-noticebar-font-size | 字號 | `$font-size-base` | +| \--nutui-noticebar-line-height | 行高 | `20px` | +| \--nutui-noticebar-box-padding | padding值 | `2px 8px` | | \--nutui-noticebar-border-radius | 圓角 | `0` | -| \--nutui-noticebar-wrap-padding | 多行展示的padding值 | `8px 16px` | -| \--nutui-noticebar-icon-gap | icon、text間距 | `4px` | -| \--nutui-noticebar-left-icon-width | 左側icon的寬度和高度的設定 | `16px` | +| \--nutui-noticebar-wrap-padding | 多行展示的padding值 | `9px 8px` | +| \--nutui-noticebar-icon-gap | icon、text間距 | `6px` | +| \--nutui-noticebar-left-icon-width | 左側icon的寬度和高度的設定 | `24px` | +| \--nutui-noticebar-left-icon-wrap-width | 雙行模式下icon的寬度和高度 | `32px` | | \--nutui-noticebar-right-icon-width | 右側icon的寬度和高度的設定 | `16px` | +| \--nutui-noticebar-close-size | 關閉按鈕尺寸 | `20px` | +| \--nutui-noticebar-tag-size | 信息標尺寸 | `12px` | +| \--nutui-noticebar-tag-gap | 信息標與文本間距 | `4px` | +| \--nutui-noticebar-action-max-width | 操作按鈕最大寬度 | `99px` | +| \--nutui-noticebar-action-gap | 操作按鈕與文本間距 | `12px` | +| \--nutui-noticebar-action-font-size | 操作按鈕字號 | `$font-size-xs` | +| \--nutui-noticebar-description-font-size | 副文本字號 | `11px` | +| \--nutui-noticebar-description-color | 副文本顏色 | `$color-text` | +| \--nutui-noticebar-description-line-height | 副文本行高 | `16px` | +| \--nutui-noticebar-left-icon-border-radius | 左側圖標圓角 | `4px` | +| \--nutui-noticebar-close-color | 關閉按鈕顏色 | `$color-text-help` | +| \--nutui-noticebar-close-icon-size | 關閉圖標尺寸 | `10px` | +| \--nutui-noticebar-close-ring-color | 倒計時圓環進度色 | `$color-text-help` | +| \--nutui-noticebar-close-ring-shadow-color | 倒計時圓環底色 | `$color-border` | diff --git a/src/packages/noticebar/noticebar.scss b/src/packages/noticebar/noticebar.scss index ca406526d2..139b522877 100644 --- a/src/packages/noticebar/noticebar.scss +++ b/src/packages/noticebar/noticebar.scss @@ -20,10 +20,17 @@ .nut-noticebar-box-wrap { height: auto; } + + .nut-noticebar-box-left-icon { + height: $noticebar-left-icon-wrap-width; + min-width: $noticebar-left-icon-wrap-width; + } } &-wrapable { .nut-noticebar-box-wrap { + flex: initial; + .nut-noticebar-box-wrap-content { position: relative; white-space: normal; @@ -51,26 +58,75 @@ &-left-icon { display: flex; + align-items: center; + justify-content: center; height: $noticebar-left-icon-width; min-width: $noticebar-left-icon-width; margin-right: $noticebar-icon-gap; background-size: 100% 100%; + .nut-icon { - color: $noticebar-color; + color: $noticebar-icon-color; } + + img { + border-radius: $noticebar-left-icon-border-radius; + } + } + + &-content-wrapper { + flex: 1; + overflow: hidden; + min-width: 0; + } + + &-content-main { + display: flex; + align-items: center; + } + + &-description { + font-size: $noticebar-description-font-size; + color: $noticebar-description-color; + line-height: $noticebar-description-line-height; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + &-tag { + display: flex; + align-items: center; + width: $noticebar-tag-size; + height: $noticebar-tag-size; + margin-left: $noticebar-tag-gap; + flex-shrink: 0; + } + + &-action { + display: flex; + align-items: center; + justify-content: center; + max-width: $noticebar-action-max-width; + margin-left: $noticebar-action-gap; + font-size: $noticebar-action-font-size; + color: $color-primary; + flex-shrink: 0; + white-space: nowrap; } &-right-icon { display: flex; align-items: center; justify-content: center; - width: $noticebar-right-icon-width; - margin-left: $noticebar-icon-gap; + width: $noticebar-close-size; + height: $noticebar-close-size; + margin-left: $noticebar-action-gap; + flex-shrink: 0; + cursor: pointer; .nut-icon { - width: 12px; - height: 12px; - color: $noticebar-color; + color: $noticebar-close-color; } } @@ -79,6 +135,49 @@ height: $icon-size-12; } + &-close-countdown { + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: $noticebar-close-size; + height: $noticebar-close-size; + background: conic-gradient( + $noticebar-close-ring-color 0% var(--progress), + $noticebar-close-ring-shadow-color var(--progress) 100% + ); + border-radius: 50%; + + &::before { + content: ''; + position: absolute; + inset: scale-px(1px); + background: $noticebar-background; + border-radius: 50%; + } + } + + &-close-icon { + position: relative; + width: $noticebar-close-icon-size; + height: $noticebar-close-icon-size; + color: $noticebar-close-color; + } + + &-left-icon--product { + height: scale-px(32px); + min-width: scale-px(32px); + + img { + background: $white; + border-radius: $noticebar-left-icon-border-radius; + } + } + + &-right { + flex-shrink: 0; + } + &-wrap { display: flex; flex: 1; @@ -158,11 +257,12 @@ flex-direction: column; } + .nut-noticebar-box-description { + white-space: normal; + } + .nut-noticebar-box-right-icon { align-self: center; - display: flex; - justify-content: center; - width: $noticebar-right-icon-width; margin-left: $noticebar-icon-gap; } } @@ -196,7 +296,17 @@ &-right-icon { margin-left: 0; - margin-right: $noticebar-icon-gap; + margin-right: $noticebar-action-gap; + } + + &-tag { + margin-left: 0; + margin-right: $noticebar-tag-gap; + } + + &-action { + margin-left: 0; + margin-right: $noticebar-action-gap; } .play { @@ -225,5 +335,15 @@ margin-left: 0; margin-right: $noticebar-icon-gap; } + + .nut-noticebar-box-tag { + margin-left: 0; + margin-right: $noticebar-tag-gap; + } + + .nut-noticebar-box-action { + margin-left: 0; + margin-right: $noticebar-action-gap; + } } } diff --git a/src/packages/noticebar/noticebar.taro.tsx b/src/packages/noticebar/noticebar.taro.tsx index ac9acb7d87..c759e15936 100644 --- a/src/packages/noticebar/noticebar.taro.tsx +++ b/src/packages/noticebar/noticebar.taro.tsx @@ -22,13 +22,17 @@ const defaultProps = { direction: 'horizontal', list: [], duration: 1000, - height: 40, + height: 36, content: '', closeable: false, wrap: false, leftIcon: , rightIcon: null, right: null, + description: null, + tag: null, + action: null, + autoClose: 0, delay: 1, scrollable: null, speed: 50, @@ -53,6 +57,10 @@ export const NoticeBar: FunctionComponent< leftIcon, rightIcon, right, + description, + tag, + action, + autoClose, delay, scrollable, speed, @@ -75,6 +83,7 @@ export const NoticeBar: FunctionComponent< const contentRefId = `content-ref-${uid}` const [showNoticeBar, setShowNoticeBar] = useState(true) + const [autoCloseProgress, setAutoCloseProgress] = useState(100) const scrollList: any = useRef([]) const [wrapWidth, SetWrapWidth] = useState(0) const [firstRound, SetFirstRound] = useState(true) @@ -125,6 +134,33 @@ export const NoticeBar: FunctionComponent< return 0 })() + const onCloseRef = useRef(onClose) + onCloseRef.current = onClose + const autoCloseTimerRef = useRef(0) + const autoCloseIntervalRef = useRef(0) + + // 自动关闭 + useEffect(() => { + if (autoClose && autoClose > 0 && showNoticeBar) { + const startTime = Date.now() + autoCloseIntervalRef.current = setInterval(() => { + const elapsed = Date.now() - startTime + const remaining = Math.max(0, 100 - (elapsed / autoClose) * 100) + setAutoCloseProgress(remaining) + if (remaining <= 0) clearInterval(autoCloseIntervalRef.current) + }, 50) as unknown as number + autoCloseTimerRef.current = setTimeout(() => { + setShowNoticeBar(false) + onCloseRef.current?.() + }, autoClose) as unknown as number + return () => { + clearInterval(autoCloseIntervalRef.current) + clearTimeout(autoCloseTimerRef.current) + } + } + setAutoCloseProgress(100) + }, [autoClose, showNoticeBar]) + useEffect(() => { if (isVertical) { if (children) { @@ -186,6 +222,18 @@ export const NoticeBar: FunctionComponent< onClick && onClick(event) } + const onClickIcon = useCallback( + (event: ITouchEvent) => { + event.stopPropagation() + setShowNoticeBar(false) + clearInterval(autoCloseIntervalRef.current) + clearTimeout(autoCloseTimerRef.current) + close && close(event) + onClose && onClose(event) + }, + [close, onClose] + ) + const onAnimationEnd = () => { SetFirstRound(false) setTimeout(() => { @@ -216,16 +264,6 @@ export const NoticeBar: FunctionComponent< }, time) } - const handleClickIcon = useCallback( - (event: ITouchEvent) => { - event.stopPropagation() - setShowNoticeBar(!closeable) - close && close(event) - onClose && onClose(event) - }, - [close, onClose, closeable] - ) - const isEllipsis = () => { if (isCanScroll == null && align === 'left') { return wrap @@ -392,7 +430,6 @@ export const NoticeBar: FunctionComponent< const style: any = { width: '100%' } if (height) { style.height = `${height}px` - // style.lineHeight = `${height}px` } const offset = childOffset[index] if (offset) { @@ -461,78 +498,108 @@ export const NoticeBar: FunctionComponent< setIsContainerReady(true) }, []) - const renderLeftIcon = useCallback(() => { + const renderLeftIcon = () => { + if (!leftIcon) return null + return {leftIcon} + } + + const renderTag = () => { + if (!tag) return null + return {tag} + } + + const renderAction = () => { + if (!action) return null + return {action} + } + + const renderAutoCloseIcon = () => { return ( - <> - {leftIcon ? ( - {leftIcon} - ) : null} - + + + ) - }, [leftIcon]) - - const renderRight = useCallback( - () => ( - <> - {right ? ( - {right} - ) : null} - - ), - [right] - ) + } - const renderRightIcon = useCallback( - () => ( - <> - {rightIcon || closeable ? ( - - {rightIcon || ( - - )} - - ) : null} - - ), - [rightIcon, closeable, handleClickIcon] - ) + const renderCloseIcon = () => { + if (!closeable && !rightIcon && !(autoClose && autoClose > 0)) return null + return ( + + {rightIcon || + (autoClose && autoClose > 0 ? ( + renderAutoCloseIcon() + ) : ( + + ))} + + ) + } + + const renderRight = () => { + if (!right) return null + if (process.env.NODE_ENV !== 'production') { + console.warn( + '[NutUI] NoticeBar: `right` prop is deprecated, use `action` instead.' + ) + } + return {right} + } return ( {showNoticeBar && direction === 'horizontal' ? ( {renderLeftIcon()} - - - {children} - {content} + + + + + {children} + {content} + + + {renderTag()} + {description ? ( + + {description} + + ) : null} + {renderAction()} {renderRight()} - {renderRightIcon()} + {renderCloseIcon()} ) : null} {showNoticeBar && hasVerticalContent && isVertical ? ( {renderLeftIcon()} {children ? ( - + {scrollList.current.map((item: string, index: number) => { return ( ) : ( {scrollList.current.map((item: string, index: number) => { return ( { @@ -568,8 +635,10 @@ export const NoticeBar: FunctionComponent< })} )} + {renderTag()} + {renderAction()} {renderRight()} - {renderRightIcon()} + {renderCloseIcon()} ) : null} diff --git a/src/packages/noticebar/noticebar.tsx b/src/packages/noticebar/noticebar.tsx index ccf99c42c5..7d9fedc4d3 100644 --- a/src/packages/noticebar/noticebar.tsx +++ b/src/packages/noticebar/noticebar.tsx @@ -20,13 +20,17 @@ const defaultProps = { direction: 'horizontal', list: [], duration: 1000, - height: 40, + height: 36, content: '', closeable: false, wrap: false, leftIcon: , rightIcon: null, right: null, + description: null, + tag: null, + action: null, + autoClose: 0, delay: 1, scrollable: null, speed: 50, @@ -51,6 +55,10 @@ export const NoticeBar: FunctionComponent< leftIcon, rightIcon, right, + description, + tag, + action, + autoClose, delay, scrollable, speed, @@ -67,7 +75,8 @@ export const NoticeBar: FunctionComponent< const classPrefix = 'nut-noticebar' const wrapRef = useRef(null) const contentRef = useRef(null) - const [showNoticeBar, SetShowNoticeBar] = useState(true) + const [showNoticeBar, setShowNoticeBar] = useState(true) + const [autoCloseProgress, setAutoCloseProgress] = useState(100) const scrollList: any = useRef([]) const [wrapWidth, SetWrapWidth] = useState(0) const [firstRound, SetFirstRound] = useState(true) @@ -118,6 +127,33 @@ export const NoticeBar: FunctionComponent< return 0 })() + const onCloseRef = useRef(onClose) + onCloseRef.current = onClose + const autoCloseTimerRef = useRef(0) + const autoCloseIntervalRef = useRef(0) + + // 自动关闭 + useEffect(() => { + if (autoClose && autoClose > 0 && showNoticeBar) { + const startTime = Date.now() + autoCloseIntervalRef.current = window.setInterval(() => { + const elapsed = Date.now() - startTime + const remaining = Math.max(0, 100 - (elapsed / autoClose) * 100) + setAutoCloseProgress(remaining) + if (remaining <= 0) clearInterval(autoCloseIntervalRef.current) + }, 50) + autoCloseTimerRef.current = window.setTimeout(() => { + setShowNoticeBar(false) + onCloseRef.current?.() + }, autoClose) + return () => { + clearInterval(autoCloseIntervalRef.current) + clearTimeout(autoCloseTimerRef.current) + } + } + setAutoCloseProgress(100) + }, [autoClose, showNoticeBar]) + useEffect(() => { if (isVertical) { if (children) { @@ -175,7 +211,9 @@ export const NoticeBar: FunctionComponent< const onClickIcon = (event: MouseEvent) => { event.stopPropagation() - SetShowNoticeBar(!closeable) + setShowNoticeBar(false) + clearInterval(autoCloseIntervalRef.current) + clearTimeout(autoCloseTimerRef.current) close && close(event) onClose && onClose(event) } @@ -210,14 +248,6 @@ export const NoticeBar: FunctionComponent< }, time) } - // 点击滚动单元 - const handleClickIcon = (event: MouseEvent) => { - event.stopPropagation() - SetShowNoticeBar(!closeable) - close && close(event) - onClose && onClose(event) - } - const isEllipsis = () => { if (isCanScroll == null && align === 'left') { return wrap @@ -450,50 +480,103 @@ export const NoticeBar: FunctionComponent< setIsContainerReady(true) }, []) + const renderLeftIcon = () => { + if (!leftIcon) return null + return
{leftIcon}
+ } + + const renderTag = () => { + if (!tag) return null + return
{tag}
+ } + + const renderAction = () => { + if (!action) return null + return
{action}
+ } + + const renderAutoCloseIcon = () => { + return ( +
+ +
+ ) + } + + const renderCloseIcon = () => { + if (!closeable && !rightIcon && !(autoClose && autoClose > 0)) return null + return ( +
+ {rightIcon || + (autoClose && autoClose > 0 ? ( + renderAutoCloseIcon() + ) : ( + + ))} +
+ ) + } + + const renderRight = () => { + if (!right) return null + if (process.env.NODE_ENV !== 'production') { + console.warn( + '[NutUI] NoticeBar: `right` prop is deprecated, use `action` instead.' + ) + } + return
{right}
+ } + return (
{showNoticeBar && direction === 'horizontal' ? (
- {leftIcon ? ( -
{leftIcon}
- ) : null} -
-
- {children} - {content} + {renderLeftIcon()} +
+
+
+
+ {children} + {content} +
+
+ {renderTag()}
+ {description ? ( +
+ {description} +
+ ) : null}
- {right ? ( -
{right}
- ) : null} - {closeable || rightIcon ? ( -
- {rightIcon || ( - - )} -
- ) : null} + {renderAction()} + {renderRight()} + {renderCloseIcon()}
) : null} {showNoticeBar && hasVerticalContent && isVertical ? (
- {leftIcon ? ( -
{leftIcon}
- ) : null} + {renderLeftIcon()} {children ? ( -
+
{scrollList.current.map((item: string, index: number) => { return (
) : (
{scrollList.current.map((item: string, index: number) => { return ( - // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
{ @@ -530,17 +612,10 @@ export const NoticeBar: FunctionComponent< })}
)} -
{ - handleClickIcon(e) - }} - > - {rightIcon || - (closeable ? ( - - ) : null)} -
+ {renderTag()} + {renderAction()} + {renderRight()} + {renderCloseIcon()}
) : null}
diff --git a/src/styles/variables-daojia.scss b/src/styles/variables-daojia.scss index 3603c7d984..3e882769cf 100644 --- a/src/styles/variables-daojia.scss +++ b/src/styles/variables-daojia.scss @@ -1103,6 +1103,22 @@ $noticebar-left-icon-width: var(--nutui-noticebar-left-icon-width, 16px) !default; $noticebar-right-icon-width: var(--nutui-noticebar-right-icon-width, 16px) !default; +$noticebar-icon-color: var(--nutui-noticebar-icon-color, $color-primary) !default; +$noticebar-left-icon-wrap-width: var(--nutui-noticebar-left-icon-wrap-width, 32px) !default; +$noticebar-close-size: var(--nutui-noticebar-close-size, 20px) !default; +$noticebar-tag-size: var(--nutui-noticebar-tag-size, 12px) !default; +$noticebar-tag-gap: var(--nutui-noticebar-tag-gap, 4px) !default; +$noticebar-action-max-width: var(--nutui-noticebar-action-max-width, 99px) !default; +$noticebar-action-gap: var(--nutui-noticebar-action-gap, 12px) !default; +$noticebar-action-font-size: var(--nutui-noticebar-action-font-size, $font-size-xs) !default; +$noticebar-description-font-size: var(--nutui-noticebar-description-font-size, 11px) !default; +$noticebar-description-color: var(--nutui-noticebar-description-color, $color-text) !default; +$noticebar-left-icon-border-radius: var(--nutui-noticebar-left-icon-border-radius, 4px) !default; +$noticebar-description-line-height: var(--nutui-noticebar-description-line-height, 16px) !default; +$noticebar-close-color: var(--nutui-noticebar-close-color, $color-text-help) !default; +$noticebar-close-icon-size: var(--nutui-noticebar-close-icon-size, 10px) !default; +$noticebar-close-ring-color: var(--nutui-noticebar-close-ring-color, $color-text-help) !default; +$noticebar-close-ring-shadow-color: var(--nutui-noticebar-close-ring-shadow-color, $color-border) !default; // TimeSelect(✅) $timeselect-date-width: var(--nutui-timeselect-date-width, 140px) !default; diff --git a/src/styles/variables-jmapp.scss b/src/styles/variables-jmapp.scss index 9f50ac70a0..273346acd3 100644 --- a/src/styles/variables-jmapp.scss +++ b/src/styles/variables-jmapp.scss @@ -1881,6 +1881,25 @@ $noticebar-right-icon-width: var( --nutui-noticebar-right-icon-width, 16px ) !default; +$noticebar-icon-color: var(--nutui-noticebar-icon-color, $color-primary) !default; +$noticebar-left-icon-wrap-width: var( + --nutui-noticebar-left-icon-wrap-width, + 32px +) !default; +$noticebar-close-size: var(--nutui-noticebar-close-size, 20px) !default; +$noticebar-tag-size: var(--nutui-noticebar-tag-size, 12px) !default; +$noticebar-tag-gap: var(--nutui-noticebar-tag-gap, 4px) !default; +$noticebar-action-max-width: var(--nutui-noticebar-action-max-width, 99px) !default; +$noticebar-action-gap: var(--nutui-noticebar-action-gap, 12px) !default; +$noticebar-action-font-size: var(--nutui-noticebar-action-font-size, $font-size-xs) !default; +$noticebar-description-font-size: var(--nutui-noticebar-description-font-size, 11px) !default; +$noticebar-description-color: var(--nutui-noticebar-description-color, $color-text) !default; +$noticebar-left-icon-border-radius: var(--nutui-noticebar-left-icon-border-radius, 4px) !default; +$noticebar-description-line-height: var(--nutui-noticebar-description-line-height, 16px) !default; +$noticebar-close-color: var(--nutui-noticebar-close-color, $color-text-help) !default; +$noticebar-close-icon-size: var(--nutui-noticebar-close-icon-size, 10px) !default; +$noticebar-close-ring-color: var(--nutui-noticebar-close-ring-color, $color-text-help) !default; +$noticebar-close-ring-shadow-color: var(--nutui-noticebar-close-ring-shadow-color, $color-border) !default; // TimeSelect(✅) $timeselect-date-width: var(--nutui-timeselect-date-width, 140px) !default; diff --git a/src/styles/variables-jrkf.scss b/src/styles/variables-jrkf.scss index 088fb4ef61..6f7e709c60 100644 --- a/src/styles/variables-jrkf.scss +++ b/src/styles/variables-jrkf.scss @@ -1984,6 +1984,25 @@ $noticebar-right-icon-width: var( --nutui-noticebar-right-icon-width, 16px ) !default; +$noticebar-icon-color: var(--nutui-noticebar-icon-color, $color-primary) !default; +$noticebar-left-icon-wrap-width: var( + --nutui-noticebar-left-icon-wrap-width, + 32px +) !default; +$noticebar-close-size: var(--nutui-noticebar-close-size, 20px) !default; +$noticebar-tag-size: var(--nutui-noticebar-tag-size, 12px) !default; +$noticebar-tag-gap: var(--nutui-noticebar-tag-gap, 4px) !default; +$noticebar-action-max-width: var(--nutui-noticebar-action-max-width, 99px) !default; +$noticebar-action-gap: var(--nutui-noticebar-action-gap, 12px) !default; +$noticebar-action-font-size: var(--nutui-noticebar-action-font-size, $font-size-xs) !default; +$noticebar-description-font-size: var(--nutui-noticebar-description-font-size, 11px) !default; +$noticebar-description-color: var(--nutui-noticebar-description-color, $color-text) !default; +$noticebar-left-icon-border-radius: var(--nutui-noticebar-left-icon-border-radius, 4px) !default; +$noticebar-description-line-height: var(--nutui-noticebar-description-line-height, 16px) !default; +$noticebar-close-color: var(--nutui-noticebar-close-color, $color-text-help) !default; +$noticebar-close-icon-size: var(--nutui-noticebar-close-icon-size, 10px) !default; +$noticebar-close-ring-color: var(--nutui-noticebar-close-ring-color, $color-text-help) !default; +$noticebar-close-ring-shadow-color: var(--nutui-noticebar-close-ring-shadow-color, $color-border) !default; // TimeSelect(✅) $timeselect-date-width: var(--nutui-timeselect-date-width, 140px) !default; diff --git a/src/styles/variables.scss b/src/styles/variables.scss index 1ad90e86f2..53d7b755bc 100644 --- a/src/styles/variables.scss +++ b/src/styles/variables.scss @@ -1770,30 +1770,90 @@ $fixednav-item-active-color: var( ) !default; // NoticeBar(✅) -$noticebar-height: var(--nutui-noticebar-height, scale-px(36px)) !default; +$noticebar-height: var(--nutui-noticebar-height, scale-px(40px)) !default; $noticebar-background: var( --nutui-noticebar-background, - rgba(251, 248, 220, 1) + $color-background-overlay +) !default; +$noticebar-color: var(--nutui-noticebar-color, $color-title) !default; +$noticebar-icon-color: var( + --nutui-noticebar-icon-color, + $color-primary ) !default; -$noticebar-color: var(--nutui-noticebar-color, #d9500b) !default; -$noticebar-font-size: var(--nutui-noticebar-font-size, $font-size-s) !default; -$noticebar-line-height: var(--nutui-noticebar-line-height, scale-px(24px)) !default; -$noticebar-box-padding: var(--nutui-noticebar-box-padding, 0 scale-px(16px)) !default; +$noticebar-font-size: var(--nutui-noticebar-font-size, $font-size-base) !default; +$noticebar-line-height: var(--nutui-noticebar-line-height, scale-px(20px)) !default; +$noticebar-box-padding: var(--nutui-noticebar-box-padding, scale-px(2px) scale-px(8px)) !default; $noticebar-border-radius: var(--nutui-noticebar-border-radius, 0) !default; $noticebar-wrap-padding: var( --nutui-noticebar-wrapable-padding, - scale-px(8px) scale-px(16px) + scale-px(9px) scale-px(8px) ) !default; -$noticebar-icon-gap: var(--nutui-noticebar-icon-gap, scale-px(4px)) !default; +$noticebar-icon-gap: var(--nutui-noticebar-icon-gap, scale-px(6px)) !default; $noticebar-left-icon-width: var( --nutui-noticebar-left-icon-width, - scale-px(16px) + scale-px(24px) +) !default; +$noticebar-left-icon-wrap-width: var( + --nutui-noticebar-left-icon-wrap-width, + scale-px(32px) ) !default; $noticebar-right-icon-width: var( --nutui-noticebar-right-icon-width, scale-px(16px) ) !default; - +$noticebar-close-size: var( + --nutui-noticebar-close-size, + scale-px(20px) +) !default; +$noticebar-tag-size: var( + --nutui-noticebar-tag-size, + scale-px(12px) +) !default; +$noticebar-tag-gap: var(--nutui-noticebar-tag-gap, scale-px(4px)) !default; +$noticebar-action-max-width: var( + --nutui-noticebar-action-max-width, + scale-px(99px) +) !default; +$noticebar-action-gap: var( + --nutui-noticebar-action-gap, + scale-px(12px) +) !default; +$noticebar-action-font-size: var( + --nutui-noticebar-action-font-size, + $font-size-xs +) !default; +$noticebar-description-font-size: var( + --nutui-noticebar-description-font-size, + scale-px(11px) +) !default; +$noticebar-description-color: var( + --nutui-noticebar-description-color, + $color-text +) !default; +$noticebar-left-icon-border-radius: var( + --nutui-noticebar-left-icon-border-radius, + scale-px(4px) +) !default; +$noticebar-description-line-height: var( + --nutui-noticebar-description-line-height, + scale-px(16px) +) !default; +$noticebar-close-color: var( + --nutui-noticebar-close-color, + $color-text-help +) !default; +$noticebar-close-icon-size: var( + --nutui-noticebar-close-icon-size, + scale-px(10px) +) !default; +$noticebar-close-ring-color: var( + --nutui-noticebar-close-ring-color, + $color-text-help +) !default; +$noticebar-close-ring-shadow-color: var( + --nutui-noticebar-close-ring-shadow-color, + $color-border +) !default; // TimeSelect(✅) $timeselect-date-width: var(--nutui-timeselect-date-width, scale-px(140px)) !default; $timeselect-date-height: var(--nutui-timeselect-date-height, scale-px(40px)) !default; diff --git a/src/types/spec/noticebar/base.ts b/src/types/spec/noticebar/base.ts index 36bc7c9229..acddee2da9 100644 --- a/src/types/spec/noticebar/base.ts +++ b/src/types/spec/noticebar/base.ts @@ -15,12 +15,16 @@ export interface BaseNoticeBar extends BaseProps { leftIcon: ReactNode rightIcon: ReactNode right: ReactNode + description: ReactNode + tag: ReactNode + action: ReactNode + autoClose: number delay: string | number scrollable: boolean | null speed: number close?: (event: any) => void click?: (event: any) => void - onClose?: (event: any) => void + onClose?: (event?: any) => void onClick?: (event: any) => void onItemClick?: (event: any, value: any) => void }