diff --git a/migrate-from-v2.md b/migrate-from-v2.md index c414b0a315..19cddb0c34 100644 --- a/migrate-from-v2.md +++ b/migrate-from-v2.md @@ -18,12 +18,9 @@ npm install @nutui/nutui-react-taro 3. 处理不兼容更新 -从 NutUI React 1.x 到 NutUI React 2.x 存在一些不兼容更新,需要仔细阅读不兼容更新内容,并依次处理。 - -你可以手动对照下面的列表逐条检查代码进行修改,另外,我们也提供了一个 codemod cli 工具 @nutui/nutui-react-codemod 以帮助你快速升级到 v2 版本。在运行 codemod cli 前,请先提交你的本地代码修改。 +从 NutUI React 2.x 到 NutUI React 3.x 存在一些不兼容更新,需要仔细阅读不兼容更新内容,并依次处理。 4. 主题变量更名: - 如,primary-color 更名为 color-primary;注意在使用自定义主题,特别是使用 ConfigProvider 组件的情况下,有没有使用 `nutuiBrandColor`,这时记得更名为 `nutuiColorPrimary` ## 兼容更新 @@ -43,6 +40,9 @@ plugins: [ libraryDirectory: "dist/esm", style: 'css', camel2DashComponentName: false, + "customName": (name, file) => { + return `@nutui/nutui-react-taro/dist/es/packages/${name.toLowerCase()}` + } }, "nutui-react", ] @@ -61,206 +61,67 @@ plugins: [ libraryDirectory: "dist/esm", style: 'css', camel2DashComponentName: false, + "customName": (name, file) => { + return `@nutui/nutui-react-taro/dist/es/packages/${name.toLowerCase()}` + } }, "nutui-react-taro", ] ] ``` -2. 更完善的类型导出以及对类型增加 `JSDoc` 注释 -3. 组件分类的调整 - 在组件分类上,我们从交互维度上,和交互设计侧共同对 1.x 分类进行了基于信息结构的评审,并进行了子类梳理,完成重新分类,目标是更贴合交互场景的分布,易于查找组件。主要分布在: +## 新增组件 -- 基础组件,将 `Popup` 组件移除,将 `Popup` 细分到操作反馈-引导提示部分; -- 布局组件,保持不变; -- 导航组件:将分页相关组件 `Pagination`、`Indicator` 移动到展示组件(考虑移动端的分页轻操作);`Menu` 菜单移动到数据录入类-选择器子类(考虑 `Menu` 主要是作为筛选器);将 `BackTop` 移至导航组件,作为锚点组件的一部分; -- 展示组件:将 `Badge`、`NoticeBar`、`Popover` 移至操作反馈-引导提示类,`Empty`、`Skeleton` 移至操作反馈-加载状态结果反馈中;`WaterMark`、`TrendArrow` 作为特性增强类组件放在特色组件中,待由该类组件的使用场景和范围确认是否变更分类;同时新增 `Audio`,将其同 `Video`、`ImagePreview`、`Swiper` 一同归为展示-多媒体类; -- 操作反馈类,新增 `Skeleton`、`Empty`(加载结果反馈类),`Popover`、`Notify`、`NoticeBar`、`Popup` (引导提示类)6个组件;同时去除 `BackTop`(导航组件-锚点类)、`Switch`(数据录入-选择器)、`Audio``(展示-多媒体);在此基础上,未来会考虑增加 ResultPage`,整合错误状态、空状态等反馈状态,该组件在考虑中;同时考虑增加加载状态 `Loading` 组件。版本待定。 -- 数据录入类,主要分为两大类-输入及选择器。在输入中增加 `Signature`,该组件在 `Form` 表单中的应用范围日渐广泛,从特色组件中移入到数据录入部分;选择器中增加 `Switch`、`Menu`,及 `Address`。其中 `Signature` 和 `Address` 都是考虑其常用性,从特色中迁移到数据录入部分。 -- 特色组件,保留 `Barrage`、`Card`、`TimeSelect`,新增 `WaterMark`、`TrendArrow`。 +- SideBar +- PickerView ## 不兼容更新 -## NutUI Icons 调整 - -1.x 版本我们在实际开发过程中会发现 `Button` 只是引用了一个很小的 Loading Icon,但是全量引用了 IconFont 字体 ,会导致开发者的项目文件增大。我们在 NutUI React 2.x 中为解决此问题,重新定义了 Icon 组件,将所有的 Icons 抽离成单独的图标组件库 @nutui/icons-react(Taro 适配下为 @nutui/icons-react-taro) ,使其可以进行按需加载使用。 因此一些组件之前关于 Icon 的相关 Props 将被移除,需要使用插槽或者传递一个 Component 组件的 Props 进行使用。 受影响的组件如下: - -- Avatar -- Button -- ImagePreview -- Collapse -- InfiniteLoading -- Popup -- Steps -- Switch -- Toast -- Progress -- NoticeBar -- SearchBar -- Navbar -- Menu -- Tabbar -- Checkbox -- InputNumber -- Input -- Radio -- Rate -- Uploader -- Popover -- Grid -- TrendArrow - -如果你的项目中使用了这些组件,请仔细阅读文档并进行升级。 - -## 组件名称调整 - -- GridItem -> Grid.Item -- TabbarItem -> Tabbar.Item -- CollapseItem -> Collapse.Item -- SwiperItem -> Swiper.Item -- CellGroup -> Cell.Group -- MenuItem -> Menu.Item -- Infiniteloading -> InfiniteLoading +如果你的项目中使用了这些组件,请仔细阅读文档并进行升级 ## 组件 API 调整 -在 2.0 版本中,我们重点对组件 API 进行了评审和修订,使属性和方法命名更贴合常用的命名习惯及 React 语言规范,目标希望开发者在使用组件时得心应手。我们的思路大体如下: - -### 属性定义 - -本次升级重点关注属性的命名方面,从 1.x 的 610 个属性精简为 410 个,更精简、更规范;同时增强属性的类型范围,提升自定义能力。 - -- 对同一属性进行统一描述,比如: - - 缩写类会改为全拼,如 `desc`、`descSlot`、`description` 统一为 `description` - - 能使用名词或形容词的优先使用该类词性,一个词能说明白的不用两个词。 - - 如 `wrap`、`wrapable` 统一为 `wrap` - - 如将 `isXxx` 统一为 `xxx`,如 `isVisible`、`isDeletable` 等,可直接使用 `visible`、`deletable` 等,形容词化 - - 如`showXxx` 尽量统一为 `xxx`,名词化。【部分属性待优化。】 - - 如 `roundRadius` 改为 `radius` ,`columnNum` 改为 `columns`等 - - `onClickXxx` 统一为 `onXxxClick` - - `modelValue` 统一为 `value`,并增加支持 `defaultValue`,支持受控与非受控模式 - - 对于标识位置、对齐等类的属性,将属性名变更为其上一层的属性定义,如 `center`会改为 `align`、`vertical`,改为 `direction`,像标记距离的,如 `top`、`bottom`、`distance` 等,会改为 `threshold` - - 不规范的定义如 `okBtn`、`okText` 这种,会改为 `confirmXxx` -- 扩充属性的类型。如 `title` 的类型从 `string` 扩充为 `React.ReactNode`,增强自定义内容;其中有涉及合并属性的,统一用最简命名来定义属性;如 `title`、`titleSlot` 合并为 `title`,再扩充属性类型。 -- 对于 `xxClass`、`xxStyle`类的属性,移除,可使用 `className` 、`style` 来实现。 -- 移除与样式有关的属性,除基础组件的样式属性及部分实现起来较为复杂的样式属性外,大多数样式属性被移除,可通过样式变量来实现。 -- 将普遍认同可内置的属性或不怎么使用的属性,直接内置,去掉属性设置。 - -### 组件实现 - ### 基础组件 #### Button -- 去掉一些样式变量。如 `$button-default-font-weight` `$button-large-font-weight` 等。 - -#### Cell - -- `subTitle` 重命名为 `description`,类型修改为 `React.Node` -- `desc` 重命名为 `extra`,类型修改为 `React.Node` -- `roundRadius` 重命名为 `radius` -- `center` 重命名为 `align`,默认值修改为`flex-start`,可选值为 `flex-start`、`center`、`flex-end` -- 移除 `icon`、 `isLink`、`url`、`linkSlot`、`replace`、`descTextAlign`,通过用户自定义节点实现,参考文档demo示例 - -#### CellGroup - -- 新增 `divider`,单元格之间是否有分割线 -- `desc` 重命名为 `description` -- `title`、`description` 类型修改为 `React.Node` -- 移除 `titleSlot` 和 `descSlot`,通过 `title`、`description` 实现 -- - -#### ConfigProvider - -#### Icon - -#### Image - -- 移除 `round`,通过 `radius` 实现圆或圆角 -- 移除 `loadingImg` 和 `slotLoading`,通过 `loading` 属性实现,当 `loading` 属性设置为 `ReactNode` 或 `true` 时,表示展示 `loading` 状态 -- 移除 `showError` 和 `slotError`,通过 `error` 属性实现,当 `error` 属性设置为 `ReactNode` 或 `true` 时,表示展示 `error` 状态 -- 移除 `loadingImg`,可通过 `loading` 设置 `ReactNode` -- 移除 `errorImg`,可通过 `error` 设置 `ReactNode` -- `showError` 重命名为 `error`,类型修改为 `boolean|ReactNode` -- `showLoading` 重命名为 `loading`,类型修改为 `boolean|ReactNode` +- 移除样式变量 `--nutui-button-default-font-weight` -#### Overlay - -- `overlayClass` 重命名为 `className` -- `overlayStyle` 重命名为 `style` -- `closeOnClickOverlay` 重命名为 `closeOnOverlayClick` -- 更改 `lockScroll` 默认值为 `true` -- 新增 `afterClose` 和 `afterShow`,用于完全关闭后触发的回调和完全展示后触发的回调 - -#### Popup - -- `popClass` 重命名为 `className`,统一将组件的样式类名使用 `className`,不再指定特殊名字,减轻用户使用的记忆成本 -- `overlayClass` 重命名为 `overlayClassName`,继承自`Overlay` -- `closeOnClickOverlay` 重命名为 `closeOnOverlayClick` -- `onOpened` 和 `onClosed` 重命名为 `afterShow` 和 `afterClose`,继承自`Overlay`,用于完全关闭后触发的回调和完全展示后触发的回调 -- `destroyOnClose` 的描述进行了修订,改为:“组件不可见时,卸载内容”,并把其默认值改为了`false` -- `onClickCloseIcon` 和 `onClickOverlay` 两个方法,增加布尔判断,如返回false 或 未定义返回值时,将不再关闭 Popup;默认值为 `true`;在demo中已增加相应示例;同时,两者的名字变更为 `onCloseIconClick`、`onOverlayClick` -- `closeIcon` 类型从 `string` 改为 `ReactNode`,以前的 `closeIcon='mask-close'` 需改为 `closeIcon={}` -- `onOverlayClick` 和 `onCloseIconClick` 不会自动触发 `onClose` 了,如需触发关闭事件,需主动调用 `onClose` 回调函数 -- 新增 `description` 属性,支持标题下展示描述内容。 -- 调整 `position` 为 `bottom` 时的默认样式,默认支持圆角,此刻不需要再设置 `round` 属性。 +[//]: # '#### Cell' +[//]: # '#### CellGroup' +[//]: # '#### ConfigProvider' +[//]: # '#### Icon' +[//]: # '#### Image' +[//]: # '#### Overlay' +[//]: # '#### Popup' ### 布局组件 -#### Divider - -- 移除 `dashed`, 通过 `style` 属性实现 -- 移除 `hairline`, 默认为 `true` -- CSS 变量调整:`$divider-before-margin-right`、`$divider-after-margin-left` 统一为 `$divider-spacing`,`$divider-vertical-border-left` 变更为 `$divider-border-color`,增加 `$divider-side-width`。 +[//]: # '#### Divider' #### Grid -- 移除 `fontSize`,可自行控制传入的组件字体大小 -- 移除 `border`,作为默认样式 -- `columnNum` 重命名为 `columns` -- `GridItem` 使用方式修改为 `Grid.Item` +- square 属性的默认值调整为 true +- 新增主题变量 + - `--nutui-grid-border-width` 控制边框宽度 + - `--nutui-grid-border-radius` 控制圆角大小 + - -#### Layout - -#### Sticky - -- 移除 `top` 和 `bottom`, 重命名为 `threshold` +[//]: # '#### Layout' +[//]: # '#### Sticky' ### 导航组件 -#### Elevator - -- `acceptKey` 重命名为 `floorKey` -- `indexList` 重命名为 `list` -- `isSticky` 重命名为 `sticky` -- `onClickIndex` 重命名为 `onIndexClick` -- `onClickItem` 重命名为 `onItemClick` -- 新增`showKeys`,是否展示右侧导航 -- CSS 变量部分,对命名做了简化。 - -#### FixedNav - -- `unActiveText` 重命名为 `inactiveText` -- `navList` 重命名为 `list` -- `slotBtn` 重命名为 `content` -- `onSelected` 重命名为 `onSelect` -- 移除 `fixednavClass`,通过 `className` 实现 -- 移除 `slotList`,通过 `children` 实现 -- 该组件已废弃 `BEM` 规范,记得把 `__` 改为 `-` +[//]: # '#### Elevator' +[//]: # '#### FixedNav' #### Indicator -- type 属性的值调整为 `'anchor'` 或 `'slide'` -- color 属性的值增加 `'white'` - -#### Menu +- 新增 `type` 属性,可选值 `'anchor'` 或 `'slide'`,默认 `anchor` +- 新增 `color` 属性,可选值 `primary` | `'white'`,默认值 `primary` +- `total` 属性的默认值调整为 `2` -- 移除 `fontClassName` -- 移除 `iconClassPrefix` -- `closeOnClickOverlay` 重命名为 `closeOnOverlayClick` -- `titleIcon` 重命名为 `icon` -- `optionsIcon` 重命名为 `icon` -- 增加 `closeOnClickAway` +[//]: # '#### Menu' #### NavBar @@ -270,252 +131,46 @@ plugins: [ #### Pagination -- 新增 `lite` 模式,只展示页码,不支持事件交互 -- 新增 `defaultValue` 非受控值 -- `modelValue` 重命名为 `value`,受控值 -- `prevText` 重命名为 `prev`,类型修改为 `ReactNode` -- `nextText` 重命名为 `next`,类型修改为 `ReactNode` -- `forceEllipses` 重命令为 `ellipse` -- `showPageSize` 重命名为 `itemSize` -- `itemsPerpage` 重命名为 `pageSize` -- `totalitems` 重命名为 `total` -- `pageNodeRender` 重命名为 `itemRender` -- 移除 `pageCount`,通过 `total` 与 `pageSize` 组合实现 +- `itemRender` 属性类型调整为:`(page: any, index: number) => ReactNode` #### SideNavBar -- `offset` 重命名为 `indent` - -#### SideBar - -- 新增SideBar组件 -- 支持属性value,用于当前激活的`item`的key -- 支持属性defaultValue, 表示未设置value时,`item`的key的默认值 -- 支持属性contentDuration, 用于内容滚动动画时长 -- 支持属性sidebarDuration, 用于侧栏滚动动画时长 -- 支持属性onClick, 点击标签时触发 -- 支持属性onChange, 当前激活的标签改变时触发 - -#### Tabbar - -- `unactiveColor` 重命名为 `inactiveColor` -- `tabTitle` 重命名为 `title`,类型修改为 `ReactNode` -- `bottom` 重命名为 `fixed` -- `safeAreaInsetBottom` 重命名为 `safeArea` -- `visible` 重命名为 `defaultValue`,非受控 -- `activeVisible` 重命名为 `value`,受控 - -#### TabbarItem - -- 使用方式修改为 `Tabbar.Item` -- `icon` 类型改为 `ReactNode`,移除其他 `icon` 关联属性 -- 移除 `href`,通过 `onSwitch` 事件控制链接与路由跳转 -- 移除 `num`,支持传入所有 `Badge` Props -- 移除 `color`,使用父元素的 `activeColor`,保持同样的 `active` 状态 - -#### Tabs - -- 增加 `lite`、`card`、`button`、`divider` 模式。 -- 移除 `background`,通过 `className` 或 `style` 控制 -- 移除 `titleScroll`, 默认支持滚动 -- 移除 `ellipsis`,默认 `flex:1` -- 移除 `size`,通过 css 变量 `--nutui-tabs-titles-item-font-size` 实现 -- `animatedTime` 重命名为 `duration` -- `titleGutter` 重命名为 css 样式变量实现 -- `titleNode` 重命名为 `title` -- `color` 重命名为 `activeColor` -- `type` 重命名为 `activeType` -- `leftAlign` 重命名为 `align` -- `onClick` 类型改为 `(index: string | number) => void` -- `onChange` 类型改为 `(index: string | number) => void` -- 增加 defaultValue -- 增加 `activeType` 类型 `simple`,实现选项卡的简约选择,只修改字号和字重,不处理字色。 - -#### Tabs.Tabpane - -- `paneKey` 重命名为 `value` +- 注意:** 该组件即将被废弃。请使用 SideBar ** + +[//]: # '#### Tabbar' +[//]: # '#### TabbarItem' +[//]: # '#### Tabs' +[//]: # '#### Tabs.Tabpane' ### 数据录入 -#### Calendar - -- `poppable` 重命名为 `popup` -- `isAutoBackFill` 重命名为 `autoBackfill` -- `toDateAnimation` 重命名为 `scrollAnimation` -- `startText` 类型改为 `ReactNode` -- `endText` 类型改为 `ReactNode` -- `confirmText` 类型改为 `ReactNode` -- `onBtn` 重命名为 `renderHeaderButtons` -- `onDay` 重命名为 `renderDay` -- `onTopInfo` 重命名为 `renderDayTop` -- `onBottomInfo` 重命名为 `renderDayBottom` -- `onSelected` 重命名为 `onDayClick` -- `onChoose` 重命名为 `onConfirm` -- `onYearMonthChange` 重命名为 `onPageChange` -- 新增 `firstDayOfWeek`,支持按照周进行选择,指定周起止日,如0-6 - -#### Cascader - -- 新增 `defaultValue`,其中 `defaultValue` 用于非受控,原 `value` 用于受控。两者的类型都改为 `(number | string | undefined)[]` -- `checkedIcon` 重命名为 `activeIcon` -- `poppable` 重命名为 `popup` -- `lazyLoad` 重命名为 `onLoad`,当启动懒加载 `lazy` 时,动态加载数据 -- `convertConfig` 重命名为 `format`,配置转换规则 -- 合并 `textKey` `valueKey` `childrenKey` 三个属性为对象属性 `optionKey` -- 移除 `tabsColor`, 该属性为设置 `Tabs` 当前选中的 `tab` 的下划线色值,但该值最好与文字部分搭配使用,统一处理 CSS 变量。 - -#### Checkbox - -- 新增 `defaultChecked`,用于非受控,`checked` 用于受控 -- 新增 `value`,用于 group 模式 -- `textPosition` 重命名为 `labelPosition` -- `iconName` 重命名为 `icon`,类型为 `ReactNode` -- `iconAcitveName` 重命名为 `activeIcon` -- `iconIndeterminateName` 重命名为 `iconIndeterminateIcon` -- 移除 `iconSize` -- 部分 className 命名变更,废弃 `nutui-checkbox__xx` 命名方式,直接使用 `nutui-checkbox-xx`,并对选中状态命名修订为 `nutui-checkbox-icon-checked` -- 增加半选的禁用状态 - -#### Checkbox.Group - -- 新增 `defaultValue`,用于非受控,`value` 用于受控 -- `textPosition` 重命名为 `labelPosition` -- `toggleAll` 重命名为 `toggle` -- `toggleReverse` 重命名为 `reverse` -- 部分 className 命名变更,废弃 `nutui-checkbox__xx` 命名方式,直接使用 `nutui-checkbox-xx`,并对选中状态命名修订为 `nutui-checkbox-icon-checked` - -#### DatePicker - -- `modelValue` 重命名为 `value`,并增加 `defaultValue` -- `isShowChinese` 重命名为 `showChinese` -- `minDate` 重命名为 `startDate` -- `maxDate` 重命名为 `endDate` -- `onConfirmDatePicker` 重命名为 `onConfirm` -- `onCloseDatePicker` 重命名为 `onClose` -- 因为依赖组件`Picker`的变更,方法 `onConfirmDatePicker`、`onChange`的参数进行了调整,从`(selectedValue, selectedOptions)` 改为 `(selectedOptions, selectedValue)`。 - -#### Form - -- 增加 `footer`,类型为 `ReactNode`,用于表单底部区域,通常用于设置提交、重置按钮 -- 增加 `initialValues`,用于设置表单初始值,同时用于表单的重置 -- 增加 `name` 属性 - -#### Form.Item - -- 移除 `labelWidth`, 通过 `--nutui-form-item-label-width` 控制宽度 -- 增加 `required`,用于必选样式控制 -- 增加 `trigger`,用于设置数据更新的时机 -- 增加 `valuePropName`,用于收集子组件受控的属性映射 -- 增加 `getValueFromEvent`,用于在收集数据中进行数据转换 -- 增加 `onclick` 用于收集子组件的 `ref` - -#### Input - -- 新增 `plain` 属性,标记为 纯文本型;该值默认为false,标记为 container 容器型; -- 区分了 readonly 和 disabled 的样式; -- 删除一些样式变量,统一到由通用变量控制,如`$input-color`、`$input-disabled-color` - -#### InputNumber - -- 增加 `allowEmpty`, 用于允许内容是否为空 -- 新增 `defaultValue`,用于非受控,`value` 用于受控 -- `decimalPlaces` 重命名为 `digits` -- `isAsync` 重命名为 `async` -- 移除 `inputWidth`, 通过`--nutui-inputnumber-input-width`控制输入框的宽度 -- 移除 `buttonSize`, 通过`–nutui-inputnumber-button-width` 和 `–nutui-inputnumber-button-height`控制按钮的宽度和高度 -- taro 新增 `formatter` 属性, 用于指定输入框展示值的格式 -- 移除 `errorMessage` -- 移除 `showWordLimit` -- `autofocus` 重命名为 `autoFocus` -- `type="textarea"` 建议改为使用 `TextArea` 组件实现 - -#### NumberKeyboard - -- `randomKeys` 重命名为 `random` -- `customKey` 重命名为 `custom` -- `title` 类型变更为 `ReactNode` -- 新增 `onConfirm` 事件 -- 移除 `popClass` 定义,默认支持透传 `Popup` 属性 - -#### Picker - -- `isVisible` 重命名为 `visible` -- `listData` 重命名为 `options` -- `defaultValueData` 重命名为 `defaultValue` -- 增加受控 `value` -- `swipeDuration` 重命名为 `duration` -- `onCloseUpdate` 重命名为 `afterClose` -- 方法 `onConfirm`、`onClose`、`afterClose`、`onChange`的参数进行了调整,从`(selectedValue, selectedOptions)` 改为 `(selectedOptions, selectedValue)`。 - -#### Radio - -- 移除 `iconSize`,可通过 Icon 的 css 变量设置 -- `iconName` 重命名为 `icon`,类型修改为 `ReactNode` -- 增加 `labelPosition`,用于设置 `label` 的位置 -- 增加 `checked` 和 `defaultChecked` ,用于受控和非受控 -- `onChange` 类型修改为 `(checked: boolean) => void` -- 部分 className 命名变更,废弃 `nutui-radio__xx` 命名方式,直接使用 `nutui-radio-xx`,并对选中状态命名修订为 `nutui-radio-icon-checked` - -### Radio.Group - -- `textPosition` 重命名为 `labelPosition` -- 增加 `defaultValue` ,用于非受控 -- `onChange` 类型修改为 `(value: string| number) => void` -- 部分 className 命名变更,废弃 `nutui-radio__xx` 命名方式,直接使用 `nutui-radio-xx`,并对选中状态命名修订为 `nutui-radio-icon-checked` - -#### Range - -- `maxDesc` 重命名为 `maxDescription`,类型改为 `ReactNode` -- `minDesc` 重命名为 `minDescription`,类型改为 `ReactNode` -- `curValueDesc` 重命名为 `currentDescription`,类型改为 `(value) => ReactNode` -- 移除 `hiddenRange`,通过 `max/minDescription` 传 `null` 实现 -- 移除 `hiddenTag`,通过 `currentDescription` 传 `null` 实现 -- 移除 `activeColor`、`inactiveColor`、`buttonColor`,通过 `css` 变量实现 -- `onDragStart` 重命名为 `onStart` -- `onDragEnd` 重命名为 `onEnd` -- `modelValue` 重命为 `value`,增加 `defaultValue` 非受控方式 +[//]: # '#### Calendar' +[//]: # '#### Cascader' +[//]: # '#### Checkbox' +[//]: # '#### Checkbox.Group' +[//]: # '#### DatePicker' +[//]: # '#### Form' +[//]: # '#### Form.Item' +[//]: # '#### Input' +[//]: # '#### InputNumber' +[//]: # '#### NumberKeyboard' +[//]: # '#### Picker' +[//]: # '#### Radio' +[//]: # '### Radio.Group' +[//]: # '#### Range' #### Rate -- `minimizeValue` 重命名为 `min` -- `readonly` 重命名为 `readOnly` -- 移除 `spacing`,通过 css 样式变量实现 -- 移除 `activeColor`、`voidColor`、`iconSize`,通过 `checkedIcon`、`uncheckedIcon` 实现 -- 增加受控 `value` 与非受控 `defaultValue`,移除 `modelValue` - -#### SearchBar - -- `onClickInput` 重命名为 `onInputClick` -- 移除 `clearSize`,样式默认 -- 移除 `background`,使用 CSS 变量 `--nutui-searchbar-background` 实现 -- 移除 `inputBackground`,使用 CSS 变量 `--nutui-searchbar-input-background` 实现 -- 移除 `align`,使用 CSS 变量 `--nutui-searchbar-input-text-align` -- 新增 `left` 和 `right`,为 `ReactNode` 节点,可自定义内容 -- 移除 `leftoutIcon` 和 `label`,使用 `left` 实现 -- 移除 `rightoutIcon` 和 `actionText`,使用 `right` 实现 -- 移除 `leftinIcon`,使用 `leftIn` 实现 -- 移除 `rightinIcon`,使用 `rightIn` 实现,同时兼顾和 clearIcon 的交互,当设置rightIn时,默认展示 rightIn,当触发输入后,展示 clearIcon。同时增加 `backable` 来标记是否展示左侧返回Icon -- 移除 `onCancel`,使用 `right` 来实现事件处理 -- 移除 `onClickLeftinIcon`,用户可使用 `left` 来实现事件处理 -- 移除 `onClickLeftoutIcon`,用户可使用 `left` 来实现事件处理 -- 移除 `onClickRightinIcon`,用户可使用 `right` 来实现事件处理 -- 移除 `onClickRightoutIcon`,用户可使用 `right` 来实现事件处理 - -#### ShortPassword - -- `desc` 重命名为 `description` -- `noButton` 重命名为 `hideFooter` -- `onOk` 重命名为 `onConfirm` -- `errorMsg` 重命名为 `error` -- 移除 `closeOnClickOverlay`,默认支持透传 Popup 属性 -- `title`、`description`、`tips`、`error` 类型修改为 `ReactNode` -- `modelValue` 重命名为 `value`,受控模式 -- 新增 `onFoucs` 事件 +- 新增 size 属性,控制图标的大小 +- 新增 showScore 属性,展示评分文案 + +[//]: # '#### SearchBar' +[//]: # '#### ShortPassword' #### TextArea -- 新增 `plain` 属性,标记为 纯文本型;该值默认为false,标记为 container 容器型; -- 新增 `status` 属性,值为 `default` | `error`,可定义输入框的状态; +- 新增 `plain` 属性,标记为 纯文本型;该值默认为false,标记为 container 容器型 +- 新增 `status` 属性,值为 `default` | `error`,可定义输入框的状态 - 删掉一些可使用基础样式变量,并且建议使用基础样式变量的样式变量,比如 `$textarea-font` `$textarea-limit-color` `$textarea-disabled-color` #### Uploader @@ -532,26 +187,12 @@ plugins: [ ### 操作反馈 -#### ActionSheet - -- `title`,类型变更为 `ReactNode` -- `description`,类型变更为 `ReactNode` -- `cancelTxt`,重命名为 `cancelText`,类型变更为 `ReactNode` -- `menuItems` 重命名为 `options` -- `chooseTagValue` 重命名为 `value` -- `onChoose` 重命名为 `onSelect` -- 增加 `options` 的定义 - - `color` 重命名为 `danger` - - `name`,列表项的标题key - - `description`,列表项的描述key - - `danger`,列表项中提醒用户重点关注的操作 - - `disabled`,列表项中禁用项 +[//]: # '#### ActionSheet' #### BackTop -- 使用 `HoverButton` 重构 `BackTop` -- 新增 `icon` 字段,可直接修改图标 -- 继续支持自定义节点 +- Taro + - 提供鸿蒙端能力,增加 scrollRes 属性 #### Dialog @@ -559,304 +200,74 @@ plugins: [ - 当只有一个主操作按钮时,主操作按钮样式撑开; - 增加了底部icon的大小设置的样式变量;修改右侧按钮的默认值为 16 px; -#### Drag +[//]: # '#### Drag' #### InfiniteLoading -- `useCapture` 重命名为 `capture` -- `onScrollChange` 重命名为 `onScroll` -- `isOpenRefresh` 重命名为 `pullRefresh` -- `pullTxt` 重命名为 `pullingText`,类型变更为 `ReactNode` -- `loadTxt` 重命名为 `loadingText`,类型变更为 `ReactNode` -- `containerId` 重命名为 `target` -- 修订类名如 `top-box`、`bottom-box` 为 `nut-infinite-top-tips`、`nut-infinite-bottom-tips` - -#### Notify +- `target` 属性获取监听的目标元素 -- 移除 `color` ,通过css变量`--nutui-notify-text-color`实现 -- 移除`background`,通过css变量`--nutui-notify-base-background-color`实现 -- `onClosed` 重命名为 `onClose` - -#### PullToRefresh - -#### Swipe - -- 移除 `leftWidth` ,通过 `leftAction` 实现 -- 移除 `rightWidth` ,通过 `rightAction` 实现 +[//]: # '#### Notify' +[//]: # '#### PullToRefresh' +[//]: # '#### Swipe' #### Switch -- 新增 `defaultChecked`,用于非受控,`checked` 用于受控 -- 移除 `isAsync`,通过 `checked`实现 -- 移除 `activeColor` ,通过css变量`--nutui-switch-open-background-color`实现 -- 移除 `inactiveColor`,通过css变量`--nutui-switch-close-background-color`实现 - `activeText` 属性类型更改为`ReactNode` - `inactiveText` 属性类型更改为 `ReactNode` -#### Toast - -- 移除H5版本 `id` -- 移除 `center`和 `bottom`,通过 `position` 实现 -- 移除 `bgColor`,通过 css 变量实现 -- 移除 `customClass`,通过 `className` 实现 -- 移除 `cover` 和 `coverColor` ,通过css变量实现 -- 移除 `loadingRotate`,旋转状态通过 `iconFont`实现 -- 移除 `textAlignCenter`,通过css变量实现 -- 修改 `closeOnClickOverlay` 为 `closeOnOverlayClick` ,语义不变,是否在点击遮罩层后关闭提示 -- 新增 `lockScroll` ,用于背景是否锁定,默认值为 `false` +[//]: # '#### Toast' ### 展示组件 -#### Animate - -- `type` 属性类型更改为 `AnimateType` ,具体值详见文档 -- `action` 属性类型更改为 `initial \| click` - -#### AnimatingNumbers - -- `maxLen` 重命名为 `length` -- `endNumber` 重命名为 `value`,类型修改为 `string|number` -- `delaySpeed` 重命名为 `delay` -- `easeSpeed` 重命名为 `duration` - -#### Audio - -- `url` 重命名为 `src` -- `autoplay` 重命名为 `autoPlay` -- `onFastBack` 重命名为 `onBack` -- `onPlayEnd` 重命名为 `onEnd` - -#### Avatar - -- `url` 重命名为 `src` -- `onActiveAvatar` 重命名为 `onClick` -- 新增 `fit` 属性,用于图片填充模式 -- 移除 `iconSize`,可通过 icon 属性传入自定义 icon 或借助 CSS Variables 修改 icon 大小 - -#### AvatarGroup - -- AvatarGroup `maxCount` 重命名为 `max` -- AvatarGroup `span` 重命名为 `gap` -- AvatarGroup `zIndex` 重命名为 `level` +[//]: # '#### Animate' +[//]: # '#### AnimatingNumbers' +[//]: # '#### Audio' +[//]: # '#### Avatar' +[//]: # '#### AvatarGroup' #### Badge - 新增 `size` 属性,dot 尺寸,当 dot 等于 `true` 时生效 -- 移除 `徽标背景颜色`,通过css变量`--nutui-badge-background-color`实现 +- 移除 `color`属性(`徽标背景颜色`),通过css变量`--nutui-badge-background-color`实现 -#### CircleProgress - -- `progress` 重命名为 `percent` -- `circleColor` 重命名为 `color` -- `pathColor` 重命名为 `background` - -#### Collapse - -- 新增 `defaultActiveName` 非受控 -- `activeName` 改为受控方式 -- `icon` 重命名为 `expandIcon`,类型修改为 `ReactNode` -- `onChange` 参数变更为 `activeName, name, status` -- 新增一种样式,尝试修改 `--nutui-collapse-item-border-bottom` 和 `-nutui-collapse-item-header-border-bottom`,可查看 - -#### CollapseItem - -- 使用方式调整为 `Collapse.Item` -- subTitle 重命名为 extra,类型修改为 `ReactNode` -- 新增 `expnandIcon`,优先级高于父组件对应值 -- 新增 `rotate`,优先级高于父组件对应值 +[//]: # '#### CircleProgress' +[//]: # '#### Collapse' +[//]: # '#### CollapseItem' #### CountDown -- 新增 `remainingTime`,支持剩余毫秒时间倒计时。 - -#### Ellipsis +- 新增 `type`,设置变体类型 -- 新增 `className` 和 `style` 属性的支持 -- 优化 H5 的代码,去掉 `useEffect` 渲染改用 `useLayoutEffect` +[//]: # '#### Ellipsis' #### Empty -- 新增 `status` 属性,用于默认图片错误类型 -- 新增 `size` 属性,用于区分全屏与半屏状态下图片的不同大小 -- 新增 `title` 属性,用于展示提示的标题部分 -- 新增 `actions` 属性,用于展示提示的操作部分,支持1个或2个操作 -- `image` 属性类型更改为 `ReactNode` -- 新增 `title`、`size`、`actions` 属性,支持标题的设置、图片大小的设置、可能的操作设置,操作设置默认以`Button`实现。 - -#### ImagePreview - -- `show` 重命名为 `visible` -- `autoplay` 重命名为 `autoPlay` -- `initNo` 重命名为 `defaultValue`,同时增加 `value`,为受控 -- `paginationVisible` 重命名为 `indicator` -- `paginationColor` 重命名为 `indicatorColor` -- `contentClose` 重命名为 `closeOnContentClick` -- 在 `Taro` 下支持视频 - -#### NoticeBar - -- `direction` 的可选值从 `across` 重命名为 `horizontal` -- `text` 重命名为 `content` -- `closeMode` 重命名为 `closeable` -- `leftIcon` 类型扩充,支持 `ReactNode` -- `rightIcon` 类型扩充,支持 `ReactNode` -- `color` 移除,使用 CSS 变量,之前已支持 -- `background` 移除,使用 CSS 变量,之前已支持 -- `wrapable` 重命名为 `wrap` -- `standTime` 重命名为 `duration` -- `onClickItem` 重命名为 `onItemClick` -- `complexAm` 废弃 - -#### Popover - -- 移除 `theme` 属性,可以通过css变量 `--nutui-brand-color` 控制暗黑模式 -- 新增 `showArrow` 属性,用于是否显示小箭头 -- 新增 `closeOnActionClick` 属性,用于是否在点击选项后关闭 -- 新增 `closeOnOutsideClick` 属性,用于是否在点击外部元素后关闭菜单 -- 新增 `targetId` 属性,用于自定义目标元素 id -- 新增 `onOpen` 属性,用于点击菜单时触发 -- 新增 `onClose` 属性,用于关闭菜单时触发 -- 新增 `action` 属性,用于为对应的选项添加方法 -- `onChoose` 重命名为 `onSelect` -- 继承Popup组件的 `overlayStyle` 、`overlayClassName` 、`overlay` 、`closeOnOverlayClick` 属性。 +- 移除 `--nutui-empty-title-margin-top` 主题变量 +- 移除 `--nutui-empty-description-margin-top` 主题变量 + +[//]: # '#### ImagePreview' +[//]: # '#### NoticeBar' +[//]: # '#### Popover' #### Price - 修改 `size`,增加 'xlarge' 尺寸 - 新增 `color`, 价格类型 -#### Progress - -- `percentage` 重命名为 `percent`,受控 -- 移除 `isShowPercentage`,可以自定义传入文案 -- 移除 `textWidth`,可以自定义传入内容的宽度 -- `strokeColor` 重命名为 `color` -- `fillColor` 重命名为 `background` -- 移除 `size`,通过 `strokeWidth`、`progress-height` css 变量实现尺寸自定义 -- `status` 重命名为 `animated`,表示是否展示动画效果 -- 移除 `textBackground`,通过 css 实现 -- 移除 `textColor`,通过 css 实现 -- 移除 `textInside`,仅保留内显功能 -- 移除 `textType、icon`,通过 `children` 传入自定义 `ReactNode`,不再区分类型 -- 新增 `lazy` 属性,支持每次进入可视区时展示进度条动画 -- 新增 `delay` 属性,表示延迟数据加载时长 - -#### Skeleton - -- `loading` 重命名为 `visible` -- `row` 重命名为 `rows` -- 移除 `width`,通过 css 变量 `skeleton-line-width` 实现 -- 移除 `height`,通过 css 变量 `skeleton-line-height` 实现 -- 移除 `round`,通过 css 变量 `skeleton-line-border-radius` 实现 - -#### Steps - -- `current` 重命名为 `value` -- `onClickStep` 重命名为 `onStepClick` -- `progressDot` 重命名为 `dot` - -#### Step - -- 移除 `iconColor`,可通过 `icon` 属性传入自定义 icon 或借助 CSS Variables 修改 icon 颜色 -- 移除 `size`,可通过 icon 属性传入自定义 icon 或借助 CSS Variables 修改 icon 大小 -- 移除 `renderContent` ,可通过 `description` 实现 -- `title` 类型修改为 `ReactNode` -- `content` 重命名为 `description`,类型改为 `ReactNode` -- `icon` 类型修改为 `ReactNode` -- `activeIndex` 重命名为 `value` - -#### Swiper - -- h5 - - 移除 `paginationColor`,通过 `indicator` 的 CSS 变量控制 - - 移除 `paginationBgColor`,通过 `indicator` 的 CSS 变量控制 - - 移除 `pageContent`,通过 indicator 实现 - - `autoplay` 重命名为 `autoplay` - - `initPage` 重命名为 `defaultValue` - - `paginationVisible` 重命名为 `indicator`,类型改为`ReactNode` - - `isPreventDefault` 重命名为 `preventDefault` - - `isStopPropagation` 重命名为 `stopPropagation` - - `isCenter` 重命名为 `center` -- taro - - 通过封装 Taro 的 `Swiper` 和 `SwiperItem` 实现,支持的属性可参考 Taro Swiper 文档。 - -#### Table - -- `onSorter` 重命名为 `onSort` -- 合并 `summary` 与 `noData` 的样式处理 - -#### Tag - -- `color` 重命名为 `background` -- `textColor` 重命名为 `color` - -#### TrendArrow - -- `rate` 重命名为 `value` -- `showSign` 重命名为 `symbol` -- `showZero` 重命名为 `zero` -- `arrowLeft` 重命名为 `left` -- `syncTextColor` 重命名为 `sync` -- `textColor` 重命名为 `color` -- `upIconName` 重命名为 `riseIcon`,类型修改为 `React.Node` -- `downIconName` 重命名为 `dropIcon`,类型修改为 `React.Node` -- 移除 `iconSize`,通过`riseIcon`、`dropIcon`自定义传入icon大小 -- 新增 `size`,star 尺寸, 默认值 `normal` 为 `12px` -- 新增 `showScore`, 展示评分 - -#### Video - -- 在 `Taro` 下新增video的适配 - -#### VirtualList - -- `sourceData` 重命名为 `list` -- `conatinerSize` 重命名为 `containerHeight` -- `itemSize` 重命名为 `itemHeight` -- `itemEqualSize` 重命名为 `itemEqual` -- `horizontal` 修改为 `direction`,默认值 `vertical`,可选值 `horizontal` - -#### WaterMark - -- `fontColor` 重命名为 `color` - -### 特色组件 - -#### Address - -- 该组件的 `custom` 改用 `Cascader` 组件重写;`custom2`也将使用 `Cascader` 完成,在 `Cascader` 中支持 `Elevator`,开发中。所以会废弃 `province`、`city`、`country`、`town` 这些属性,同时支持 `Cascader` 的属性。 -- `modelValue` 重命名为 `visible` -- `modelSelect` 重命名为 `defaultValue` -- `onSelected` 重命名为 `onSelect` -- `existAddress` 重命名为 `existList` -- `selectedIcon` 重命名为 `selectIcon` -- `closeBtnIcon` 重命名为 `closeIcon` -- `backBtnIcon` 重命名为 `backIcon` -- `isShowCustomAddress` 重命名为 `custom`,用于已有地址列表与自定义列表的切换,修改默认为值 `false` -- `customAndExistTitle` 废弃,与 `custom` 合并,当 `custom` 为 true 时,为默认文案,设置为某字符串时,展示字符串。 -- `customAddressTitle`、`existAddressTitle` 重命名为 `title`,不再区分状态,可通过onSwitch修改title -- 精简布局和样式 - -#### Barrage - -- `barrageList` 重命名为 `list` -- `frequency` 重命名为 `interval` -- `speeds` 重命名为 `duration` -- `top` 重命名为 `gapY` - -#### Card - -#### Signature - -- `type` 类型修改为 `png|jpg` -- `unSupportTpl` 重命名为 `unsupported`,类型修改为 `ReactNode` -- 新增 `confirm`和`clear` ref 的方法,移除组件内部 `button`元素,通过自定义按钮元素,设置元素点击事件结合ref实现,参考文档demo示例 - -#### TimeSelect - -- 移除 `height`,通过 `style` 设置高度 -- `title` 类型修改为 `ReactNode` -- `onPannelChange` 重命名为 `onDateChange` -- 移除 `dates`、`times`,合并为 `options`,重新设计了数据结构 -- 增加 `optionKey` 用于自定义数据中的关键字 -- 移除 `currentKey`,新增 `defaultValue` 用于设置默认选项,支持时间选择 +[//]: # '#### Progress' +[//]: # '#### Skeleton' +[//]: # '#### Steps' +[//]: # '#### Step' +[//]: # '#### Swiper' +[//]: # '#### Table' +[//]: # '#### Tag' +[//]: # '#### TrendArrow' +[//]: # '#### Video' +[//]: # '#### VirtualList' +[//]: # '#### WaterMark' +[//]: # '### 特色组件' +[//]: # '#### Address' +[//]: # '#### Barrage' +[//]: # '#### Card' +[//]: # '#### Signature' +[//]: # '#### TimeSelect' diff --git a/src/config.json b/src/config.json index 70976e92f3..ac1ac996d7 100644 --- a/src/config.json +++ b/src/config.json @@ -688,8 +688,8 @@ "sort": 10, "show": true, "taro": true, - "author": "dsj", - "dd": false + "dd": false, + "author": "songsong" }, { "version": "3.0.0", @@ -1456,4 +1456,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/packages/backtop/doc.taro.md b/src/packages/backtop/doc.taro.md index dec6816459..bfa5ecd0ea 100644 --- a/src/packages/backtop/doc.taro.md +++ b/src/packages/backtop/doc.taro.md @@ -61,7 +61,7 @@ import { BackTop } from '@nutui/nutui-react-taro' | threshold | 页面垂直滚动多高后出现 | `number` | `200` | | zIndex | 设置组件页面层级 | `number` | `900` | | duration | 设置动画持续时间,为 0 时表示无动画 | `number` | `1000` | -| scrollRes | 被监听容器滚动时的回调参数,主要用于 rn、鸿蒙端 | `PageScrollObejct` | `-` | +| scrollRes | 被监听容器滚动时的回调参数 | `PageScrollObejct` | `-` | | onClick | 按钮点击时触发事件 | `(event: MouseEvent) => void` | `-` | ## 主题定制 diff --git a/src/packages/calendar/demos/h5/demo6.tsx b/src/packages/calendar/demos/h5/demo6.tsx index 37ae07619b..2e0d5486dd 100644 --- a/src/packages/calendar/demos/h5/demo6.tsx +++ b/src/packages/calendar/demos/h5/demo6.tsx @@ -1,5 +1,12 @@ import React, { useRef, useState } from 'react' -import { Cell, Calendar, DatePicker, CalendarDay } from '@nutui/nutui-react' +import { + Cell, + Calendar, + DatePicker, + CalendarDay, + PickerValue, + PickerOptions, +} from '@nutui/nutui-react' const padZero = (num: number | string, targetLength = 2) => { let str = `${num}` @@ -32,14 +39,18 @@ const Demo6 = () => { const dateArr = [...[chooseData[0][3], chooseData[1][3]]] setDate([...dateArr]) } - const confirm = (values: (string | number)[], options: any[]) => { + const confirm = (values: PickerValue[], options: PickerOptions) => { if (desc.current === 1) { setDesc1( - options.map((option) => padZero(parseInt(option.text))).join(':') + options + .map((option) => padZero(parseInt(option.label as string))) + .join(':') ) } else { setDesc2( - options.map((option) => padZero(parseInt(option.text))).join(':') + options + .map((option) => padZero(parseInt(option.label as string))) + .join(':') ) } } diff --git a/src/packages/calendar/demos/taro/demo6.tsx b/src/packages/calendar/demos/taro/demo6.tsx index 93e78b6fff..1e9172218d 100644 --- a/src/packages/calendar/demos/taro/demo6.tsx +++ b/src/packages/calendar/demos/taro/demo6.tsx @@ -4,6 +4,8 @@ import { Calendar, DatePicker, CalendarDay, + PickerValue, + PickerOptions, } from '@nutui/nutui-react-taro' import { View } from '@tarojs/components' @@ -33,14 +35,18 @@ const Demo6 = () => { const dateArr = [...[chooseData[0][3], chooseData[1][3]]] setDate([...dateArr]) } - const confirm = (values: (string | number)[], options: any[]) => { + const confirm = (values: PickerValue[], options: PickerOptions) => { if (desc.current === 1) { setDesc1( - options.map((option) => padZero(parseInt(option.text))).join(':') + options + .map((option) => padZero(parseInt(option.label as string))) + .join(':') ) } else { setDesc2( - options.map((option) => padZero(parseInt(option.text))).join(':') + options + .map((option) => padZero(parseInt(option.label as string))) + .join(':') ) } } diff --git a/src/packages/datepicker/__test__/datepicker.spec.tsx b/src/packages/datepicker/__test__/datepicker.spec.tsx index 9952adc4b2..08dee3ba9c 100644 --- a/src/packages/datepicker/__test__/datepicker.spec.tsx +++ b/src/packages/datepicker/__test__/datepicker.spec.tsx @@ -21,7 +21,7 @@ test('Show Chinese', async () => { fireEvent.click(confirmBtn) await waitFor(() => { expect( - confirm.mock.calls[0][0].map((option: any) => option.text).join('') + confirm.mock.calls[0][0].map((option: any) => option.label).join('') ).toEqual(`${currentYear - 10}年01月01日`) }) }) @@ -40,13 +40,9 @@ test('Min date & Max date', async () => { /> ) - const columns = container.querySelectorAll('.nut-picker-list')[0] - const lists = columns.querySelectorAll('.nut-picker-roller-item-title') - const years = ['2020', '2021', '2022'] + const columns = container.querySelectorAll('.nut-pickerview-list') + const lists = columns[0].querySelectorAll('.nut-pickerview-roller-item-tiled') expect(lists.length).toBe(3) - lists.forEach((list, i) => { - expect(list.textContent).toEqual(years[i]) - }) rerender( { const formatter = (type: string, option: any) => { switch (type) { case 'year': - option.text += '' + option.label += '' break case 'month': - option.text += 'M' + option.label += 'M' break case 'day': - option.text += 'D' + option.label += 'D' break case 'hour': - option.text += 'H' + option.label += 'H' break case 'minute': - option.text += 'M' + option.label += 'M' break default: - option.text += '' + option.label += '' } return option } @@ -148,7 +144,7 @@ test('should pick defaultValue', async () => { fireEvent.click(confirmBtn) await waitFor(() => expect( - confirm.mock.calls[0][0].map((option: any) => option.text).join('') + confirm.mock.calls[0][0].map((option: any) => option.label).join('') ).toEqual('20210301') ) }) @@ -166,8 +162,8 @@ test('Increment step setting', async () => { /> ) - const columns = container.querySelectorAll('.nut-picker-list')[1] - const lists = columns.querySelectorAll('.nut-picker-roller-item') + const columns = container.querySelectorAll('.nut-pickerview-list') + const lists = columns[1].querySelectorAll('.nut-pickerview-roller-item') expect(lists.length).toBe(12) }) @@ -189,7 +185,7 @@ test('Filter Time', async () => { /> ) - const columns = container.querySelectorAll('.nut-picker-list')[3] - const lists = columns.querySelectorAll('.nut-picker-roller-item') + const columns = container.querySelectorAll('.nut-pickerview-list') + const lists = columns[3].querySelectorAll('.nut-pickerview-roller-item') expect(lists.length).toBe(4) }) diff --git a/src/packages/datepicker/datepicker.taro.tsx b/src/packages/datepicker/datepicker.taro.tsx index afdcf64d92..4cf3c985eb 100644 --- a/src/packages/datepicker/datepicker.taro.tsx +++ b/src/packages/datepicker/datepicker.taro.tsx @@ -5,7 +5,7 @@ import React, { useImperativeHandle, } from 'react' import { View } from '@tarojs/components' -import Picker, { PickerOption } from '@/packages/picker/index.taro' +import Picker from '@/packages/picker/index.taro' import { useConfig } from '@/packages/configprovider/index.taro' import { usePropsValue } from '@/hooks/use-props-value' import { ComponentDefaults } from '@/utils/typings' @@ -17,8 +17,9 @@ import { getDatePartValue, handlePickerValueChange, } from './utils' -import { DatePickerActions, DatePickerRef } from './types' import { DatePickerProps } from './types.taro' +import { DatePickerActions, DatePickerRef } from './types' +import { PickerOptions, PickerValue } from '@/packages/pickerview/types' const currentYear = new Date().getFullYear() @@ -76,8 +77,8 @@ const InternalPicker: ForwardRefRenderFunction< seconds: lang.seconds, } - const [pickerValue, setPickerValue] = useState<(string | number)[]>([]) - const [pickerOptions, setPickerOptions] = useState([]) + const [pickerValue, setPickerValue] = useState([]) + const [pickerOptions, setPickerOptions] = useState([]) const [selectedDate, setSelectedDate] = usePropsValue({ value: props.value && formatValue(props.value, startDate, endDate), @@ -107,7 +108,7 @@ const InternalPicker: ForwardRefRenderFunction< const handleDateComparison = ( newDate: Date | null, - selectedOptions: PickerOption[], + selectedOptions: PickerOptions, index: number ) => { const isEqual = new Date(innerDate)?.getTime() === newDate?.getTime() @@ -146,10 +147,7 @@ const InternalPicker: ForwardRefRenderFunction< onClose?.() } - const handleConfirm = ( - options: PickerOption[], - value: (string | number)[] - ) => { + const handleConfirm = (options: PickerOptions, value: PickerValue[]) => { handlePickerValueChange( options, value, @@ -162,8 +160,8 @@ const InternalPicker: ForwardRefRenderFunction< } const handleChange = ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[], + selectedOptions: PickerOptions, + selectedValue: PickerValue[], index: number ) => { innerVisible && @@ -177,7 +175,7 @@ const InternalPicker: ForwardRefRenderFunction< ) } - const generatePickerColumns = (): PickerOption[][] => { + const generatePickerColumns = (): PickerOptions[] => { const dateRanges = generateDatePickerRanges( type, innerDate, @@ -236,11 +234,9 @@ const InternalPicker: ForwardRefRenderFunction< onClose={handleClose} onCancel={handleCancel} onConfirm={handleConfirm} - onChange={( - options: PickerOption[], - value: (string | number)[], - index: number - ) => handleChange(options, value, index)} + onChange={({ value, index, selectedOptions }) => { + handleChange(selectedOptions, value, index) + }} threeDimensional={threeDimensional} /> )} diff --git a/src/packages/datepicker/datepicker.tsx b/src/packages/datepicker/datepicker.tsx index 42eb940025..3881dc8122 100644 --- a/src/packages/datepicker/datepicker.tsx +++ b/src/packages/datepicker/datepicker.tsx @@ -4,7 +4,7 @@ import React, { ForwardRefRenderFunction, useImperativeHandle, } from 'react' -import Picker, { PickerOption } from '@/packages/picker' +import Picker from '@/packages/picker' import { useConfig } from '@/packages/configprovider' import { usePropsValue } from '@/hooks/use-props-value' import { ComponentDefaults } from '@/utils/typings' @@ -17,6 +17,7 @@ import { handlePickerValueChange, } from './utils' import { DatePickerActions, DatePickerProps, DatePickerRef } from './types' +import { PickerOptions, PickerValue } from '@/packages/pickerview/types' const currentYear = new Date().getFullYear() @@ -74,8 +75,8 @@ const InternalPicker: ForwardRefRenderFunction< seconds: lang.seconds, } - const [pickerValue, setPickerValue] = useState<(string | number)[]>([]) - const [pickerOptions, setPickerOptions] = useState([]) + const [pickerValue, setPickerValue] = useState([]) + const [pickerOptions, setPickerOptions] = useState([]) const [selectedDate, setSelectedDate] = usePropsValue({ value: props.value && formatValue(props.value, startDate, endDate), @@ -105,7 +106,7 @@ const InternalPicker: ForwardRefRenderFunction< const handleDateComparison = ( newDate: Date | null, - selectedOptions: PickerOption[], + selectedOptions: PickerOptions, index: number ) => { const isEqual = new Date(innerDate)?.getTime() === newDate?.getTime() @@ -144,10 +145,7 @@ const InternalPicker: ForwardRefRenderFunction< onClose?.() } - const handleConfirm = ( - options: PickerOption[], - value: (string | number)[] - ) => { + const handleConfirm = (options: PickerOptions, value: PickerValue[]) => { handlePickerValueChange( options, value, @@ -160,8 +158,8 @@ const InternalPicker: ForwardRefRenderFunction< } const handleChange = ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[], + selectedOptions: PickerOptions, + selectedValue: PickerValue[], index: number ) => { innerVisible && @@ -175,7 +173,7 @@ const InternalPicker: ForwardRefRenderFunction< ) } - const generatePickerColumns = (): PickerOption[][] => { + const generatePickerColumns = (): PickerOptions[] => { const dateRanges = generateDatePickerRanges( type, innerDate, @@ -234,11 +232,9 @@ const InternalPicker: ForwardRefRenderFunction< onClose={handleClose} onCancel={handleCancel} onConfirm={handleConfirm} - onChange={( - options: PickerOption[], - value: (string | number)[], - index: number - ) => handleChange(options, value, index)} + onChange={({ value, index, selectedOptions }) => { + handleChange(selectedOptions, value, index) + }} threeDimensional={threeDimensional} /> )} diff --git a/src/packages/datepicker/demos/h5/demo1.tsx b/src/packages/datepicker/demos/h5/demo1.tsx index ff87453056..82b73fcd4e 100644 --- a/src/packages/datepicker/demos/h5/demo1.tsx +++ b/src/packages/datepicker/demos/h5/demo1.tsx @@ -1,5 +1,10 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react' +import { + DatePicker, + Cell, + PickerValue, + PickerOptions, +} from '@nutui/nutui-react' import isEqual from 'react-fast-compare' const useDatePicker = (initialDate: Date) => { @@ -31,17 +36,17 @@ const Demo1 = () => { const handleConfirm = (setDesc: (desc: string) => void, setValue?: (value: string) => void) => - (options: PickerOption[], values: (string | number)[]) => { + (options: PickerOptions, values: PickerValue[]) => { if (setValue) { if (isEqual(values, ['2026', '02', '21'])) { setValue('2026/03/22') setDesc('2026年03月22日') } else { setValue(values.join('/')) - setDesc(options.map((option) => option.text).join('')) + setDesc(options.map((option) => option.label).join('')) } } else { - setDesc(options.map((option) => option.text).join('')) + setDesc(options.map((option) => option.label).join('')) } } diff --git a/src/packages/datepicker/demos/h5/demo2.tsx b/src/packages/datepicker/demos/h5/demo2.tsx index 60a695dc40..cea8badaf4 100644 --- a/src/packages/datepicker/demos/h5/demo2.tsx +++ b/src/packages/datepicker/demos/h5/demo2.tsx @@ -1,5 +1,10 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react' +import { + DatePicker, + Cell, + PickerOptions, + PickerValue, +} from '@nutui/nutui-react' const Demo2 = () => { const defaultValue = new Date() @@ -8,8 +13,9 @@ const Demo2 = () => { `${defaultValue.getMonth() + 1}-${defaultValue.getDate()}` ) - const confirm = (values: (string | number)[], options: PickerOption[]) => { - setDesc(options.map((option) => option.text).join('-')) + const confirm = (values: PickerValue[], options: PickerOptions) => { + console.log('values', values, options) + setDesc(options.map((option) => option.label).join('-')) } return ( <> diff --git a/src/packages/datepicker/demos/h5/demo3.tsx b/src/packages/datepicker/demos/h5/demo3.tsx index 1143b67773..bf0cce9a2e 100644 --- a/src/packages/datepicker/demos/h5/demo3.tsx +++ b/src/packages/datepicker/demos/h5/demo3.tsx @@ -1,5 +1,10 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react' +import { + DatePicker, + Cell, + PickerOptions, + PickerValue, +} from '@nutui/nutui-react' const Demo3 = () => { const defaultValue = new Date() @@ -11,7 +16,7 @@ const Demo3 = () => { const endDate = new Date(2025, 10, 1) const [show, setShow] = useState(false) const [desc, setDesc] = useState(`${defaultDescription} 11:08`) - const confirm = (values: (string | number)[], options: PickerOption[]) => { + const confirm = (values: PickerValue[], options: PickerOptions) => { const date = values.slice(0, 3).join('-') const time = values.slice(3).join(':') setDesc(`${date} ${time}`) diff --git a/src/packages/datepicker/demos/h5/demo4.tsx b/src/packages/datepicker/demos/h5/demo4.tsx index fefb4b317d..7e01fa6996 100644 --- a/src/packages/datepicker/demos/h5/demo4.tsx +++ b/src/packages/datepicker/demos/h5/demo4.tsx @@ -1,5 +1,10 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react' +import { + DatePicker, + Cell, + PickerValue, + PickerOptions, +} from '@nutui/nutui-react' const Demo4 = () => { const defaultValue = new Date() @@ -10,8 +15,8 @@ const Demo4 = () => { const endDate = new Date(2025, 10, 1) const [show, setShow] = useState(false) const [desc, setDesc] = useState('10:10:00') - const confirm = (values: (string | number)[], options: PickerOption[]) => { - setDesc(options.map((option) => option.text).join(':')) + const confirm = (values: PickerValue[], options: PickerOptions) => { + setDesc(options.map((option) => option.label).join(':')) } return ( diff --git a/src/packages/datepicker/demos/h5/demo5.tsx b/src/packages/datepicker/demos/h5/demo5.tsx index 0ab54a263e..e396a55a9f 100644 --- a/src/packages/datepicker/demos/h5/demo5.tsx +++ b/src/packages/datepicker/demos/h5/demo5.tsx @@ -1,5 +1,10 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react' +import { + DatePicker, + Cell, + PickerOptions, + PickerValue, +} from '@nutui/nutui-react' const Demo5 = () => { const defaultValue = new Date() @@ -10,8 +15,8 @@ const Demo5 = () => { const endDate = new Date(2025, 10, 1) const [show, setShow] = useState(false) const [desc, setDesc] = useState('10:10') - const confirm8 = (options: PickerOption[], values: (string | number)[]) => { - setDesc(options.map((option) => option.text).join(':')) + const confirm8 = (options: PickerOptions, values: PickerValue[]) => { + setDesc(options.map((option) => option.label).join(':')) } return ( diff --git a/src/packages/datepicker/demos/h5/demo6.tsx b/src/packages/datepicker/demos/h5/demo6.tsx index 09e831821c..21350012de 100644 --- a/src/packages/datepicker/demos/h5/demo6.tsx +++ b/src/packages/datepicker/demos/h5/demo6.tsx @@ -1,5 +1,11 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react' +import { + DatePicker, + Cell, + PickerValue, + PickerOption, + PickerOptions, +} from '@nutui/nutui-react' const Demo6 = () => { const defaultValue = new Date() @@ -9,36 +15,36 @@ const Demo6 = () => { const [show, setShow] = useState(false) const [desc, setDesc] = useState(`${defaultDescription} 10:10`) - const confirm = (values: (string | number)[], options: PickerOption[]) => { + const confirm = (values: PickerValue[], options: PickerOptions) => { const date = options .slice(1, 3) - .map((op) => op.text) + .map((op) => op.label) .join('') const time = options .slice(3) .map((op) => op.value) .join(':') - setDesc(`${options[0].text}年${date} ${time}`) + setDesc(`${options[0].label}年${date} ${time}`) } const formatter = (type: string, option: PickerOption) => { switch (type) { case 'year': - option.text += '' + option.label += '' break case 'month': - option.text += '月' + option.label += '月' break case 'day': - option.text += '日' + option.label += '日' break case 'hour': - option.text += '时' + option.label += '时' break case 'minute': - option.text += '分' + option.label += '分' break default: - option.text += '' + option.label += '' } return option } diff --git a/src/packages/datepicker/demos/h5/demo7.tsx b/src/packages/datepicker/demos/h5/demo7.tsx index a447fa27f5..ba3b8f9366 100644 --- a/src/packages/datepicker/demos/h5/demo7.tsx +++ b/src/packages/datepicker/demos/h5/demo7.tsx @@ -1,5 +1,10 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react' +import { + DatePicker, + Cell, + PickerValue, + PickerOptions, +} from '@nutui/nutui-react' const Demo7 = () => { const defaultValue = new Date() @@ -11,8 +16,8 @@ const Demo7 = () => { const [show, setShow] = useState(false) const [desc, setDesc] = useState('10:10:00') - const confirm6 = (values: (string | number)[], options: PickerOption[]) => { - setDesc(options.map((option) => option.text).join(':')) + const confirm6 = (values: PickerValue[], options: PickerOptions) => { + setDesc(options.map((option) => option.label).join(':')) } return ( <> diff --git a/src/packages/datepicker/demos/h5/demo8.tsx b/src/packages/datepicker/demos/h5/demo8.tsx index 84f2b853e3..f821923cec 100644 --- a/src/packages/datepicker/demos/h5/demo8.tsx +++ b/src/packages/datepicker/demos/h5/demo8.tsx @@ -1,5 +1,11 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react' +import { + DatePicker, + Cell, + PickerValue, + PickerOption, + PickerOptions, +} from '@nutui/nutui-react' const Demo8 = () => { const startDate = new Date(2020, 0, 1) @@ -15,31 +21,31 @@ const Demo8 = () => { }月${defaultValue.getDate()}日 06时` ) - const confirm = (values: (string | number)[], options: PickerOption[]) => { - setDesc(options.map((option) => option.text).join(' ')) + const confirm = (values: PickerValue[], options: PickerOptions) => { + setDesc(options.map((option) => option.label).join(' ')) } - const filter = (type: string, options: PickerOption[]) => { + const filter = (type: string, options: PickerOptions) => { if (type === 'hour') { return options.filter((option) => Number(option.value) % 6 === 0) } return options } - const formatter1 = (type: string, option: PickerOption) => { + const formatter = (type: string, option: PickerOption) => { switch (type) { case 'year': - option.text += `年` + option.label += `年` break case 'month': - option.text += `月` + option.label += `月` break case 'day': - option.text += `日` + option.label += `日` break case 'hour': - option.text += `时` + option.label += `时` break default: - option.text += '' + option.label += '' } return option } @@ -57,7 +63,7 @@ const Demo8 = () => { endDate={endDate} visible={show} defaultValue={new Date(`${defaultDescription}`)} - formatter={formatter1} + formatter={formatter} minuteStep={5} filter={filter} onClose={() => setShow(false)} diff --git a/src/packages/datepicker/demos/taro/demo1.tsx b/src/packages/datepicker/demos/taro/demo1.tsx index a81c77dfc5..a5690b6864 100644 --- a/src/packages/datepicker/demos/taro/demo1.tsx +++ b/src/packages/datepicker/demos/taro/demo1.tsx @@ -1,5 +1,10 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react-taro' +import { + DatePicker, + Cell, + PickerOptions, + PickerValue, +} from '@nutui/nutui-react-taro' import isEqual from 'react-fast-compare' const useDatePicker = (initialDate: Date) => { @@ -31,17 +36,17 @@ const Demo1 = () => { const handleConfirm = (setDesc: (desc: string) => void, setValue?: (value: string) => void) => - (options: PickerOption[], values: (string | number)[]) => { + (options: PickerOptions, values: PickerValue[]) => { if (setValue) { if (isEqual(values, ['2026', '02', '21'])) { setValue('2026/03/22') setDesc('2026年03月22日') } else { setValue(values.join('/')) - setDesc(options.map((option) => option.text).join('')) + setDesc(options.map((option) => option.label).join('')) } } else { - setDesc(options.map((option) => option.text).join('')) + setDesc(options.map((option) => option.label).join('')) } } diff --git a/src/packages/datepicker/demos/taro/demo2.tsx b/src/packages/datepicker/demos/taro/demo2.tsx index 947d497e95..0a6e49eaf8 100644 --- a/src/packages/datepicker/demos/taro/demo2.tsx +++ b/src/packages/datepicker/demos/taro/demo2.tsx @@ -1,5 +1,10 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react-taro' +import { + DatePicker, + Cell, + PickerOptions, + PickerValue, +} from '@nutui/nutui-react-taro' const Demo2 = () => { const defaultValue = new Date() @@ -7,9 +12,8 @@ const Demo2 = () => { const [desc, setDesc] = useState( `${defaultValue.getMonth() + 1}-${defaultValue.getDate()}` ) - - const confirm = (values: (string | number)[], options: PickerOption[]) => { - setDesc(options.map((option) => option.text).join('-')) + const confirm = (values: PickerValue[], options: PickerOptions) => { + setDesc(options.map((option) => option.label).join('-')) } return ( <> diff --git a/src/packages/datepicker/demos/taro/demo3.tsx b/src/packages/datepicker/demos/taro/demo3.tsx index 0334291b40..b4dedc010f 100644 --- a/src/packages/datepicker/demos/taro/demo3.tsx +++ b/src/packages/datepicker/demos/taro/demo3.tsx @@ -1,5 +1,10 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react-taro' +import { + DatePicker, + Cell, + PickerValue, + PickerOptions, +} from '@nutui/nutui-react-taro' const Demo3 = () => { const defaultValue = new Date() @@ -11,7 +16,7 @@ const Demo3 = () => { const endDate = new Date(2025, 10, 1) const [show, setShow] = useState(false) const [desc, setDesc] = useState(`${defaultDescription} 11:08`) - const confirm = (values: (string | number)[], options: PickerOption[]) => { + const confirm = (values: PickerValue[], options: PickerOptions) => { const date = values.slice(0, 3).join('-') const time = values.slice(3).join(':') setDesc(`${date} ${time}`) diff --git a/src/packages/datepicker/demos/taro/demo4.tsx b/src/packages/datepicker/demos/taro/demo4.tsx index 99f4ca3a55..00e85593b7 100644 --- a/src/packages/datepicker/demos/taro/demo4.tsx +++ b/src/packages/datepicker/demos/taro/demo4.tsx @@ -1,5 +1,10 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react-taro' +import { + DatePicker, + Cell, + PickerValue, + PickerOptions, +} from '@nutui/nutui-react-taro' const Demo4 = () => { const defaultValue = new Date() @@ -10,8 +15,8 @@ const Demo4 = () => { const endDate = new Date(2025, 10, 1) const [show, setShow] = useState(false) const [desc, setDesc] = useState('10:10:00') - const confirm = (values: (string | number)[], options: PickerOption[]) => { - setDesc(options.map((option) => option.text).join(':')) + const confirm = (values: PickerValue[], options: PickerOptions) => { + setDesc(options.map((option) => option.label).join(':')) } return ( diff --git a/src/packages/datepicker/demos/taro/demo5.tsx b/src/packages/datepicker/demos/taro/demo5.tsx index db834280b3..0386bc9c61 100644 --- a/src/packages/datepicker/demos/taro/demo5.tsx +++ b/src/packages/datepicker/demos/taro/demo5.tsx @@ -1,5 +1,10 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react-taro' +import { + DatePicker, + Cell, + PickerValue, + PickerOptions, +} from '@nutui/nutui-react-taro' const Demo5 = () => { const defaultValue = new Date() @@ -10,8 +15,8 @@ const Demo5 = () => { const endDate = new Date(2025, 10, 1) const [show, setShow] = useState(false) const [desc, setDesc] = useState('10:10') - const confirm = (options: PickerOption[], values: (string | number)[]) => { - setDesc(options.map((option) => option.text).join(':')) + const confirm = (options: PickerOptions, values: PickerValue[]) => { + setDesc(options.map((option) => option.label).join(':')) } return ( diff --git a/src/packages/datepicker/demos/taro/demo6.tsx b/src/packages/datepicker/demos/taro/demo6.tsx index 037c396eec..9aa1371946 100644 --- a/src/packages/datepicker/demos/taro/demo6.tsx +++ b/src/packages/datepicker/demos/taro/demo6.tsx @@ -1,5 +1,11 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react-taro' +import { + DatePicker, + Cell, + PickerValue, + PickerOption, + PickerOptions, +} from '@nutui/nutui-react-taro' const Demo6 = () => { const defaultValue = new Date() @@ -9,36 +15,36 @@ const Demo6 = () => { const [show, setShow] = useState(false) const [desc, setDesc] = useState(`${defaultDescription} 10:10`) - const confirm = (values: (string | number)[], options: PickerOption[]) => { + const confirm = (values: PickerValue[], options: PickerOptions) => { const date = options .slice(1, 3) - .map((op) => op.text) + .map((op) => op.label) .join('') const time = options .slice(3) .map((op) => op.value) .join(':') - setDesc(`${options[0].text}年${date} ${time}`) + setDesc(`${options[0].label}年${date} ${time}`) } const formatter = (type: string, option: PickerOption) => { switch (type) { case 'year': - option.text += '' + option.label += '' break case 'month': - option.text += '月' + option.label += '月' break case 'day': - option.text += '日' + option.label += '日' break case 'hour': - option.text += '时' + option.label += '时' break case 'minute': - option.text += '分' + option.label += '分' break default: - option.text += '' + option.label += '' } return option } diff --git a/src/packages/datepicker/demos/taro/demo7.tsx b/src/packages/datepicker/demos/taro/demo7.tsx index 24702e28bf..6f7210ac00 100644 --- a/src/packages/datepicker/demos/taro/demo7.tsx +++ b/src/packages/datepicker/demos/taro/demo7.tsx @@ -1,5 +1,10 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react-taro' +import { + DatePicker, + Cell, + PickerValue, + PickerOptions, +} from '@nutui/nutui-react-taro' const Demo7 = () => { const defaultValue = new Date() @@ -11,8 +16,8 @@ const Demo7 = () => { const [show, setShow] = useState(false) const [desc, setDesc] = useState('10:10:00') - const confirm = (values: (string | number)[], options: PickerOption[]) => { - setDesc(options.map((option) => option.text).join(':')) + const confirm = (values: PickerValue[], options: PickerOptions) => { + setDesc(options.map((option) => option.label).join(':')) } return ( <> diff --git a/src/packages/datepicker/demos/taro/demo8.tsx b/src/packages/datepicker/demos/taro/demo8.tsx index 31911a0f5a..2031efe015 100644 --- a/src/packages/datepicker/demos/taro/demo8.tsx +++ b/src/packages/datepicker/demos/taro/demo8.tsx @@ -1,5 +1,11 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react-taro' +import { + DatePicker, + Cell, + PickerValue, + PickerOption, + PickerOptions, +} from '@nutui/nutui-react-taro' const Demo8 = () => { const startDate = new Date(2020, 0, 1) @@ -7,14 +13,18 @@ const Demo8 = () => { const defaultValue = new Date() const defaultDescription = `${defaultValue.getFullYear()}-${ defaultValue.getMonth() + 1 - }-${defaultValue.getDate()}` + }-${defaultValue.getDate()} 06:00` const [show, setShow] = useState(false) - const [desc, setDesc] = useState(`${defaultDescription} 00`) + const [desc, setDesc] = useState( + `${defaultValue.getFullYear()}年${ + defaultValue.getMonth() + 1 + }月${defaultValue.getDate()}日 06时` + ) - const confirm = (values: (string | number)[], options: PickerOption[]) => { - setDesc(options.map((option) => option.text).join(' ')) + const confirm = (values: PickerValue[], options: PickerOptions) => { + setDesc(options.map((option) => option.label).join(' ')) } - const filter = (type: string, options: PickerOption[]) => { + const filter = (type: string, options: PickerOptions) => { if (type === 'hour') { return options.filter((option) => Number(option.value) % 6 === 0) } @@ -23,26 +33,26 @@ const Demo8 = () => { const formatter = (type: string, option: PickerOption) => { switch (type) { case 'year': - option.text += `年` + option.label += `年` break case 'month': - option.text += `月` + option.label += `月` break case 'day': - option.text += `日` + option.label += `日` break case 'hour': - option.text += `时` + option.label += `时` break default: - option.text += '' + option.label += '' } return option } return ( <> setShow(true)} /> diff --git a/src/packages/datepicker/doc.en-US.md b/src/packages/datepicker/doc.en-US.md index 03fa3aff30..f330ddff9d 100644 --- a/src/packages/datepicker/doc.en-US.md +++ b/src/packages/datepicker/doc.en-US.md @@ -89,7 +89,7 @@ import { DatePicker } from '@nutui/nutui' | endDate | End date | `Date` | `Ten years later on December 31` | | pickerProps | picker props | `object` | `-` | | formatter | Option text formatter | `(type: string, option: PickerOption) => PickerOption` | `-` | -| filter | Option filter | `(type: string, option: PickerOption) => PickerOption[]` | `-` | +| filter | Option filter | `(type: string, options: PickerOptions) => PickerOptions` | `-` | | threeDimensional | Turn on 3D effects | `boolean` | `true` | | onConfirm | Emitted when click confirm button. | `(options, value) => void` | `-` | | onCancel | Emitted when click cancel button. | `() => void` | `-` | diff --git a/src/packages/datepicker/doc.md b/src/packages/datepicker/doc.md index c7b3d741cd..fff8fc49e5 100644 --- a/src/packages/datepicker/doc.md +++ b/src/packages/datepicker/doc.md @@ -99,7 +99,7 @@ DatetimePicker 通过 type 属性来定义需要选择的时间类型。将 type | endDate | 结束日期 | `Date` | `十年后` | | pickerProps | 透传picker属性 | `object` | `-` | | formatter | 选项格式化函数 | `(type: string, option: PickerOption) => PickerOption` | `-` | -| filter | 选项过滤函数 | `(type: string, option: PickerOption) => PickerOption[]` | `-` | +| filter | 选项过滤函数 | `(type: string, options: PickerOptions) => PickerOptions` | `-` | | threeDimensional | 是否开启3D效果 | `boolean` | `true` | | onConfirm | 点击确定按钮时触发 | `(options, value) => void` | `-` | | onCancel | 点击取消按钮时触发 | `() => void` | `-` | diff --git a/src/packages/datepicker/doc.taro.md b/src/packages/datepicker/doc.taro.md index 766a1230b4..8328b12d9c 100644 --- a/src/packages/datepicker/doc.taro.md +++ b/src/packages/datepicker/doc.taro.md @@ -99,7 +99,7 @@ DatetimePicker 通过 type 属性来定义需要选择的时间类型。将 type | endDate | 结束日期 | `Date` | `十年后` | | formatter | 选项格式化函数 | `(type: string, option: PickerOption) => PickerOption` | `-` | | pickerProps | 透传picker属性 | `object` | `-` | -| filter | 选项过滤函数 | `(type: string, option: PickerOption) => PickerOption[]` | `-` | +| filter | 选项过滤函数 | `(type: string, options: PickerOptions) => PickerOptions` | `-` | | threeDimensional | 是否开启3D效果 | `boolean` | `true` | | onConfirm | 点击确定按钮时触发 | `(options, value) => void` | `-` | | onCancel | 点击取消按钮时触发 | `() => void` | `-` | diff --git a/src/packages/datepicker/doc.zh-TW.md b/src/packages/datepicker/doc.zh-TW.md index c364f20277..21850c8ebe 100644 --- a/src/packages/datepicker/doc.zh-TW.md +++ b/src/packages/datepicker/doc.zh-TW.md @@ -99,7 +99,7 @@ DatetimePicker 通過 type 屬性來定義需要選擇的時間類型。將 type | endDate | 結束日期 | `Date` | `十年後` | | formatter | 選項格式化函數 | `(type: string, option: PickerOption) => PickerOption` | `-` | | pickerProps | 透传 picker 屬性 | `object` | `-` | -| filter | 選項過濾函數 | `(type: string, option: PickerOption) => PickerOption[]` | `-` | +| filter | 選項過濾函數 | `(type: string, options: PickerOptions) => PickerOptions` | `-` | | threeDimensional | 是否開啟3D效果 | `boolean` | `true` | | onConfirm | 點擊確定按鈕時觸發 | `(options, value) => void` | `-` | | onCancel | 點擊取消按鈕時觸發 | `() => void` | `-` | diff --git a/src/packages/datepicker/index.taro.ts b/src/packages/datepicker/index.taro.ts index e5aef5354a..d50f1c96e8 100644 --- a/src/packages/datepicker/index.taro.ts +++ b/src/packages/datepicker/index.taro.ts @@ -1,4 +1,4 @@ -import DatePicker from './datepicker' +import DatePicker from './datepicker.taro' export type { DatePickerProps } from './types.taro' export default DatePicker diff --git a/src/packages/datepicker/types.ts b/src/packages/datepicker/types.ts index 0af55e6625..6d2a44ac12 100644 --- a/src/packages/datepicker/types.ts +++ b/src/packages/datepicker/types.ts @@ -1,5 +1,6 @@ import { BasicComponent } from '@/utils/typings' -import { PickerOption, PickerProps } from '../picker/types' +import { PickerProps } from '@/packages/picker/types' +import { PickerOptions, PickerValue, PickerOption } from '@/packages/pickerview' export type DatePickerRef = DatePickerActions export type DatePickerActions = { @@ -39,16 +40,16 @@ export interface DatePickerProps extends BasicComponent { > > formatter: (type: string, option: PickerOption) => PickerOption - filter: (type: string, option: PickerOption[]) => PickerOption[] + filter: (type: string, options: PickerOptions) => PickerOptions onClose: () => void onCancel: () => void onConfirm: ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => void onChange?: ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[], + selectedOptions: PickerOptions, + selectedValue: PickerValue[], columnIndex: number ) => void children?: any diff --git a/src/packages/datepicker/utils.ts b/src/packages/datepicker/utils.ts index cc82353bc2..99648a8df2 100644 --- a/src/packages/datepicker/utils.ts +++ b/src/packages/datepicker/utils.ts @@ -1,6 +1,10 @@ import { padZero } from '@/utils/pad-zero' import { isDate } from '@/utils/is-date' -import { PickerOption } from '../picker/types' +import { + PickerOption, + PickerOptions, + PickerValue, +} from '@/packages/pickerview/types' /** * 获取指定年份和月份的最后一天 @@ -160,13 +164,13 @@ export const generatePickerColumnWithCallback = ( currentValue: number | string, type: string, minuteStep: number, - callback: (selectedIndex: number, options: PickerOption[]) => void, + callback: (selectedIndex: number, options: PickerOptions) => void, showChinese: boolean, zhCNType: { [key: string]: string }, formatter?: (type: string, option: PickerOption) => PickerOption -): PickerOption[] => { +): PickerOptions => { let currentMin = min - const options: PickerOption[] = [] + const options: PickerOptions = [] let selectedIndex = 0 // 遍历从最小值到最大值的范围 @@ -212,7 +216,7 @@ export const formatPickerOption = ( ): PickerOption => { if (formatter) { return formatter(type, { - text: padZero(value, 2), + label: padZero(value, 2), value: padZero(value, 2), }) } @@ -222,7 +226,7 @@ export const formatPickerOption = ( const chineseText = showChinese ? zhCNType[type] : '' return { - text: paddedValue + chineseText, + label: paddedValue + chineseText, value: paddedValue, } } @@ -251,14 +255,14 @@ export const formatValue = ( * @param index 当前列的索引 */ export const handlePickerValueChange = ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[], + selectedOptions: PickerOptions, + selectedValue: PickerValue[], index: number, type: string, defaultDate: Date, handleDateComparison: ( newDate: Date | null, - selectedOptions: PickerOption[], + selectedOptions: PickerOptions, index: number ) => void ) => { @@ -269,7 +273,7 @@ export const handlePickerValueChange = ( rangeType ) ) { - const formattedDate: (string | number)[] = [] + const formattedDate: PickerValue[] = [] selectedValue.forEach((item) => { formattedDate.push(item) diff --git a/src/packages/form/demos/h5/demo7.tsx b/src/packages/form/demos/h5/demo7.tsx index ddd6ac960d..d0e12c6a7d 100644 --- a/src/packages/form/demos/h5/demo7.tsx +++ b/src/packages/form/demos/h5/demo7.tsx @@ -18,14 +18,15 @@ import { ArrowRight } from '@nutui/icons-react' const Demo7 = () => { const pickerOptions = [ - { value: 4, text: 'BeiJing' }, - { value: 1, text: 'NanJing' }, - { value: 2, text: 'WuXi' }, - { value: 8, text: 'DaQing' }, - { value: 9, text: 'SuiHua' }, - { value: 10, text: 'WeiFang' }, - { value: 12, text: 'ShiJiaZhuang' }, + { value: 1, label: 'BeiJing' }, + { value: 2, label: 'NanJing' }, + { value: 3, label: 'WuXi' }, + { value: 4, label: 'DaQing' }, + { value: 5, label: 'SuiHua' }, + { value: 6, label: 'WeiFang' }, + { value: 7, label: 'ShiJiaZhuang' }, ] + const submitFailed = (error: any) => { Toast.show({ content: JSON.stringify(error), icon: 'fail' }) } @@ -107,7 +108,7 @@ const Demo7 = () => { title={ value.length ? pickerOptions.filter((po) => po.value === value[0])[0] - ?.text + ?.label : 'Please select' } extra={} @@ -122,7 +123,6 @@ const Demo7 = () => { name="DatePicker" trigger="onConfirm" getValueFromEvent={(...args) => { - console.log('sssss', args[0]) return new Date(args[1].join('/')) }} onClick={(event, ref: any) => { diff --git a/src/packages/form/demos/taro/demo7.tsx b/src/packages/form/demos/taro/demo7.tsx index 34141a06fd..bf02da4caf 100644 --- a/src/packages/form/demos/taro/demo7.tsx +++ b/src/packages/form/demos/taro/demo7.tsx @@ -19,13 +19,13 @@ import { View } from '@tarojs/components' const Demo7 = () => { const pickerOptions = [ - { value: 4, text: 'BeiJing' }, - { value: 1, text: 'NanJing' }, - { value: 2, text: 'WuXi' }, - { value: 8, text: 'DaQing' }, - { value: 9, text: 'SuiHua' }, - { value: 10, text: 'WeiFang' }, - { value: 12, text: 'ShiJiaZhuang' }, + { value: 1, label: 'BeiJing' }, + { value: 2, label: 'NanJing' }, + { value: 3, label: 'WuXi' }, + { value: 4, label: 'DaQing' }, + { value: 5, label: 'SuiHua' }, + { value: 6, label: 'WeiFang' }, + { value: 7, label: 'ShiJiaZhuang' }, ] const submitFailed = (error: any) => { Taro.showToast({ title: JSON.stringify(error), icon: 'error' }) @@ -108,7 +108,7 @@ const Demo7 = () => { title={ value.length ? pickerOptions.filter((po) => po.value === value[0])[0] - ?.text + ?.label : 'Please select' } extra={} @@ -123,7 +123,6 @@ const Demo7 = () => { name="DatePicker" trigger="onConfirm" getValueFromEvent={(...args) => { - console.log('sssss', args[0]) return new Date(args[1].join('/')) }} onClick={(event, ref: any) => { diff --git a/src/packages/picker/__tests__/picker.spec.tsx b/src/packages/picker/__tests__/picker.spec.tsx index 0c08207240..c3f2447d3f 100644 --- a/src/packages/picker/__tests__/picker.spec.tsx +++ b/src/packages/picker/__tests__/picker.spec.tsx @@ -2,6 +2,7 @@ import React, { useState } from 'react' import { render, waitFor, fireEvent, act } from '@testing-library/react' import '@testing-library/jest-dom' import Picker from '../picker' +import { PickerOptions } from '@/packages/pickerview' function sleep(delay = 0): Promise { return new Promise((resolve) => { @@ -10,80 +11,84 @@ function sleep(delay = 0): Promise { } interface PickerOption { - text: string | number + label: string | number value: string | number disabled?: boolean - children?: PickerOption[] + children?: PickerOptions className?: string | number } const simpleColumns = [ - { text: '南京市', value: 'NanJing' }, - { text: '无锡市', value: 'WuXi' }, - { text: '海北藏族自治区', value: 'ZangZu' }, - { text: '北京市', value: 'BeiJing' }, - { text: '连云港市', value: 'LianYunGang' }, + [ + { label: '南京市', value: 'NanJing' }, + { label: '无锡市', value: 'WuXi' }, + { label: '海北藏族自治区', value: 'ZangZu' }, + { label: '北京市', value: 'BeiJing' }, + { label: '连云港市', value: 'LianYunGang' }, + ], ] const multipleColumns = [ [ - { text: '周一', value: 'Monday' }, - { text: '周二', value: 'Tuesday' }, - { text: '周三', value: 'Wednesday' }, - { text: '周四', value: 'Thursday' }, - { text: '周五', value: 'Friday' }, + { label: '周一', value: 'Monday' }, + { label: '周二', value: 'Tuesday' }, + { label: '周三', value: 'Wednesday' }, + { label: '周四', value: 'Thursday' }, + { label: '周五', value: 'Friday' }, ], // 第二列 [ - { text: '上午', value: 'Morning' }, - { text: '下午', value: 'Afternoon' }, - { text: '晚上', value: 'Evening' }, + { label: '上午', value: 'Morning' }, + { label: '下午', value: 'Afternoon' }, + { label: '晚上', value: 'Evening' }, ], ] const multistageColumns = [ - { - text: '浙江', - value: 'ZheJiang', - children: [ - { - text: '杭州', - value: 'HangZhou', - children: [ - { text: '西湖区', value: 'XiHu' }, - { text: '余杭区', value: 'YuHang' }, - ], - }, - { - text: '温州', - value: 'WenZhou', - children: [ - { text: '鹿城区', value: 'LuCheng' }, - { text: '瓯海区', value: 'OuHai' }, - ], - }, - ], - }, - { - text: '福建', - value: 'FuJian', - children: [ - { - text: '福州', - value: 'FuZhou', - children: [ - { text: '鼓楼区', value: 'GuLou' }, - { text: '台江区', value: 'TaiJiang' }, - ], - }, - { - text: '厦门', - value: 'XiaMen', - children: [ - { text: '思明区', value: 'SiMing' }, - { text: '海沧区', value: 'HaiCang' }, - ], - }, - ], - }, + [ + { + label: '浙江', + value: 'ZheJiang', + children: [ + { + label: '杭州', + value: 'HangZhou', + children: [ + { label: '西湖区', value: 'XiHu' }, + { label: '余杭区', value: 'YuHang' }, + ], + }, + { + label: '温州', + value: 'WenZhou', + children: [ + { label: '鹿城区', value: 'LuCheng' }, + { label: '瓯海区', value: 'OuHai' }, + ], + }, + ], + }, + { + label: '福建', + value: 'FuJian', + children: [ + { + label: '福州', + value: 'FuZhou', + children: [ + { label: '鼓楼区', value: 'GuLou' }, + { label: '台江区', value: 'TaiJiang' }, + ], + }, + { + label: '厦门', + value: 'XiaMen', + children: [ + { label: '思明区', value: 'SiMing' }, + { label: '海沧区', value: 'HaiCang' }, + ], + }, + ], + }, + ], ] test('renderLabel works', async () => { @@ -98,8 +103,9 @@ test('simple list-data confirm event', async () => { const { container } = render( confirm(value)} + onConfirm={(selectedOptions, value) => confirm(value)} /> ) const confirmBtn = container.querySelectorAll('.nut-picker-confirm-btn')[0] @@ -137,6 +143,7 @@ test('multiple list-data render', async () => { const { container } = render( confirm(value)} /> @@ -154,6 +161,7 @@ test('multistageColumns list-data render', async () => { confirm(value)} /> ) @@ -167,7 +175,7 @@ test('multistageColumns list-data render', async () => { test('async list-data render', async () => { const confirm = vi.fn() const PenderContent = () => { - const [asyncColumns, setasyncColumns] = useState([]) + const [asyncColumns, setasyncColumns] = useState([]) setTimeout(() => { setasyncColumns(simpleColumns) @@ -176,6 +184,7 @@ test('async list-data render', async () => { return ( confirm(value)} /> diff --git a/src/packages/picker/demos/h5/demo1.tsx b/src/packages/picker/demos/h5/demo1.tsx index b0c5f799ba..480bf28554 100644 --- a/src/packages/picker/demos/h5/demo1.tsx +++ b/src/packages/picker/demos/h5/demo1.tsx @@ -1,40 +1,44 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react' - -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} +import { + Picker, + Cell, + PickerOptions, + PickerValue, + PickerOnChangeCallbackParameter, + PickerOption, +} from '@nutui/nutui-react' const Demo1 = () => { const [visible, setVisible] = useState(false) const [baseDesc, setBaseDesc] = useState('') - const listData1 = [ + const options = [ [ - { value: 1, text: '南京市' }, - { value: 2, text: '无锡市' }, - { value: 3, text: '海北藏族自治区' }, - { value: 4, text: '北京市' }, - { value: 5, text: '连云港市' }, - { value: 8, text: '大庆市' }, - { value: 9, text: '绥化市' }, - { value: 10, text: '潍坊市' }, - { value: 12, text: '乌鲁木齐市' }, + { value: 1, label: '南京市' }, + { value: 2, label: '无锡市' }, + { value: 3, label: '海北藏族自治区' }, + { value: 4, label: '北京市' }, + { value: 5, label: '连云港市' }, + { value: 8, label: '大庆市' }, + { value: 9, label: '绥化市' }, + { value: 10, label: '潍坊市' }, + { value: 12, label: '乌鲁木齐市' }, ], ] - const changePicker = (list: any[], option: any, columnIndex: number) => { - console.log(columnIndex, option) + const changePicker = ({ + value, + index, + selectedOptions, + }: PickerOnChangeCallbackParameter) => { + console.log('changePicker', value, index, selectedOptions) } const confirmPicker = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { + console.log('confirmPicker', selectedOptions, selectedValue) let description = '' - options.forEach((option: any) => { - description += ` ${option.text}` + selectedOptions.forEach((option: PickerOption) => { + description += ` ${option.label}` }) setBaseDesc(description) } @@ -48,8 +52,8 @@ const Demo1 = () => { confirmPicker(list, values)} + options={options} + onConfirm={confirmPicker} onClose={() => setVisible(false)} onChange={changePicker} /> diff --git a/src/packages/picker/demos/h5/demo2.tsx b/src/packages/picker/demos/h5/demo2.tsx index 22b87f1203..643137b163 100644 --- a/src/packages/picker/demos/h5/demo2.tsx +++ b/src/packages/picker/demos/h5/demo2.tsx @@ -1,54 +1,46 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react' +import { Picker, Cell, PickerOptions, PickerValue } from '@nutui/nutui-react' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo2 = () => { const [visible, setVisible] = useState(false) - const [baseDefault, setbaseDefault] = useState('') + const [baseDesc, setBaseDesc] = useState('无锡市') const [defaultValue] = useState([2]) - - const listData1 = [ + const options = [ [ - { value: 1, text: '南京市' }, - { value: 2, text: '无锡市' }, - { value: 3, text: '海北藏族自治区' }, - { value: 4, text: '北京市' }, - { value: 5, text: '连云港市' }, - { value: 8, text: '大庆市' }, - { value: 9, text: '绥化市' }, - { value: 10, text: '潍坊市' }, - { value: 12, text: '乌鲁木齐市' }, + { value: 1, label: '南京市' }, + { value: 2, label: '无锡市' }, + { value: 3, label: '海北藏族自治区' }, + { value: 4, label: '北京市' }, + { value: 5, label: '连云港市' }, + { value: 8, label: '大庆市' }, + { value: 9, label: '绥化市' }, + { value: 10, label: '潍坊市' }, + { value: 12, label: '乌鲁木齐市' }, ], ] const confirmPicker = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { let description = '' - options.forEach((option: any) => { - description += ` ${option.text}` + selectedOptions.forEach((option: any) => { + description += ` ${option.label}` }) - setbaseDefault(description) + setBaseDesc(description) } return ( <> setVisible(!visible)} /> confirmPicker(list, values)} + options={options} + onConfirm={confirmPicker} onClose={() => setVisible(false)} /> diff --git a/src/packages/picker/demos/h5/demo3.tsx b/src/packages/picker/demos/h5/demo3.tsx index a4652af91d..81f59dcdfb 100644 --- a/src/packages/picker/demos/h5/demo3.tsx +++ b/src/packages/picker/demos/h5/demo3.tsx @@ -1,59 +1,64 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react' +import { Picker, Cell, PickerOptions, PickerValue } from '@nutui/nutui-react' +import isEqual from 'react-fast-compare' +import { PickerOnChangeCallbackParameter } from '@/packages/pickerview/types' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo3 = () => { - const [isVisible, setIsVisible] = useState(false) + const [visible, setVisible] = useState(false) const [baseDesc, setBaseDesc] = useState('') - const [val, setVal] = useState>([]) + const [value, setValue] = useState([] as PickerValue[]) const options = [ [ - { value: 1, text: '南京市' }, - { value: 2, text: '无锡市' }, - { value: 3, text: '海北藏族自治区' }, - { value: 4, text: '北京市' }, - { value: 5, text: '连云港市' }, - { value: 8, text: '大庆市' }, - { value: 9, text: '绥化市' }, - { value: 10, text: '潍坊市' }, - { value: 12, text: '乌鲁木齐市' }, + { value: 1, label: '南京市' }, + { value: 2, label: '无锡市' }, + { value: 3, label: '海北藏族自治区' }, + { value: 4, label: '北京市' }, + { value: 5, label: '连云港市' }, + { value: 8, label: '大庆市' }, + { value: 9, label: '绥化市' }, + { value: 10, label: '潍坊市' }, + { value: 12, label: '乌鲁木齐市' }, ], ] + + const changePicker = ({ + value, + index, + selectedOptions, + }: PickerOnChangeCallbackParameter) => { + console.log('changePicker', value, index, selectedOptions) + } const confirmPicker = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { - let description = '' - options.forEach((option: any) => { - description += ` ${option.text}` - }) - setBaseDesc(description) + if (isEqual(selectedValue, [3])) { + setValue([1]) + setBaseDesc('南京市') + } else { + setValue(selectedValue) + let description = '' + selectedOptions.forEach((option: any) => { + description += ` ${option.label}` + }) + setBaseDesc(description) + } } return ( <> setIsVisible(!isVisible)} + onClick={() => setVisible(!visible)} /> { - confirmPicker(list, values) - setVal(values) - }} - onClose={() => { - setIsVisible(false) - }} + onChange={changePicker} + onConfirm={confirmPicker} + onClose={() => setVisible(false)} /> ) diff --git a/src/packages/picker/demos/h5/demo4.tsx b/src/packages/picker/demos/h5/demo4.tsx index b9594ffb6b..16192241fd 100644 --- a/src/packages/picker/demos/h5/demo4.tsx +++ b/src/packages/picker/demos/h5/demo4.tsx @@ -1,39 +1,34 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react' +import { Picker, Cell, PickerOptions, PickerValue } from '@nutui/nutui-react' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo4 = () => { - const [isVisible2, setIsVisible2] = useState(false) - const [mutilDesc, setMutilDesc] = useState('') - const listData2 = [ + const [visible, setVisible] = useState(false) + const [mutilDesc, setMutilDesc] = useState('周三') + const [defaultValue] = useState(['Wednesday']) + const options = [ // 第一列 [ - { text: '周一', value: 'Monday' }, - { text: '周二', value: 'Tuesday' }, - { text: '周三', value: 'Wednesday' }, - { text: '周四', value: 'Thursday' }, - { text: '周五', value: 'Friday' }, + { label: '周一', value: 'Monday' }, + { label: '周二', value: 'Tuesday' }, + { label: '周三', value: 'Wednesday' }, + { label: '周四', value: 'Thursday' }, + { label: '周五', value: 'Friday' }, ], // 第二列 [ - { text: '上午', value: 'Morning' }, - { text: '下午', value: 'Afternoon' }, - { text: '晚上', value: 'Evening' }, + { label: '上午', value: 'Morning' }, + { label: '下午', value: 'Afternoon' }, + { label: '晚上', value: 'Evening' }, ], ] const confirmPicker = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { + console.log('confirmPicker', selectedOptions) let description = '' - options.forEach((option: any) => { - description += ` ${option.text}` + selectedOptions.forEach((option: any) => { + option?.label && (description += ` ${option.label}`) }) setMutilDesc(description) } @@ -42,14 +37,14 @@ const Demo4 = () => { setIsVisible2(!isVisible2)} + onClick={() => setVisible(!visible)} /> setIsVisible2(false)} - defaultValue={['Wednesday']} - onConfirm={(list, values) => confirmPicker(list, values)} + visible={visible} + options={options} + onClose={() => setVisible(false)} + defaultValue={defaultValue} + onConfirm={confirmPicker} /> ) diff --git a/src/packages/picker/demos/h5/demo5.tsx b/src/packages/picker/demos/h5/demo5.tsx index aeb6a2f1e0..73a72fd091 100644 --- a/src/packages/picker/demos/h5/demo5.tsx +++ b/src/packages/picker/demos/h5/demo5.tsx @@ -1,38 +1,27 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react' +import { Picker, Cell, PickerOptions, PickerValue } from '@nutui/nutui-react' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo5 = () => { - const [tileDesc, settileDesc] = useState('') const [isVisible, setIsVisible] = useState(false) - - const listData1 = [ + const [tileDesc, settileDesc] = useState('无锡市') + const options = [ [ - { value: 1, text: '南京市' }, - { value: 2, text: '无锡市' }, - { value: 3, text: '海北藏族自治区' }, - { value: 4, text: '北京市' }, - { value: 5, text: '连云港市' }, - { value: 8, text: '大庆市' }, - { value: 9, text: '绥化市' }, - { value: 10, text: '潍坊市' }, - { value: 12, text: '乌鲁木齐市' }, + { value: 1, label: '南京市' }, + { value: 2, label: '无锡市' }, + { value: 3, label: '海北藏族自治区' }, + { value: 4, label: '北京市' }, + { value: 5, label: '连云港市' }, + { value: 8, label: '大庆市' }, + { value: 9, label: '绥化市' }, + { value: 10, label: '潍坊市' }, + { value: 12, label: '乌鲁木齐市' }, ], ] - const confirmPicker = ( - options: PickerOption[], - values: (string | number)[] - ) => { + const confirmPicker = (options: PickerOptions, values: PickerValue[]) => { let description = '' options.forEach((option: any) => { - description += ` ${option.text}` + description += ` ${option.label}` }) settileDesc(description) setIsVisible(false) @@ -46,8 +35,8 @@ const Demo5 = () => { /> confirmPicker(list, values)} + options={options} + onConfirm={confirmPicker} defaultValue={[2]} threeDimensional={false} duration={1000} diff --git a/src/packages/picker/demos/h5/demo6.tsx b/src/packages/picker/demos/h5/demo6.tsx index 007a1f8352..f39d06544a 100644 --- a/src/packages/picker/demos/h5/demo6.tsx +++ b/src/packages/picker/demos/h5/demo6.tsx @@ -1,105 +1,93 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react' +import { + Picker, + Cell, + PickerOptions, + PickerValue, + PickerOption, +} from '@nutui/nutui-react' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo6 = () => { const [isVisible, setIsVisible] = useState(false) + const [value, setValue] = useState([2]) + const [cityCustom, setCityCustom] = useState('上海') const customCityData = [ - { - value: 1, - text: '北京', - children: [ - { - value: 1, - text: '朝阳区', - }, - { - value: 2, - text: '海淀区', - }, - { - value: 3, - text: '大兴区', - }, - { - value: 4, - text: '东城区', - }, - { - value: 5, - text: '西城区', - }, - { - value: 6, - text: '丰台区', - }, - ], - }, - { - value: 2, - text: '上海', - children: [ - { - value: 1, - text: '黄埔区', - }, - { - value: 2, - text: '长宁区', - }, - { - value: 3, - text: '普陀区', - }, - { - value: 4, - text: '杨浦区', - }, - { - value: 5, - text: '浦东新区', - }, - ], - }, + [ + { + value: 1, + label: '北京', + children: [ + { + value: 1, + label: '朝阳区', + }, + { + value: 2, + label: '海淀区', + }, + { + value: 3, + label: '大兴区', + }, + { + value: 4, + label: '东城区', + }, + { + value: 5, + label: '西城区', + }, + { + value: 6, + label: '丰台区', + }, + ], + }, + { + value: 2, + label: '上海', + children: [ + { + value: 1, + label: '黄埔区', + }, + { + value: 2, + label: '长宁区', + }, + { + value: 3, + label: '普陀区', + }, + { + value: 4, + label: '杨浦区', + }, + { + value: 5, + label: '浦东新区', + }, + ], + }, + ], ] - const [asyncData] = useState([ - { - value: 1, - text: '北京市', - children: [ - { value: 1, text: '朝阳区' }, - { value: 2, text: '海淀区' }, - { value: 3, text: '大兴区' }, - { value: 4, text: '东城区' }, - { value: 5, text: '西城区' }, - { value: 6, text: '丰台区' }, - ], - }, - { - value: 2, - text: '上海市', - children: [], - }, - ]) - const [cityCustom, setCityCustom] = useState('') const setChooseValueCustom = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { - const str = options.map((item) => item.text).join('-') - setCityCustom(str) + console.log('onconfirm', selectedOptions, selectedValue) + const city = selectedOptions + .map((item: PickerOption) => item.label) + .join('-') + setCityCustom(city) + setValue(selectedValue) } + return ( <> setIsVisible(!isVisible)} /> @@ -107,13 +95,12 @@ const Demo6 = () => { setIsVisible(false)} - onConfirm={(list, values) => setChooseValueCustom(list, values)} - onChange={( - options: PickerOption[], - value: (string | number)[], - columnIndex: number - ) => console.log(asyncData, '多级联动', columnIndex, value, options)} + onConfirm={setChooseValueCustom} + onChange={({ value, index, selectedOptions }) => + console.log('多级联动', value, index, selectedOptions) + } /> ) diff --git a/src/packages/picker/demos/h5/demo7.tsx b/src/packages/picker/demos/h5/demo7.tsx index 1707e8c4aa..553359db48 100644 --- a/src/packages/picker/demos/h5/demo7.tsx +++ b/src/packages/picker/demos/h5/demo7.tsx @@ -1,77 +1,100 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react' +import { + Picker, + Cell, + PickerOptions, + PickerValue, + PickerOnChangeCallbackParameter, + PickerOption, +} from '@nutui/nutui-react' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo7 = () => { const [isVisible, setIsVisible] = useState(false) - const [asyncDesc, setasyncDesc] = useState('') + const [value, setValue] = useState([1]) + const [asyncDesc, setasyncDesc] = useState('北京') const [asyncData, setAsyncData] = useState([ - { - value: 1, - text: '北京市', - children: [ - { value: 1, text: '朝阳区' }, - { value: 2, text: '海淀区' }, - { value: 3, text: '大兴区' }, - { value: 4, text: '东城区' }, - { value: 5, text: '西城区' }, - { value: 6, text: '丰台区' }, - ], - }, - { - value: 2, - text: '上海市', - children: [], - }, + [ + { + value: 1, + label: '北京', + children: [ + { + value: 1, + label: '朝阳区', + }, + { + value: 2, + label: '海淀区', + }, + { + value: 3, + label: '大兴区', + }, + { + value: 4, + label: '东城区', + }, + { + value: 5, + label: '西城区', + }, + { + value: 6, + label: '丰台区', + }, + ], + }, + { + value: 2, + label: '上海', + children: [], + }, + ], ]) - const updateChooseValueCustmer = ( - options: PickerOption[], - values: (string | number)[], - columnIndex: number - ) => { - console.log('updateChooseValueCustmer', columnIndex, values, options) - if (columnIndex === 0 && values[0] === 2) { + const updateChooseValueCustmer = ({ + value, + index, + selectedOptions, + }: PickerOnChangeCallbackParameter) => { + if (value[0] === 2 && asyncData[0]?.[1].children.length === 0) { + console.log('updateChooseValueCustmer', index, value, selectedOptions) setTimeout(() => { - if (asyncData[1].children.length === 0) { - asyncData[1].children = [ - { - value: 1, - text: '黄埔区', - }, - { - value: 2, - text: '长宁区', - }, - { - value: 3, - text: '普陀区', - }, - { - value: 4, - text: '杨浦区', - }, - { - value: 5, - text: '浦东新区', - }, - ] - setAsyncData([...asyncData]) - } - }, 100) + asyncData[0][1].children = [ + { + value: 1, + label: '黄埔区', + }, + { + value: 2, + label: '长宁区', + }, + { + value: 3, + label: '普陀区', + }, + { + value: 4, + label: '杨浦区', + }, + { + value: 5, + label: '浦东新区', + }, + ] + setAsyncData([...[...asyncData]]) + }, 0) } } const setAsyncConfirm = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { - const str = options.map((item) => item.text).join('-') - setasyncDesc(str) + console.log('onconfirm', selectedOptions, selectedValue) + const city = selectedOptions + .map((item: PickerOption) => item.label) + .join('-') + setasyncDesc(city) + setValue(selectedValue) } return ( @@ -81,18 +104,14 @@ const Demo7 = () => { description={asyncDesc} onClick={() => setIsVisible(!isVisible)} /> + setIsVisible(false)} - onConfirm={(list, values) => setAsyncConfirm(list, values)} - onChange={( - selectedOptions: PickerOption[], - selectedValue: (string | number)[], - columnIndex: number - ) => - updateChooseValueCustmer(selectedOptions, selectedValue, columnIndex) - } + onConfirm={setAsyncConfirm} + onChange={updateChooseValueCustmer} /> ) diff --git a/src/packages/picker/demos/h5/demo8.tsx b/src/packages/picker/demos/h5/demo8.tsx index 493b5dce06..4f16c7e357 100644 --- a/src/packages/picker/demos/h5/demo8.tsx +++ b/src/packages/picker/demos/h5/demo8.tsx @@ -1,50 +1,47 @@ import React, { useState } from 'react' -import { Picker, Cell, ConfigProvider } from '@nutui/nutui-react' +import { + Picker, + Cell, + ConfigProvider, + PickerOption, + PickerOptions, + PickerValue, +} from '@nutui/nutui-react' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo8 = () => { - const [isVisible, setIsVisible] = useState(false) + const [visible, setVisible] = useState(false) + const [baseDesc, setBaseDesc] = useState('') const options = [ [ - { value: 1, text: '南京市' }, - { value: 2, text: '无锡市' }, - { value: 3, text: '海北藏族自治区' }, - { value: 4, text: '北京市' }, - { value: 5, text: '连云港市' }, - { value: 8, text: '大庆市' }, - { value: 9, text: '绥化市' }, - { value: 10, text: '潍坊市' }, - { value: 12, text: '乌鲁木齐市' }, + { value: 1, label: '南京市' }, + { value: 2, label: '无锡市' }, + { value: 3, label: '海北藏族自治区' }, + { value: 4, label: '北京市' }, + { value: 5, label: '连云港市' }, + { value: 8, label: '大庆市' }, + { value: 9, label: '绥化市' }, + { value: 10, label: '潍坊市' }, + { value: 12, label: '乌鲁木齐市' }, ], ] - const [baseDesc, setBaseDesc] = useState('') - const confirmPicker = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { - console.log('demo 确定', options, values) + console.log('confirmPicker', selectedOptions, selectedValue) let description = '' - options.forEach((option: any) => { - description += ` ${option.text}` + selectedOptions.forEach((option: PickerOption) => { + description += ` ${option.label}` }) setBaseDesc(description) - setIsVisible(false) } - return ( <> setIsVisible(!isVisible)} + onClick={() => setVisible(!visible)} /> { }} > confirmPicker(list, values)} - onClose={() => { - setIsVisible(false) - console.log('onclose') - }} + onConfirm={confirmPicker} + onClose={() => setVisible(false)} /> diff --git a/src/packages/picker/demos/taro/demo1.tsx b/src/packages/picker/demos/taro/demo1.tsx index f34f7003f3..94bbae0cdf 100644 --- a/src/packages/picker/demos/taro/demo1.tsx +++ b/src/packages/picker/demos/taro/demo1.tsx @@ -1,40 +1,44 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react-taro' - -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} +import { + Picker, + Cell, + PickerOptions, + PickerValue, + PickerOnChangeCallbackParameter, + PickerOption, +} from '@nutui/nutui-react-taro' const Demo1 = () => { const [visible, setVisible] = useState(false) const [baseDesc, setBaseDesc] = useState('') - const listData1 = [ + const options = [ [ - { value: 1, text: '南京市' }, - { value: 2, text: '无锡市' }, - { value: 3, text: '海北藏族自治区' }, - { value: 4, text: '北京市' }, - { value: 5, text: '连云港市' }, - { value: 8, text: '大庆市' }, - { value: 9, text: '绥化市' }, - { value: 10, text: '潍坊市' }, - { value: 12, text: '乌鲁木齐市' }, + { value: 1, label: '南京市' }, + { value: 2, label: '无锡市' }, + { value: 3, label: '海北藏族自治区' }, + { value: 4, label: '北京市' }, + { value: 5, label: '连云港市' }, + { value: 8, label: '大庆市' }, + { value: 9, label: '绥化市' }, + { value: 10, label: '潍坊市' }, + { value: 12, label: '乌鲁木齐市' }, ], ] - const changePicker = (list: any[], option: any, columnIndex: number) => { - console.log(columnIndex, option) + const changePicker = ({ + value, + index, + selectedOptions, + }: PickerOnChangeCallbackParameter) => { + console.log('changePicker', value, index, selectedOptions) } const confirmPicker = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { + console.log('confirmPicker', selectedOptions, selectedValue) let description = '' - options.forEach((option: any) => { - description += ` ${option.text}` + selectedOptions.forEach((option: PickerOption) => { + description += ` ${option.label}` }) setBaseDesc(description) } @@ -48,8 +52,8 @@ const Demo1 = () => { confirmPicker(list, values)} + options={options} + onConfirm={confirmPicker} onClose={() => setVisible(false)} onChange={changePicker} /> diff --git a/src/packages/picker/demos/taro/demo2.tsx b/src/packages/picker/demos/taro/demo2.tsx index ca6a3d4c09..f4fe925b36 100644 --- a/src/packages/picker/demos/taro/demo2.tsx +++ b/src/packages/picker/demos/taro/demo2.tsx @@ -1,54 +1,51 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react-taro' +import { + Picker, + Cell, + PickerOptions, + PickerValue, +} from '@nutui/nutui-react-taro' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo2 = () => { const [visible, setVisible] = useState(false) - const [baseDefault, setbaseDefault] = useState('') + const [baseDesc, setBaseDesc] = useState('无锡市') const [defaultValue] = useState([2]) - - const listData1 = [ + const options = [ [ - { value: 1, text: '南京市' }, - { value: 2, text: '无锡市' }, - { value: 3, text: '海北藏族自治区' }, - { value: 4, text: '北京市' }, - { value: 5, text: '连云港市' }, - { value: 8, text: '大庆市' }, - { value: 9, text: '绥化市' }, - { value: 10, text: '潍坊市' }, - { value: 12, text: '乌鲁木齐市' }, + { value: 1, label: '南京市' }, + { value: 2, label: '无锡市' }, + { value: 3, label: '海北藏族自治区' }, + { value: 4, label: '北京市' }, + { value: 5, label: '连云港市' }, + { value: 8, label: '大庆市' }, + { value: 9, label: '绥化市' }, + { value: 10, label: '潍坊市' }, + { value: 12, label: '乌鲁木齐市' }, ], ] const confirmPicker = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { let description = '' - options.forEach((option: any) => { - description += ` ${option.text}` + selectedOptions.forEach((option: any) => { + description += ` ${option.label}` }) - setbaseDefault(description) + setBaseDesc(description) } return ( <> setVisible(!visible)} /> confirmPicker(list, values)} + options={options} + onConfirm={confirmPicker} onClose={() => setVisible(false)} /> diff --git a/src/packages/picker/demos/taro/demo3.tsx b/src/packages/picker/demos/taro/demo3.tsx index f183117990..c0cee40ba1 100644 --- a/src/packages/picker/demos/taro/demo3.tsx +++ b/src/packages/picker/demos/taro/demo3.tsx @@ -1,59 +1,69 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react-taro' +import { + Picker, + Cell, + PickerOptions, + PickerValue, +} from '@nutui/nutui-react-taro' +import isEqual from 'react-fast-compare' +import { PickerOnChangeCallbackParameter } from '@/packages/pickerview/types' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo3 = () => { - const [isVisible, setIsVisible] = useState(false) + const [visible, setVisible] = useState(false) const [baseDesc, setBaseDesc] = useState('') - const [val, setVal] = useState>([]) + const [value, setValue] = useState([] as PickerValue[]) const options = [ [ - { value: 1, text: '南京市' }, - { value: 2, text: '无锡市' }, - { value: 3, text: '海北藏族自治区' }, - { value: 4, text: '北京市' }, - { value: 5, text: '连云港市' }, - { value: 8, text: '大庆市' }, - { value: 9, text: '绥化市' }, - { value: 10, text: '潍坊市' }, - { value: 12, text: '乌鲁木齐市' }, + { value: 1, label: '南京市' }, + { value: 2, label: '无锡市' }, + { value: 3, label: '海北藏族自治区' }, + { value: 4, label: '北京市' }, + { value: 5, label: '连云港市' }, + { value: 8, label: '大庆市' }, + { value: 9, label: '绥化市' }, + { value: 10, label: '潍坊市' }, + { value: 12, label: '乌鲁木齐市' }, ], ] + + const changePicker = ({ + value, + index, + selectedOptions, + }: PickerOnChangeCallbackParameter) => { + console.log('changePicker', value, index, selectedOptions) + } const confirmPicker = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { - let description = '' - options.forEach((option: any) => { - description += ` ${option.text}` - }) - setBaseDesc(description) + if (isEqual(selectedValue, [3])) { + setValue([1]) + setBaseDesc('南京市') + } else { + setValue(selectedValue) + let description = '' + selectedOptions.forEach((option: any) => { + description += ` ${option.label}` + }) + setBaseDesc(description) + } } return ( <> setIsVisible(!isVisible)} + onClick={() => setVisible(!visible)} /> { - confirmPicker(list, values) - setVal(values) - }} - onClose={() => { - setIsVisible(false) - }} + onChange={changePicker} + onConfirm={confirmPicker} + onClose={() => setVisible(false)} /> ) diff --git a/src/packages/picker/demos/taro/demo4.tsx b/src/packages/picker/demos/taro/demo4.tsx index 79992790c3..ea0cfdfab9 100644 --- a/src/packages/picker/demos/taro/demo4.tsx +++ b/src/packages/picker/demos/taro/demo4.tsx @@ -1,59 +1,55 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react-taro' +import { + Picker, + Cell, + PickerOptions, + PickerValue, +} from '@nutui/nutui-react-taro' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo4 = () => { - const [isVisible2, setIsVisible2] = useState(false) - const [mutilDesc, setMutilDesc] = useState('') - const listData2 = [ + const [visible, setVisible] = useState(false) + const [mutilDesc, setMutilDesc] = useState('周三') + const [defaultValue] = useState(['Wednesday']) + const options = [ // 第一列 [ - { text: '周一', value: 'Monday' }, - { text: '周二', value: 'Tuesday' }, - { text: '周三', value: 'Wednesday' }, - { text: '周四', value: 'Thursday' }, - { text: '周五', value: 'Friday' }, + { label: '周一', value: 'Monday' }, + { label: '周二', value: 'Tuesday' }, + { label: '周三', value: 'Wednesday' }, + { label: '周四', value: 'Thursday' }, + { label: '周五', value: 'Friday' }, ], // 第二列 [ - { text: '上午', value: 'Morning' }, - { text: '下午', value: 'Afternoon' }, - { text: '晚上', value: 'Evening' }, + { label: '上午', value: 'Morning' }, + { label: '下午', value: 'Afternoon' }, + { label: '晚上', value: 'Evening' }, ], ] const confirmPicker = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { + console.log('confirmPicker', selectedOptions) let description = '' - options.forEach((option: any) => { - description += ` ${option.text}` + selectedOptions.forEach((option: any) => { + option?.label && (description += ` ${option.label}`) }) setMutilDesc(description) } - const changePicker = (options: any[], values: any, columnIndex: number) => { - console.log('picker onChange', columnIndex, values, options) - } return ( <> setIsVisible2(!isVisible2)} + onClick={() => setVisible(!visible)} /> setIsVisible2(false)} - defaultValue={['Wednesday']} - onChange={changePicker} - onConfirm={(list, values) => confirmPicker(list, values)} + visible={visible} + options={options} + onClose={() => setVisible(false)} + defaultValue={defaultValue} + onConfirm={confirmPicker} /> ) diff --git a/src/packages/picker/demos/taro/demo5.tsx b/src/packages/picker/demos/taro/demo5.tsx index df1c6c3d36..cd4fcd0af9 100644 --- a/src/packages/picker/demos/taro/demo5.tsx +++ b/src/packages/picker/demos/taro/demo5.tsx @@ -1,45 +1,36 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react-taro' +import { + Picker, + Cell, + PickerOptions, + PickerValue, +} from '@nutui/nutui-react-taro' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo5 = () => { - const [tileDesc, settileDesc] = useState('') const [isVisible, setIsVisible] = useState(false) - - const listData1 = [ + const [tileDesc, settileDesc] = useState('无锡市') + const options = [ [ - { value: 1, text: '南京市' }, - { value: 2, text: '无锡市' }, - { value: 3, text: '海北藏族自治区' }, - { value: 4, text: '北京市' }, - { value: 5, text: '连云港市' }, - { value: 8, text: '大庆市' }, - { value: 9, text: '绥化市' }, - { value: 10, text: '潍坊市' }, - { value: 12, text: '乌鲁木齐市' }, + { value: 1, label: '南京市' }, + { value: 2, label: '无锡市' }, + { value: 3, label: '海北藏族自治区' }, + { value: 4, label: '北京市' }, + { value: 5, label: '连云港市' }, + { value: 8, label: '大庆市' }, + { value: 9, label: '绥化市' }, + { value: 10, label: '潍坊市' }, + { value: 12, label: '乌鲁木齐市' }, ], ] - const confirmPicker = ( - options: PickerOption[], - values: (string | number)[] - ) => { + const confirmPicker = (options: PickerOptions, values: PickerValue[]) => { let description = '' options.forEach((option: any) => { - description += ` ${option.text}` + description += ` ${option.label}` }) settileDesc(description) setIsVisible(false) } - const changePicker = (options: any[], values: any, columnIndex: number) => { - console.log('picker onChange', columnIndex, values, options) - } return ( <> { /> confirmPicker(list, values)} + options={options} + onConfirm={confirmPicker} defaultValue={[2]} threeDimensional={false} duration={1000} onClose={() => setIsVisible(false)} - onChange={changePicker} /> ) diff --git a/src/packages/picker/demos/taro/demo6.tsx b/src/packages/picker/demos/taro/demo6.tsx index 3c3e880622..64f6bf4ba9 100644 --- a/src/packages/picker/demos/taro/demo6.tsx +++ b/src/packages/picker/demos/taro/demo6.tsx @@ -1,105 +1,93 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react-taro' +import { + Picker, + Cell, + PickerOptions, + PickerValue, + PickerOption, +} from '@nutui/nutui-react-taro' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo6 = () => { const [isVisible, setIsVisible] = useState(false) + const [value, setValue] = useState([2]) + const [cityCustom, setCityCustom] = useState('上海') const customCityData = [ - { - value: 1, - text: '北京', - children: [ - { - value: 1, - text: '朝阳区', - }, - { - value: 2, - text: '海淀区', - }, - { - value: 3, - text: '大兴区', - }, - { - value: 4, - text: '东城区', - }, - { - value: 5, - text: '西城区', - }, - { - value: 6, - text: '丰台区', - }, - ], - }, - { - value: 2, - text: '上海', - children: [ - { - value: 1, - text: '黄埔区', - }, - { - value: 2, - text: '长宁区', - }, - { - value: 3, - text: '普陀区', - }, - { - value: 4, - text: '杨浦区', - }, - { - value: 5, - text: '浦东新区', - }, - ], - }, + [ + { + value: 1, + label: '北京', + children: [ + { + value: 1, + label: '朝阳区', + }, + { + value: 2, + label: '海淀区', + }, + { + value: 3, + label: '大兴区', + }, + { + value: 4, + label: '东城区', + }, + { + value: 5, + label: '西城区', + }, + { + value: 6, + label: '丰台区', + }, + ], + }, + { + value: 2, + label: '上海', + children: [ + { + value: 1, + label: '黄埔区', + }, + { + value: 2, + label: '长宁区', + }, + { + value: 3, + label: '普陀区', + }, + { + value: 4, + label: '杨浦区', + }, + { + value: 5, + label: '浦东新区', + }, + ], + }, + ], ] - const [asyncData] = useState([ - { - value: 1, - text: '北京市', - children: [ - { value: 1, text: '朝阳区' }, - { value: 2, text: '海淀区' }, - { value: 3, text: '大兴区' }, - { value: 4, text: '东城区' }, - { value: 5, text: '西城区' }, - { value: 6, text: '丰台区' }, - ], - }, - { - value: 2, - text: '上海市', - children: [], - }, - ]) - const [cityCustom, setCityCustom] = useState('') const setChooseValueCustom = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { - const str = options.map((item) => item.text).join('-') - setCityCustom(str) + console.log('onconfirm', selectedOptions, selectedValue) + const city = selectedOptions + .map((item: PickerOption) => item.label) + .join('-') + setCityCustom(city) + setValue(selectedValue) } + return ( <> setIsVisible(!isVisible)} /> @@ -107,13 +95,12 @@ const Demo6 = () => { setIsVisible(false)} - onConfirm={(list, values) => setChooseValueCustom(list, values)} - onChange={( - options: PickerOption[], - value: (string | number)[], - columnIndex: number - ) => console.log(asyncData, '多级联动', columnIndex, value, options)} + onConfirm={setChooseValueCustom} + onChange={({ value, index, selectedOptions }) => + console.log('多级联动', value, index, selectedOptions) + } /> ) diff --git a/src/packages/picker/demos/taro/demo7.tsx b/src/packages/picker/demos/taro/demo7.tsx index 2bd3af5785..2071f0010f 100644 --- a/src/packages/picker/demos/taro/demo7.tsx +++ b/src/packages/picker/demos/taro/demo7.tsx @@ -1,77 +1,100 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react-taro' +import { + Picker, + Cell, + PickerOptions, + PickerValue, + PickerOnChangeCallbackParameter, + PickerOption, +} from '@nutui/nutui-react-taro' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo7 = () => { const [isVisible, setIsVisible] = useState(false) - const [asyncDesc, setasyncDesc] = useState('') + const [value, setValue] = useState([1]) + const [asyncDesc, setasyncDesc] = useState('北京') const [asyncData, setAsyncData] = useState([ - { - value: 1, - text: '北京市', - children: [ - { value: 1, text: '朝阳区' }, - { value: 2, text: '海淀区' }, - { value: 3, text: '大兴区' }, - { value: 4, text: '东城区' }, - { value: 5, text: '西城区' }, - { value: 6, text: '丰台区' }, - ], - }, - { - value: 2, - text: '上海市', - children: [], - }, + [ + { + value: 1, + label: '北京', + children: [ + { + value: 1, + label: '朝阳区', + }, + { + value: 2, + label: '海淀区', + }, + { + value: 3, + label: '大兴区', + }, + { + value: 4, + label: '东城区', + }, + { + value: 5, + label: '西城区', + }, + { + value: 6, + label: '丰台区', + }, + ], + }, + { + value: 2, + label: '上海', + children: [], + }, + ], ]) - const updateChooseValueCustmer = ( - options: PickerOption[], - values: (string | number)[], - columnIndex: number - ) => { - console.log('updateChooseValueCustmer', columnIndex, values, options) - if (columnIndex === 0 && values[0] === 2) { + const updateChooseValueCustmer = ({ + value, + index, + selectedOptions, + }: PickerOnChangeCallbackParameter) => { + if (value[0] === 2 && asyncData[0]?.[1].children.length === 0) { + console.log('updateChooseValueCustmer', index, value, selectedOptions) setTimeout(() => { - if (asyncData[1].children.length === 0) { - asyncData[1].children = [ - { - value: 1, - text: '黄埔区', - }, - { - value: 2, - text: '长宁区', - }, - { - value: 3, - text: '普陀区', - }, - { - value: 4, - text: '杨浦区', - }, - { - value: 5, - text: '浦东新区', - }, - ] - setAsyncData([...asyncData]) - } - }, 100) + asyncData[0][1].children = [ + { + value: 1, + label: '黄埔区', + }, + { + value: 2, + label: '长宁区', + }, + { + value: 3, + label: '普陀区', + }, + { + value: 4, + label: '杨浦区', + }, + { + value: 5, + label: '浦东新区', + }, + ] + setAsyncData([...[...asyncData]]) + }, 0) } } const setAsyncConfirm = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { - const str = options.map((item) => item.text).join('-') - setasyncDesc(str) + console.log('onconfirm', selectedOptions, selectedValue) + const city = selectedOptions + .map((item: PickerOption) => item.label) + .join('-') + setasyncDesc(city) + setValue(selectedValue) } return ( @@ -81,18 +104,14 @@ const Demo7 = () => { description={asyncDesc} onClick={() => setIsVisible(!isVisible)} /> + setIsVisible(false)} - onConfirm={(list, values) => setAsyncConfirm(list, values)} - onChange={( - selectedOptions: PickerOption[], - selectedValue: (string | number)[], - columnIndex: number - ) => - updateChooseValueCustmer(selectedOptions, selectedValue, columnIndex) - } + onConfirm={setAsyncConfirm} + onChange={updateChooseValueCustmer} /> ) diff --git a/src/packages/picker/demos/taro/demo8.tsx b/src/packages/picker/demos/taro/demo8.tsx index 029c6a2d79..5cb9b00514 100644 --- a/src/packages/picker/demos/taro/demo8.tsx +++ b/src/packages/picker/demos/taro/demo8.tsx @@ -1,50 +1,47 @@ import React, { useState } from 'react' -import { Picker, Cell, ConfigProvider } from '@nutui/nutui-react-taro' +import { + Picker, + Cell, + ConfigProvider, + PickerOption, + PickerOptions, + PickerValue, +} from '@nutui/nutui-react-taro' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo8 = () => { - const [isVisible, setIsVisible] = useState(false) + const [visible, setVisible] = useState(false) + const [baseDesc, setBaseDesc] = useState('') const options = [ [ - { value: 1, text: '南京市' }, - { value: 2, text: '无锡市' }, - { value: 3, text: '海北藏族自治区' }, - { value: 4, text: '北京市' }, - { value: 5, text: '连云港市' }, - { value: 8, text: '大庆市' }, - { value: 9, text: '绥化市' }, - { value: 10, text: '潍坊市' }, - { value: 12, text: '乌鲁木齐市' }, + { value: 1, label: '南京市' }, + { value: 2, label: '无锡市' }, + { value: 3, label: '海北藏族自治区' }, + { value: 4, label: '北京市' }, + { value: 5, label: '连云港市' }, + { value: 8, label: '大庆市' }, + { value: 9, label: '绥化市' }, + { value: 10, label: '潍坊市' }, + { value: 12, label: '乌鲁木齐市' }, ], ] - const [baseDesc, setBaseDesc] = useState('') - const confirmPicker = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { - console.log('demo 确定', options, values) + console.log('confirmPicker', selectedOptions, selectedValue) let description = '' - options.forEach((option: any) => { - description += ` ${option.text}` + selectedOptions.forEach((option: PickerOption) => { + description += ` ${option.label}` }) setBaseDesc(description) - setIsVisible(false) } - return ( <> setIsVisible(!isVisible)} + onClick={() => setVisible(!visible)} /> { }} > confirmPicker(list, values)} - onClose={() => { - setIsVisible(false) - console.log('onclose') - }} + onConfirm={confirmPicker} + onClose={() => setVisible(false)} /> diff --git a/src/packages/picker/index.taro.ts b/src/packages/picker/index.taro.ts index 2dc0c9af3c..6f6691f2b3 100644 --- a/src/packages/picker/index.taro.ts +++ b/src/packages/picker/index.taro.ts @@ -1,5 +1,4 @@ import Picker from './picker.taro' -export type { PickerOption } from './types' export type { PickerProps } from './types.taro' export default Picker diff --git a/src/packages/picker/index.ts b/src/packages/picker/index.ts index 266c22b803..1314b31597 100644 --- a/src/packages/picker/index.ts +++ b/src/packages/picker/index.ts @@ -1,4 +1,4 @@ import Picker from './picker' -export type { PickerOption, PickerProps } from './types' +export type { PickerProps } from './types' export default Picker diff --git a/src/packages/picker/picker.scss b/src/packages/picker/picker.scss index 6516efc1bf..a95a838b80 100644 --- a/src/packages/picker/picker.scss +++ b/src/packages/picker/picker.scss @@ -6,11 +6,12 @@ &-control { display: flex; - height: $popup-title-height; - font-size: $popup-title-font-size; align-items: center; justify-content: space-between; + height: $popup-title-height; padding: $popup-title-padding; + box-sizing: border-box; + font-size: $popup-title-font-size; } &-cancel-btn { @@ -36,135 +37,5 @@ &-panel { display: flex; - position: relative; - } - - &-indicator { - position: absolute; - top: 108px; - height: $picker-item-height; - width: 100%; - border: $picker-item-active-line-border; - border-left: 0; - border-right: 0; - color: $picker-item-text-color; - font-size: $picker-item-text-font-size; - z-index: 3; - - &-taro { - height: $picker-item-height; - border: 0; - - &::before, - &::after { - border: $picker-item-active-line-border; - border-left: 0; - border-right: 0; - } - } - } - - &-list { - flex: 1; - position: relative; - height: $picker-list-height; - overflow: hidden; - text-align: center; - } - - &-list-panel { - transform-style: preserve-3d; - } - - &-mask { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-image: $picker-mask-background; - background-position: top, bottom; - background-size: 100% 108px; - background-repeat: no-repeat; - transform: translateZ(0); - z-index: 3; - } - - &-view-panel { - height: $picker-list-height; - flex-grow: 1; - } - - &-content, - &-roller { - position: absolute; - top: 108px; - width: 100%; - height: $picker-item-height; - } - - &-content { - background: #fff; - z-index: 2; - overflow: hidden; - } - - &-item, - &-roller-item { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - height: $picker-item-height; - line-height: $picker-item-height; - color: $picker-item-text-color; - font-size: $picker-item-text-font-size; - text-align: center; - } - - &-item { - font-size: 16px; - background: #fff; } - - &-roller { - z-index: 1; - transform-style: preserve-3d; - } - - &-roller-item { - backface-visibility: hidden; - -moz-backface-visibility: hidden; - -webkit-backface-visibility: hidden; - position: absolute; - top: 0; - width: 100%; - } - - &-roller-item-title { - display: block; - width: 100%; - height: $picker-item-height; - line-height: $picker-item-height; - text-align: center; - color: $color-title; - font-size: $font-size-base; - } - - &-roller-item-hidden { - visibility: hidden; - opacity: 0; - } - - &-placeholder { - height: 1px; - } -} - -[dir='rtl'] .nut-picker-mask, -.nut-rtl .nut-picker-mask { - background-image: var( - --picker-mask-background, - linear-gradient(-180deg, var(--nutui-white-12), var(--nutui-white-7)), - linear-gradient(0deg, var(--nutui-white-12), var(--nutui-white-7)) - ); } diff --git a/src/packages/picker/picker.taro.tsx b/src/packages/picker/picker.taro.tsx index 14283dbfe7..4f5651654f 100644 --- a/src/packages/picker/picker.taro.tsx +++ b/src/packages/picker/picker.taro.tsx @@ -5,36 +5,34 @@ import React, { ForwardRefRenderFunction, useImperativeHandle, } from 'react' +import { View } from '@tarojs/components' import classNames from 'classnames' -import Taro from '@tarojs/taro' -import { View, PickerView, PickerViewColumn } from '@tarojs/components' +import isEqual from 'react-fast-compare' +import { + PickerOptions, + PickerValue, + PickerOnChangeCallbackParameter, +} from '@/packages/pickerview/types' +import PickerView from '@/packages/pickerview/index.taro' import Popup from '@/packages/popup/index.taro' -import PickerPanel from './pickerpanel.taro' +import SafeArea from '@/packages/safearea/index.taro' import useRefs from '@/hooks/use-refs' import { useConfig } from '@/packages/configprovider/index.taro' -import { PickerOption } from './types' import { usePropsValue } from '@/hooks/use-props-value' import { ComponentDefaults } from '@/utils/typings' +import { PickerActions, PickerRef } from './types' import { PickerProps } from './types.taro' -export type PickerActions = { - open: () => void - close: () => void -} - const defaultProps = { ...ComponentDefaults, - visible: false, title: '', options: [], - value: [], + value: undefined, defaultValue: [], - threeDimensional: true, closeOnOverlayClick: true, - duration: 1000, } as unknown as PickerProps const InternalPicker: ForwardRefRenderFunction< - unknown, + PickerRef, Partial > = (props, ref) => { const { locale } = useConfig() @@ -53,37 +51,29 @@ const InternalPicker: ForwardRefRenderFunction< onConfirm, onCancel, onClose, - afterClose, onChange, ...rest } = { ...defaultProps, ...props } const classPrefix = 'nut-picker' const classes = classNames(classPrefix, className) - const [selectedValue, setSelectedValue] = usePropsValue< - Array - >({ + const [selectedValue, setSelectedValue] = usePropsValue({ value: props.value, defaultValue: [...defaultValue], finalValue: [...defaultValue], - onChange: (val) => { - props.onConfirm?.(setSelectedOptions(), val) + onChange: (value: PickerValue[]) => { + props.onConfirm?.(selectedOptionsRef.current, value) }, }) const [innerVisible, setInnerVisible] = usePropsValue({ value: props.visible, defaultValue: false, finalValue: false, - onChange: (val: boolean) => { - props.onClose?.(setSelectedOptions(), innerValue) + onChange: (v: boolean) => { + if (!v) { + props.onClose?.(selectedOptionsRef.current, innerValue) + } }, }) - const [innerValue, setInnerValue] = useState(selectedValue) - const [currentValue, setCurrentValue] = useState([]) - const [columnIndex, setColumnIndex] = useState(0) // 选中列 - const pickerRef = useRef(null) - const [refs, setRefs] = useRefs() - const [columnsList, setColumnsList] = useState([]) // 格式化后每一列的数据 - const isConfirmEvent = useRef(false) const actions: PickerActions = { open: () => { @@ -93,190 +83,56 @@ const InternalPicker: ForwardRefRenderFunction< setInnerVisible(false) }, } - useImperativeHandle(ref, () => actions) - // 级联数据格式化 - const formatCascade = ( - columns: PickerOption[], - values: (number | string)[] - ) => { - const formatted: PickerOption[][] = [] - let columnOptions: PickerOption = { - text: '', - value: '', - children: columns, - } - - let columnIndex = 0 - while (columnOptions && columnOptions.children) { - const options: PickerOption[] = columnOptions.children - const value = values[columnIndex] - let index = options.findIndex((columnItem) => columnItem.value === value) - if (index === -1) index = 0 - columnOptions = columnOptions.children[index] - columnIndex++ - formatted.push(options) - } - return formatted - } - - // 数据类型:多列、嵌套、单列 - const columnsType = () => { - const firstColumn: PickerOption | PickerOption[] = options[0] - if (firstColumn) { - if (Array.isArray(firstColumn)) { - return 'multiple' - } - if ('children' in firstColumn) { - return 'cascade' - } - } - return 'single' - } - - // 传入的数据格式化 - const normalListData = (innerValue: any) => { - const type = columnsType() - switch (type) { - case 'multiple': - return options - case 'cascade': - // 级联数据处理 - return formatCascade(options as PickerOption[], innerValue) - default: - return [options] - } - } - const init = () => { - const normalData: PickerOption[][] = normalListData( - innerValue - ) as PickerOption[][] - setColumnsList(normalData) - // 初始化默认选中数据 - const data: (string | number)[] = [] - normalData.length > 0 && - normalData.map((item) => { - item[0] && data.push(item[0].value) - return item - }) - if (!innerValue.length && innerValue.length === 0) { - setInnerValue([...data]) - } - } - - useEffect(() => { - setInnerValue(innerValue !== selectedValue ? selectedValue : innerValue) - }, [innerVisible, selectedValue]) + const [innerValue, setInnerValue] = useState([...selectedValue]) + const innerValueRef = useRef(innerValue) + const [innerOptions, setInnerOptions] = useState([]) + const selectedOptionsRef = useRef([] as PickerOptions) + const [refs, setRefs] = useRefs() useEffect(() => { if (innerVisible) { - init() + setInnerValue(selectedValue) + setInnerOptions(options as PickerOptions[]) } - }, [options, innerVisible]) - - // 选中值进行修改 - useEffect(() => { - if (!innerVisible) { - return + }, [selectedValue, innerOptions, innerVisible]) + + const onChangeItem = ({ + value, + index, + selectedOptions, + }: PickerOnChangeCallbackParameter) => { + if (selectedOptions?.length) { + selectedOptionsRef.current = selectedOptions } - Taro.getEnv() !== 'WEB' && setCurrentValue(defaultValuesConvert()) - onChange && onChange(setSelectedOptions(), innerValue, columnIndex) - }, [innerValue, columnsList, innerVisible]) - - const setSelectedOptions = () => { - const options: PickerOption[] = [] - let currOptions = [] - columnsList.forEach((columnOptions: PickerOption[], index: number) => { - currOptions = columnOptions.filter( - (item) => item.value === innerValue[index] - ) - if (currOptions[0]) { - options.push(currOptions[0]) - } else { - columnOptions[0] && options.push(columnOptions[0]) - } - }) - return options - } - - const defaultValuesConvert = () => { - const defaultIndexs: number[] = [] - if (innerValue.length > 0) { - innerValue.forEach((value, index) => { - for (let i = 0; i < columnsList?.[index]?.length; i++) { - if (columnsList[index][i].value === value) { - defaultIndexs.push(i) - break - } - } + if (isEqual(value, innerValueRef.current)) return + innerValueRef.current = value + setInnerValue(value) + innerVisible && + onChange?.({ + selectedOptions, + value, + index, }) - } else if (columnsList && columnsList.length > 0) { - columnsList.forEach((item) => { - defaultIndexs.push(0) - item.length > 0 && selectedValue.push(item[0].value) - }) - } - - return defaultIndexs } - // 更新已选择数据 - const chooseItem = (columnOptions: PickerOption, columnIndex: number) => { - const values: any = [] - const start = columnIndex - if (columnOptions && Object.keys(columnOptions).length) { - // 切换数据后,数据有变动才触发。 - if (values[columnIndex] !== columnOptions.value) { - if (columnsType() === 'cascade') { - values[columnIndex] = columnOptions.value || '' - while (columnOptions?.children?.[0]) { - values[columnIndex + 1] = columnOptions.children[0].value - columnIndex++ - columnOptions = columnOptions.children[0] - } - // 当前改变列的下一列 children 值为空 - if (columnOptions?.children?.length) { - values[columnIndex + 1] = '' - } - const combineResult = [ - ...innerValue.slice(0, start), - ...values.splice(start), - ] - setInnerValue(combineResult) - setColumnsList(normalListData(combineResult) as PickerOption[][]) - } else { - setInnerValue((data: (number | string)[]) => { - const cdata: (number | string)[] = [...data] - cdata[columnIndex] = Object.prototype.hasOwnProperty.call( - columnOptions, - 'value' - ) - ? columnOptions.value - : '' - return cdata - }) - } - setColumnIndex(columnIndex) - } - } - } - // 点击确定 - const confirm = () => { + const onConfirmEvent = () => { let moving = false refs.forEach((ref: any) => { if (ref.moving) moving = true ref.stopMomentum() }) - if (moving) { - isConfirmEvent.current = true - } else { + if (!moving) { setSelectedValue(innerValue, true) setInnerVisible(false) } - setTimeout(() => { - isConfirmEvent.current = false - }, 0) + } + + const onCancelEvent = () => { + setInnerValue(selectedValue) + onCancel?.() + setInnerVisible(false) } const renderTitleBar = () => { @@ -284,10 +140,9 @@ const InternalPicker: ForwardRefRenderFunction< { + onClick={(e: { stopPropagation: () => void }) => { e.stopPropagation() - onCancel?.() - setInnerVisible(false) + onCancelEvent() }} > {locale?.cancel} @@ -295,9 +150,9 @@ const InternalPicker: ForwardRefRenderFunction< {title || ''} { + onClick={(e: { stopPropagation: () => void }) => { e.stopPropagation() - confirm() + onConfirmEvent() }} > {locale.confirm} @@ -306,32 +161,28 @@ const InternalPicker: ForwardRefRenderFunction< ) } - const [, setPickingStatus] = useState(false) - - const pickerStart = () => { - setPickingStatus(true) - } - - const pickerEnd = () => { - setPickingStatus(false) - } - - const pickerChange = (data: any) => { - const prevDefaultValue = currentValue - let changeIndex = 0 - // 判断变化的是第几个 - const list = data.detail.value - for (let i = 0, len = list.length; i < len; i++) { - if (prevDefaultValue[i] !== list[i]) { - changeIndex = i - break - } - } - - // 选择的是哪个 option - chooseItem( - columnsList[changeIndex][data.detail.value[changeIndex]], - changeIndex + const renderPickerElement = () => { + return ( + + {renderTitleBar()} + {typeof children !== 'function' && children} + + { + onChangeItem({ value, index, selectedOptions }) + }} + /> + + ) } @@ -343,72 +194,16 @@ const InternalPicker: ForwardRefRenderFunction< visible={innerVisible} position="bottom" onOverlayClick={() => { - if (closeOnOverlayClick) { - props.onCancel?.() - setInnerVisible(false) - } - }} - afterClose={() => { - afterClose?.(setSelectedOptions(), innerValue, pickerRef) + if (!closeOnOverlayClick) return + onCancelEvent() }} > - - {renderTitleBar()} - {typeof children !== 'function' && children} - - {Taro.getEnv() === 'WEB' ? ( - columnsList?.map((item, index) => { - return ( - - chooseItem(value, index) - } - duration={duration} - key={index} - keyIndex={index} - itemShow={visible} - /> - ) - }) - ) : ( - - {columnsList?.map((columnOptions, index) => { - return ( - - {columnOptions.map((item, index) => { - return ( - - <>{item.text} - - ) - })} - - ) - })} - - )} - - + {innerVisible ? <>{renderPickerElement()} : null} + ) } -const Picker = React.forwardRef>(InternalPicker) +const Picker = React.forwardRef>(InternalPicker) export default Picker diff --git a/src/packages/picker/picker.tsx b/src/packages/picker/picker.tsx index e8faab6f04..6477f9d83c 100644 --- a/src/packages/picker/picker.tsx +++ b/src/packages/picker/picker.tsx @@ -6,32 +6,31 @@ import React, { useImperativeHandle, } from 'react' import classNames from 'classnames' +import isEqual from 'react-fast-compare' +import { + PickerOptions, + PickerValue, + PickerOnChangeCallbackParameter, +} from '@/packages/pickerview/types' +import PickerView from '@/packages/pickerview/index' import Popup from '@/packages/popup/index' -import { SafeArea } from '@/packages/safearea/safearea' -import PickerPanel from './pickerpanel' +import SafeArea from '@/packages/safearea/index' import useRefs from '@/hooks/use-refs' import { useConfig } from '@/packages/configprovider' -import { PickerOption, PickerProps } from './types' import { usePropsValue } from '@/hooks/use-props-value' import { ComponentDefaults } from '@/utils/typings' - -export type PickerActions = { - open: () => void - close: () => void -} +import { PickerActions, PickerProps, PickerRef } from './types' const defaultProps = { ...ComponentDefaults, title: '', options: [], - value: [], + value: undefined, defaultValue: [], - threeDimensional: true, closeOnOverlayClick: true, - duration: 1000, } as unknown as PickerProps const InternalPicker: ForwardRefRenderFunction< - unknown, + PickerRef, Partial > = (props, ref) => { const { locale } = useConfig() @@ -50,36 +49,29 @@ const InternalPicker: ForwardRefRenderFunction< onConfirm, onCancel, onClose, - afterClose, onChange, ...rest } = { ...defaultProps, ...props } const classPrefix = 'nut-picker' const classes = classNames(classPrefix, className) - const [selectedValue, setSelectedValue] = usePropsValue< - Array - >({ + const [selectedValue, setSelectedValue] = usePropsValue({ value: props.value, defaultValue: [...defaultValue], finalValue: [...defaultValue], - onChange: (val: (string | number)[]) => { - props.onConfirm?.(setSelectedOptions(), val) + onChange: (value: PickerValue[]) => { + props.onConfirm?.(selectedOptionsRef.current, value) }, }) const [innerVisible, setInnerVisible] = usePropsValue({ value: props.visible, defaultValue: false, finalValue: false, - onChange: (val: boolean) => { - props.onClose?.(setSelectedOptions(), innerValue) + onChange: (v: boolean) => { + if (!v) { + props.onClose?.(selectedOptionsRef.current, innerValue) + } }, }) - const [innerValue, setInnerValue] = useState(selectedValue) - const [columnIndex, setColumnIndex] = useState(0) // 选中列 - const pickerRef = useRef(null) - const [refs, setRefs] = useRefs() - const [columnsList, setColumnsList] = useState([]) // 格式化后每一列的数据 - const isConfirmEvent = useRef(false) const actions: PickerActions = { open: () => { @@ -89,164 +81,56 @@ const InternalPicker: ForwardRefRenderFunction< setInnerVisible(false) }, } - useImperativeHandle(ref, () => actions) - // 级联数据格式化 - const formatCascade = ( - columns: PickerOption[], - values: (number | string)[] - ) => { - const formatted: PickerOption[][] = [] - let columnOptions: PickerOption = { - text: '', - value: '', - children: columns, - } - - let columnIndex = 0 - while (columnOptions && columnOptions.children) { - const options: PickerOption[] = columnOptions.children - const value = values[columnIndex] - let index = options.findIndex((columnItem) => columnItem.value === value) - if (index === -1) index = 0 - columnOptions = columnOptions.children[index] - columnIndex++ - formatted.push(options) - } - return formatted - } - - // 数据类型:多列、嵌套、单列 - const columnsType = () => { - const firstColumn: PickerOption | PickerOption[] = options[0] - if (firstColumn) { - if (Array.isArray(firstColumn)) { - return 'multiple' - } - if ('children' in firstColumn) { - return 'cascade' - } - } - return 'single' - } - - // 传入的数据格式化 - const normalListData = (innerValue: any) => { - const type = columnsType() - switch (type) { - case 'multiple': - return options - case 'cascade': - // 级联数据处理 - return formatCascade(options as PickerOption[], innerValue) - default: - return [options] - } - } - const init = () => { - const normalData: PickerOption[][] = normalListData( - innerValue - ) as PickerOption[][] - setColumnsList(normalData) - // 初始化默认选中数据 - const data: (string | number)[] = [] - normalData.length > 0 && - normalData.map((item) => { - item[0] && data.push(item[0].value) - return item - }) - if (!innerValue.length && innerValue.length === 0) { - setInnerValue([...data]) - } - } - - useEffect(() => { - setInnerValue(innerValue !== selectedValue ? selectedValue : innerValue) - }, [innerVisible, selectedValue]) + const [innerValue, setInnerValue] = useState([...selectedValue]) + const innerValueRef = useRef(innerValue) + const [innerOptions, setInnerOptions] = useState([]) + const selectedOptionsRef = useRef([] as PickerOptions) + const [refs, setRefs] = useRefs() useEffect(() => { if (innerVisible) { - init() + setInnerValue(selectedValue) + setInnerOptions(options as PickerOptions[]) } - }, [options, innerVisible]) - - // 选中值进行修改 - useEffect(() => { - onChange && onChange(setSelectedOptions(), innerValue, columnIndex) - }, [innerValue, columnsList]) - - const setSelectedOptions = () => { - const options: PickerOption[] = [] - let currOptions = [] - columnsList.forEach((columnOptions: PickerOption[], index: number) => { - currOptions = columnOptions.filter( - (item) => item.value === innerValue[index] - ) - if (currOptions[0]) { - options.push(currOptions[0]) - } else { - columnOptions[0] && options.push(columnOptions[0]) - } - }) - return options - } - - // 更新已选择数据 - const chooseItem = (columnOptions: PickerOption, columnIndex: number) => { - const values: any = [] - const start = columnIndex - if (columnOptions && Object.keys(columnOptions).length) { - // 切换数据后,数据有变动才触发。 - if (values[columnIndex] !== columnOptions.value) { - if (columnsType() === 'cascade') { - values[columnIndex] = columnOptions.value || '' - while (columnOptions?.children?.[0]) { - values[columnIndex + 1] = columnOptions.children[0].value - columnIndex++ - columnOptions = columnOptions.children[0] - } - // 当前改变列的下一列 children 值为空 - if (columnOptions?.children?.length) { - values[columnIndex + 1] = '' - } - const combineResult = [ - ...innerValue.slice(0, start), - ...values.splice(start), - ] - setInnerValue(combineResult) - setColumnsList(normalListData(combineResult) as PickerOption[][]) - } else { - setInnerValue((data: (number | string)[]) => { - const cdata: (number | string)[] = [...data] - cdata[columnIndex] = Object.prototype.hasOwnProperty.call( - columnOptions, - 'value' - ) - ? columnOptions.value - : '' - return cdata - }) - } - setColumnIndex(columnIndex) - } + }, [selectedValue, innerOptions, innerVisible]) + + const onChangeItem = ({ + value, + index, + selectedOptions, + }: PickerOnChangeCallbackParameter) => { + if (selectedOptions?.length) { + selectedOptionsRef.current = selectedOptions } + if (isEqual(value, innerValueRef.current)) return + innerValueRef.current = value + setInnerValue(value) + innerVisible && + onChange?.({ + selectedOptions, + value, + index, + }) } - const confirm = () => { + + const onConfirmEvent = () => { let moving = false refs.forEach((ref: any) => { if (ref.moving) moving = true ref.stopMomentum() }) - if (moving) { - isConfirmEvent.current = true - } else { + if (!moving) { setSelectedValue(innerValue, true) setInnerVisible(false) } - setTimeout(() => { - isConfirmEvent.current = false - }, 0) + } + + const onCancelEvent = () => { + setInnerValue(selectedValue) + onCancel?.() + setInnerVisible(false) } const renderTitleBar = () => { @@ -256,8 +140,7 @@ const InternalPicker: ForwardRefRenderFunction< className={`${classPrefix}-cancel-btn`} onClick={(e) => { e.stopPropagation() - onCancel?.() - setInnerVisible(false) + onCancelEvent() }} > {locale?.cancel} @@ -267,7 +150,7 @@ const InternalPicker: ForwardRefRenderFunction< className={`${classPrefix}-confirm-btn`} onClick={(e) => { e.stopPropagation() - confirm() + onConfirmEvent() }} > {locale.confirm} @@ -276,50 +159,49 @@ const InternalPicker: ForwardRefRenderFunction< ) } + const renderPickerElement = () => { + return ( +
+ {renderTitleBar()} + {typeof children !== 'function' && children} +
+ { + onChangeItem({ value, index, selectedOptions }) + }} + /> +
+
+ ) + } return ( <> {typeof children === 'function' && children(selectedValue)} + { - if (closeOnOverlayClick) { - props.onCancel?.() - setInnerVisible(false) - } - }} - afterClose={() => { - afterClose?.(setSelectedOptions(), innerValue, pickerRef) + if (!closeOnOverlayClick) return + onCancelEvent() }} > -
- {renderTitleBar()} - {typeof children !== 'function' && children} -
- {columnsList?.map((item, index) => { - return ( - - chooseItem(value, index) - } - duration={duration} - key={index} - keyIndex={index} - /> - ) - })} -
-
+ {innerVisible ? <>{renderPickerElement()} : null}
) } -const Picker = React.forwardRef>(InternalPicker) +const Picker = React.forwardRef>(InternalPicker) export default Picker diff --git a/src/packages/picker/pickerpanel.taro.tsx b/src/packages/picker/pickerpanel.taro.tsx deleted file mode 100644 index 0ecb888d61..0000000000 --- a/src/packages/picker/pickerpanel.taro.tsx +++ /dev/null @@ -1,322 +0,0 @@ -import React, { - useState, - useEffect, - useRef, - ForwardRefRenderFunction, - useImperativeHandle, -} from 'react' -import { View } from '@tarojs/components' -import { PickerOption } from './types' -import { useTouch } from '@/hooks/use-touch' -import { getRectByTaro } from '@/utils/get-rect-by-taro' -import { passiveSupported } from '@/utils/supports-passive' - -interface PickerPanelProps { - keyIndex?: number - defaultValue?: string | number - options?: PickerOption[] - threeDimensional: boolean - duration: number | string - itemShow: boolean - chooseItem?: (val: PickerOption, idx: number) => void -} - -const InternalPickerPanel: ForwardRefRenderFunction< - { stopMomentum: () => void; moving: boolean }, - Partial -> = (props, ref) => { - const { - keyIndex = 0, - defaultValue, - options = [], - threeDimensional = true, - duration = 1000, - itemShow = false, - chooseItem, - } = props - - const touch = useTouch() - const DEFAULT_DURATION = 200 - // 触发惯性滑动条件: - // 在手指离开屏幕时,如果和上一次 move 时的间隔小于 `MOMENTUM_TIME` 且 move - // 距离大于 `MOMENTUM_DISTANCE` 时,执行惯性滑动 - const INERTIA_TIME = 300 - const INERTIA_DISTANCE = 15 - const [currIndex, setCurrIndex] = useState(1) - const lineSpacing = useRef(36) - const [touchTime, setTouchTime] = useState(0) - const [touchDeg, setTouchDeg] = useState('0deg') - const rotation = 20 - const moving = useRef(false) - let timer: number | undefined - - const listRef = useRef(null) - const rollerRef = useRef(null) - const pickerPanelRef = useRef(null) - - const [startTime, setStartTime] = useState(0) - const [startY, setStartY] = useState(0) - - const transformY = useRef(0) - const [scrollDistance, setScrollDistance] = useState(0) - - const isHidden = (index: number) => { - if (index >= currIndex + 8 || index <= currIndex - 8) { - return true - } - return false - } - - const setTransform = ( - type: string, - deg: string, - time = DEFAULT_DURATION, - translateY = 0 - ) => { - let nTime = time - if (type !== 'end') { - nTime = 0 - } - setTouchTime(nTime) - setTouchDeg(deg) - setScrollDistance(translateY) - } - - const setMove = (move: number, type?: string, time?: number) => { - let updateMove = move + transformY.current - if (type === 'end') { - // 限定滚动距离 - if (updateMove > 0) { - updateMove = 0 - } - if (updateMove < -(options.length - 1) * lineSpacing.current) { - updateMove = -(options.length - 1) * lineSpacing.current - } - - // 设置滚动距离为lineSpacing的倍数值 - const endMove = - Math.round(updateMove / lineSpacing.current) * lineSpacing.current - const deg = `${ - (Math.abs(Math.round(endMove / lineSpacing.current)) + 1) * rotation - }deg` - - setTransform(type, deg, time, endMove) - setCurrIndex(Math.abs(Math.round(endMove / lineSpacing.current)) + 1) - } else { - let deg = 0 - const currentDeg = (-updateMove / lineSpacing.current + 1) * rotation - - // picker 滚动的最大角度 - const maxDeg = (options.length + 1) * rotation - const minDeg = 0 - deg = Math.min(Math.max(currentDeg, minDeg), maxDeg) - - if (minDeg < deg && deg < maxDeg) { - setTransform('', `${deg}deg`, undefined, updateMove) - setCurrIndex(Math.abs(Math.round(updateMove / lineSpacing.current)) + 1) - } - } - } - - const setChooseValue = (move: number) => { - chooseItem?.(options?.[Math.round(-move / lineSpacing.current)], keyIndex) - } - - // 开始滚动 - const touchStart = (event: React.TouchEvent) => { - touch.start(event) - setStartY(touch.deltaY.current) - setStartTime(Date.now()) - transformY.current = scrollDistance - } - - const touchMove = (event: React.TouchEvent) => { - touch.move(event) - if ((touch as any).isVertical) { - moving.current = true - preventDefault(event, true) - } - const move = touch.deltaY.current - startY - setMove(move) - } - - const touchEnd = () => { - if (!moving.current) return - const move = touch.deltaY.current - startY - const moveTime = Date.now() - startTime - // 区分是否为惯性滚动 - if (moveTime <= INERTIA_TIME && Math.abs(move) > INERTIA_DISTANCE) { - // 惯性滚动 - const distance = momentum(move, moveTime) - setMove(distance, 'end', +duration) - } else { - setMove(move, 'end') - } - setTimeout(() => { - touch.reset() - }, 0) - } - - // 惯性滚动 距离 - const momentum = (distance: number, duration: number) => { - let nDistance = distance - // 惯性滚动的速度 - const speed = Math.abs(nDistance / duration) - // 惯性滚动的距离 - nDistance = (speed / 0.003) * (nDistance < 0 ? -1 : 1) - return nDistance - } - - const modifyStatus = (type?: boolean, val?: string | number) => { - const value = val || defaultValue - let index = -1 - if (value) { - options.some((item, idx) => { - if (item.value === value) { - index = idx - return true - } - return false - }) - } else { - options.forEach((item, i) => { - if (item.value === defaultValue) { - index = i - } - }) - } - - setCurrIndex(index === -1 ? 1 : index + 1) - const move = index === -1 ? 0 : index * lineSpacing.current - type && setChooseValue(-move) - setMove(-move) - } - - // 惯性滚动结束 - const stopMomentum = () => { - moving.current = false - setTouchTime(0) - setChooseValue(scrollDistance) - } - // 阻止默认事件 - const preventDefault = ( - event: React.TouchEvent, - isStopPropagation?: boolean - ) => { - event.preventDefault() - if (isStopPropagation) { - event.stopPropagation() - } - } - - const getReference = async () => { - const refe = await getRectByTaro(listRef?.current) - lineSpacing.current = refe.height ? refe.height : 36 - } - - const touchRollerStyle = () => { - return { - transition: `transform ${touchTime}ms cubic-bezier(0.17, 0.89, 0.45, 1)`, - transform: `rotate3d(1, 0, 0, ${touchDeg})`, - } - } - const touchTileStyle = () => { - return { - transition: `transform ${touchTime}ms cubic-bezier(0.17, 0.89, 0.45, 1)`, - transform: `translate3d(0, ${scrollDistance}px, 0)`, - } - } - - useEffect(() => { - setScrollDistance(0) - transformY.current = 0 - modifyStatus(false) - return () => { - clearTimeout(timer) - } - }, [options]) - - useEffect(() => { - if (itemShow) { - setTimeout(() => { - getReference() - }, 200) - } - }, [itemShow]) - - useImperativeHandle(ref, () => ({ - stopMomentum, - moving: moving.current, - })) - - useEffect(() => { - const eventOptions = passiveSupported - ? { passive: false, once: true } - : false - const element = pickerPanelRef.current - element.addEventListener('touchstart', touchStart, eventOptions) - element.addEventListener('touchmove', touchMove, eventOptions) - element.addEventListener('touchend', touchEnd, eventOptions) - return () => { - element.removeEventListener('touchstart', touchStart, eventOptions) - element.removeEventListener('touchmove', touchMove, eventOptions) - element.removeEventListener('touchend', touchEnd, eventOptions) - } - }) - - return ( - - - {/* 3D 效果 */} - {threeDimensional && - options.map((item, index) => { - return ( - - <>{item.text} - - ) - })} - {/* 平铺 */} - {!threeDimensional && - options.map((item, index) => { - return ( - - <>{item.text} - - ) - })} - - - - - ) -} -const PickerPanel = React.forwardRef< - { stopMomentum: () => void; moving: boolean }, - Partial ->(InternalPickerPanel) -export default PickerPanel diff --git a/src/packages/picker/pickerpanel.tsx b/src/packages/picker/pickerpanel.tsx deleted file mode 100644 index efe7e986fe..0000000000 --- a/src/packages/picker/pickerpanel.tsx +++ /dev/null @@ -1,305 +0,0 @@ -import React, { - useState, - useEffect, - useRef, - ForwardRefRenderFunction, - useImperativeHandle, -} from 'react' -import { PickerOption } from './types' -import { useTouch } from '@/hooks/use-touch' -import { passiveSupported } from '@/utils/supports-passive' - -interface PickerPanelProps { - keyIndex?: number - defaultValue?: string | number - options?: PickerOption[] - threeDimensional: boolean - duration: number | string - chooseItem?: (val: PickerOption, idx: number) => void -} - -const InternalPickerPanel: ForwardRefRenderFunction< - { stopMomentum: () => void; moving: boolean }, - Partial -> = (props, ref) => { - const { - keyIndex = 0, - defaultValue, - options = [], - threeDimensional = true, - duration = 1000, - chooseItem, - } = props - - const touch = useTouch() - const DEFAULT_DURATION = 200 - // 触发惯性滑动条件: - // 在手指离开屏幕时,如果和上一次 move 时的间隔小于 `MOMENTUM_TIME` 且 move - // 距离大于 `MOMENTUM_DISTANCE` 时,执行惯性滑动 - const INERTIA_TIME = 300 - const INERTIA_DISTANCE = 15 - const [currIndex, setCurrIndex] = useState(1) - const lineSpacing = 36 - const [touchTime, setTouchTime] = useState(0) - const [touchDeg, setTouchDeg] = useState('0deg') - const rotation = 20 - const moving = useRef(false) - let timer: number | undefined - - const rollerRef = useRef(null) - const PickerPanelRef = useRef(null) - - const [startTime, setStartTime] = useState(0) - const [startY, setStartY] = useState(0) - - const transformY = useRef(0) - const [scrollDistance, setScrollDistance] = useState(0) - - const isHidden = (index: number) => { - if (index >= currIndex + 8 || index <= currIndex - 8) { - return true - } - return false - } - - const setTransform = ( - type: string, - deg: string, - time = DEFAULT_DURATION, - translateY = 0 - ) => { - let nTime = time - if (type !== 'end') { - nTime = 0 - } - setTouchTime(nTime) - setTouchDeg(deg) - setScrollDistance(translateY) - } - - const setMove = (move: number, type?: string, time?: number) => { - let updateMove = move + transformY.current - if (type === 'end') { - // 限定滚动距离 - if (updateMove > 0) { - updateMove = 0 - } - if (updateMove < -(options.length - 1) * lineSpacing) { - updateMove = -(options.length - 1) * lineSpacing - } - - // 设置滚动距离为lineSpacing的倍数值 - const endMove = Math.round(updateMove / lineSpacing) * lineSpacing - const deg = `${ - (Math.abs(Math.round(endMove / lineSpacing)) + 1) * rotation - }deg` - - setTransform(type, deg, time, endMove) - setCurrIndex(Math.abs(Math.round(endMove / lineSpacing)) + 1) - } else { - let deg = 0 - const currentDeg = (-updateMove / lineSpacing + 1) * rotation - - // picker 滚动的最大角度 - const maxDeg = (options.length + 1) * rotation - const minDeg = 0 - - deg = Math.min(Math.max(currentDeg, minDeg), maxDeg) - - if (minDeg < deg && deg < maxDeg) { - setTransform('', `${deg}deg`, undefined, updateMove) - setCurrIndex(Math.abs(Math.round(updateMove / lineSpacing)) + 1) - } - } - } - - const setChooseValue = (move: number) => { - chooseItem?.(options?.[Math.round(-move / lineSpacing)], keyIndex) - } - - // 开始滚动 - const touchStart = (event: React.TouchEvent) => { - touch.start(event) - setStartY(touch.deltaY.current) - setStartTime(Date.now()) - transformY.current = scrollDistance - } - - const touchMove = (event: React.TouchEvent) => { - touch.move(event) - if ((touch as any).isVertical) { - moving.current = true - preventDefault(event, true) - } - const move = touch.deltaY.current - startY - setMove(move) - } - - const touchEnd = () => { - if (!moving.current) return - const move = touch.deltaY.current - startY - const moveTime = Date.now() - startTime - // 区分是否为惯性滚动 - if (moveTime <= INERTIA_TIME && Math.abs(move) > INERTIA_DISTANCE) { - // 惯性滚动 - const distance = momentum(move, moveTime) - setMove(distance, 'end', +duration) - } else { - setMove(move, 'end') - } - setTimeout(() => { - touch.reset() - }, 0) - } - - // 惯性滚动 距离 - const momentum = (distance: number, duration: number) => { - let nDistance = distance - // 惯性滚动的速度 - const speed = Math.abs(nDistance / duration) - // 惯性滚动的距离 - nDistance = (speed / 0.003) * (nDistance < 0 ? -1 : 1) - return nDistance - } - - const modifyStatus = (type?: boolean, val?: string | number) => { - const value = val || defaultValue - let index = -1 - if (value) { - options.some((item, idx) => { - if (item.value === value) { - index = idx - return true - } - return false - }) - } else { - options.forEach((item, i) => { - if (item.value === defaultValue) { - index = i - } - }) - } - - setCurrIndex(index === -1 ? 1 : index + 1) - const move = index === -1 ? 0 : index * lineSpacing - type && setChooseValue(-move) - setMove(-move) - } - - // 惯性滚动结束 - const stopMomentum = () => { - moving.current = false - setTouchTime(0) - setChooseValue(scrollDistance) - } - // 阻止默认事件 - const preventDefault = ( - event: React.TouchEvent, - isStopPropagation?: boolean - ) => { - /* istanbul ignore else */ - if (typeof event.cancelable !== 'boolean' || event.cancelable) { - event.preventDefault() - } - - if (isStopPropagation) { - event.stopPropagation() - } - } - - const touchRollerStyle = () => { - return { - transition: `transform ${touchTime}ms cubic-bezier(0.17, 0.89, 0.45, 1)`, - transform: `rotate3d(1, 0, 0, ${touchDeg})`, - } - } - const touchTileStyle = () => { - return { - transition: `transform ${touchTime}ms cubic-bezier(0.17, 0.89, 0.45, 1)`, - transform: `translate3d(0, ${scrollDistance}px, 0)`, - } - } - - useEffect(() => { - setScrollDistance(0) - transformY.current = 0 - modifyStatus(false) - return () => { - clearTimeout(timer) - } - }, [options]) - - useImperativeHandle(ref, () => ({ - stopMomentum, - moving: moving.current, - })) - - useEffect(() => { - const options = passiveSupported ? { passive: false } : false - PickerPanelRef.current?.addEventListener('touchstart', touchStart, options) - PickerPanelRef.current?.addEventListener('touchmove', touchMove, options) - PickerPanelRef.current?.addEventListener('touchend', touchEnd, options) - return () => { - PickerPanelRef.current?.removeEventListener('touchstart', touchStart) - PickerPanelRef.current?.removeEventListener('touchmove', touchMove) - PickerPanelRef.current?.removeEventListener('touchend', touchEnd) - } - }) - - return ( -
-
- {/* 3D 效果 */} - {threeDimensional && - options.map((item, index) => { - return ( -
- <>{item.text} -
- ) - })} - {/* 平铺 */} - {!threeDimensional && - options.map((item, index) => { - return ( -
- <>{item.text} -
- ) - })} -
-
-
-
- ) -} -const PickerPanel = React.forwardRef< - { stopMomentum: () => void; moving: boolean }, - Partial ->(InternalPickerPanel) -export default PickerPanel diff --git a/src/packages/picker/types.ts b/src/packages/picker/types.ts index f59149fe30..147341b1c5 100644 --- a/src/packages/picker/types.ts +++ b/src/packages/picker/types.ts @@ -1,45 +1,42 @@ -import { RefObject } from 'react' -import { PopupProps } from '../popup/types' +import { PopupProps } from '@/packages/popup/types' import { BasicComponent } from '@/utils/typings' +import { + PickerOnChangeCallbackParameter, + PickerOption, + PickerOptions, + PickerValue, +} from '@/packages/pickerview/types' -export interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number +export type PickerRef = PickerActions +export type PickerActions = { + open: () => void + close: () => void } +export type ColumnsType = 'single' | 'multiple' | 'cascade' export interface PickerProps extends Omit { visible?: boolean | undefined title?: string - options: (PickerOption | PickerOption[])[] - value?: (number | string)[] - defaultValue?: (number | string)[] + options: PickerOptions[] + value?: PickerValue[] + defaultValue?: PickerValue[] threeDimensional?: boolean duration: number | string closeOnOverlayClick: boolean + renderLabel?: (item: PickerOption) => React.ReactNode + popupProps: Partial< Omit > onConfirm?: ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => void onCancel?: () => void onClose?: ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[] - ) => void - afterClose?: ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[], - pickerRef: RefObject - ) => void - onChange?: ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[], - columnIndex: number + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => void + onChange?: (args0: PickerOnChangeCallbackParameter) => void children?: any } diff --git a/src/packages/pickerview/__test__/pickerview.spec.tsx b/src/packages/pickerview/__test__/pickerview.spec.tsx index 5dfd175869..6f67fe5c6c 100644 --- a/src/packages/pickerview/__test__/pickerview.spec.tsx +++ b/src/packages/pickerview/__test__/pickerview.spec.tsx @@ -133,7 +133,7 @@ test('should render with Multi Column', () => { test('should match onchange', async () => { const PenderContent = () => { - const [value, setValue] = useState([]) + const [value, setValue] = useState([] as number[]) const [options, setInnerOptions] = useState([]) useEffect(() => { diff --git a/src/packages/pickerview/doc.en-US.md b/src/packages/pickerview/doc.en-US.md index 42006732bd..0193489639 100644 --- a/src/packages/pickerview/doc.en-US.md +++ b/src/packages/pickerview/doc.en-US.md @@ -71,13 +71,13 @@ import { PickerView } from '@nutui/nutui-react' | duration | The duration of inertial rolling during rapid sliding, in ms | `string` \| `number` | `1000` | | onChange | Called when the value of each column changes | `({value, index, selectedOptions}) => void` | `-` | -### PickerOptionItem +### PickerOption | Property | Description | Type | Default | | --- | --- | --- | --- | | label | Text of column | `string` \| `number` | `-` | | value | Value of column | `string` \| `number` | `-` | -| children | Cascader Option | `PickerOptionItem[]` | `-` | +| children | Cascader Option | `PickerOptions` | `-` | ## Theming diff --git a/src/packages/pickerview/doc.md b/src/packages/pickerview/doc.md index ef3cb7dc18..378d917da3 100644 --- a/src/packages/pickerview/doc.md +++ b/src/packages/pickerview/doc.md @@ -71,13 +71,13 @@ import { PickerView } from '@nutui/nutui-react' | duration | 快速滑动时惯性滚动的时长,单位 ms | `string` \| `number` | `1000` | | onChange | 每一列值变更时调用 | `({value, index, selectedOptions}) => void` | `-` | -### PickerOptionItem +### PickerOption | 属性 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | | label | 选项的文字内容 | `string` \| `number` | `-` | | value | 选项对应的值,且唯一 | `string` \| `number` | `-` | -| children | 用于级联选项 | `PickerOptionItem[]` | `-` | +| children | 用于级联选项 | `PickerOptions` | `-` | ## 主题定制 diff --git a/src/packages/pickerview/doc.taro.md b/src/packages/pickerview/doc.taro.md index 344fc9dee3..cc0bcb4e1d 100644 --- a/src/packages/pickerview/doc.taro.md +++ b/src/packages/pickerview/doc.taro.md @@ -71,13 +71,13 @@ import { PickerView } from '@nutui/nutui-react-taro' | duration | 快速滑动时惯性滚动的时长,单位 ms | `string` \| `number` | `1000` | | onChange | 每一列值变更时调用 | `({value, index, selectedOptions}) => void` | `-` | -### PickerOptionItem +### PickerOption | 属性 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | | label | 选项的文字内容 | `string` \| `number` | `-` | | value | 选项对应的值,且唯一 | `string` \| `number` | `-` | -| children | 用于级联选项 | `PickerOptionItem[]` | `-` | +| children | 用于级联选项 | `PickerOptions` | `-` | ## 主题定制 diff --git a/src/packages/pickerview/doc.zh-TW.md b/src/packages/pickerview/doc.zh-TW.md index 073f5b8e4f..cfe5e7360e 100644 --- a/src/packages/pickerview/doc.zh-TW.md +++ b/src/packages/pickerview/doc.zh-TW.md @@ -71,13 +71,13 @@ import { PickerView } from '@nutui/nutui-react-taro' | duration | 快速滑動時慣性滾動的時長,單位 ms | `string` \| `number` | `1000` | | onChange | 每一列值變更時調用 | `({value, index, selectedOptions}) => void` | `-` | -### PickerOptionItem +### PickerOption | 屬性 | 說明 | 類型 | 默認值 | | --- | --- | --- | --- | | label | 選項的文字內容 | `string` \| `number` | `-` | | value | 選項對應的值,且唯一 | `string` \| `number` | `-` | -| children | 用於級聯選項 | `PickerOptionItem[]` | `-` | +| children | 用於級聯選項 | `PickerOptions` | `-` | ## 主題定制 diff --git a/src/packages/pickerview/index.taro.ts b/src/packages/pickerview/index.taro.ts index 1bd5f2a397..8d492244e8 100644 --- a/src/packages/pickerview/index.taro.ts +++ b/src/packages/pickerview/index.taro.ts @@ -2,7 +2,7 @@ import PickerView from './pickerview.taro' export type { PickerViewProps, - PickerOptionItem, + PickerOption, PickerRollerProps, PickerValue, PickerOptions, diff --git a/src/packages/pickerview/index.ts b/src/packages/pickerview/index.ts index 15c781a272..bff2bf6714 100644 --- a/src/packages/pickerview/index.ts +++ b/src/packages/pickerview/index.ts @@ -2,7 +2,7 @@ import PickerView from './pickerview' export type { PickerViewProps, - PickerOptionItem, + PickerOption, PickerRollerProps, PickerValue, PickerOptions, diff --git a/src/packages/pickerview/pickerroller.taro.tsx b/src/packages/pickerview/pickerroller.taro.tsx index 10c38d145f..2acf57c520 100644 --- a/src/packages/pickerview/pickerroller.taro.tsx +++ b/src/packages/pickerview/pickerroller.taro.tsx @@ -8,7 +8,7 @@ import React, { import { View } from '@tarojs/components' import { useTouch } from '@/hooks/use-touch' import { passiveSupported } from '@/utils/supports-passive' -import { PickerRollerProps, PickerOptionItem } from './types' +import { PickerRollerProps, PickerOption } from './types' import { web } from '@/utils/platform-taro' import { preventDefault } from '@/utils' import { momentum, useStyles } from './utils' @@ -23,7 +23,7 @@ const InternalPickerRoller: ForwardRefRenderFunction< threeDimensional = true, duration = 1000, onSelect, - renderLabel = (item: PickerOptionItem) => item.label, + renderLabel = (item: PickerOption) => item.label, } = props const DEFAULT_DURATION = 200 @@ -132,7 +132,9 @@ const InternalPickerRoller: ForwardRefRenderFunction< const updateStatus = (shouldSelect?: boolean, value?: string | number) => { const selectedValue = value || props.value - const index = options.findIndex((item) => item.value === selectedValue) + const index = options.findIndex( + (item: PickerOption) => item.value === selectedValue + ) setCurrentIndex(index === -1 ? 1 : index + 1) const move = index * lineSpacing.current shouldSelect && selectValue(-move) @@ -223,7 +225,7 @@ const InternalPickerRoller: ForwardRefRenderFunction< > {/* 3D 效果 */} {threeDimensional && - options.map((item, index) => ( + options.map((item: PickerOption, index: number) => ( { + options.map((item: PickerOption, index: number) => { return ( item.label, + renderLabel = (item: PickerOption) => item.label, } = props const DEFAULT_DURATION = 200 @@ -130,7 +130,9 @@ const InternalPickerRoller: ForwardRefRenderFunction< const updateStatus = (shouldSelect?: boolean, value?: string | number) => { const selectedValue = value || props.value - const index = options.findIndex((item) => item.value === selectedValue) + const index = options.findIndex( + (item: PickerOption) => item.value === selectedValue + ) setCurrentIndex(index === -1 ? 1 : index + 1) const move = index * lineSpacing.current shouldSelect && selectValue(-move) @@ -210,7 +212,7 @@ const InternalPickerRoller: ForwardRefRenderFunction< > {/* 3D */} {threeDimensional && - options.map((item, index) => ( + options.map((item: PickerOption, index: number) => (
( + options.map((item: PickerOption, index: number) => (
item.label, + renderLabel: (item: PickerOption) => item.label, } as PickerViewProps const InternalPickerView: ForwardRefRenderFunction< @@ -77,7 +77,7 @@ const InternalPickerView: ForwardRefRenderFunction< if (!options.length) return [] // 如果 options 为空,直接返回空数组 const formatted: PickerOptions[] = [] - let columnOptions: PickerOptionItem = { + let columnOptions: PickerOption = { label: '', value: '', children: options, @@ -95,7 +95,7 @@ const InternalPickerView: ForwardRefRenderFunction< } else if (currentValue) { // 如果 currentValue 存在,查找匹配的项 const index = currentOptions.findIndex( - (columnItem) => columnItem.value === currentValue + (columnItem: PickerOption) => columnItem.value === currentValue ) columnOptions = currentOptions[index === -1 ? 0 : index] // 如果未找到,默认取第一个 } else { @@ -131,7 +131,7 @@ const InternalPickerView: ForwardRefRenderFunction< }, [selectedValue]) const handleSelect = useCallback( - (option: PickerOptionItem, index: number) => { + (option: PickerOption, index: number) => { const newValue = option?.value if (!newValue || innerValue[index] === newValue) return changeIndex.current = index @@ -159,7 +159,7 @@ const InternalPickerView: ForwardRefRenderFunction< ...values.splice(startIndex), ] setInnerValue([...combineResult]) - const optionFirst = props?.options?.[0] as PickerOptionItem[] + const optionFirst = props?.options?.[0] as PickerOptions if ( !isEqual( formatCascadeOptions(optionFirst, combineResult), @@ -177,12 +177,12 @@ const InternalPickerView: ForwardRefRenderFunction< return innerOptions .map((columnOptions, index) => { const selectedOption = columnOptions.find( - (item) => item.value === innerValue[index] + (item: PickerOption) => item.value === innerValue[index] ) return selectedOption // return selectedOption || columnOptions[0] }) - .filter(Boolean) as PickerOptionItem[] + .filter(Boolean) as PickerOptions }, [innerOptions, innerValue]) useEffect(() => { diff --git a/src/packages/pickerview/pickerview.tsx b/src/packages/pickerview/pickerview.tsx index 0fef411bea..fbf2189c52 100644 --- a/src/packages/pickerview/pickerview.tsx +++ b/src/packages/pickerview/pickerview.tsx @@ -12,7 +12,7 @@ import { ComponentDefaults } from '@/utils/typings' import { usePropsValue } from '@/hooks/use-props-value' import { PickerViewProps, - PickerOptionItem, + PickerOption, PickerValue, PickerOptions, } from './types' @@ -23,7 +23,7 @@ const defaultProps = { options: [], defaultValue: [], value: undefined, - renderLabel: (item: PickerOptionItem) => item.label, + renderLabel: (item: PickerOption) => item.label, } as PickerViewProps const InternalPickerView: ForwardRefRenderFunction< @@ -76,7 +76,7 @@ const InternalPickerView: ForwardRefRenderFunction< if (!options.length) return [] // 如果 options 为空,直接返回空数组 const formatted: PickerOptions[] = [] - let columnOptions: PickerOptionItem = { + let columnOptions: PickerOption = { label: '', value: '', children: options, @@ -94,7 +94,7 @@ const InternalPickerView: ForwardRefRenderFunction< } else if (currentValue) { // 如果 currentValue 存在,查找匹配的项 const index = currentOptions.findIndex( - (columnItem) => columnItem.value === currentValue + (columnItem: PickerOption) => columnItem.value === currentValue ) columnOptions = currentOptions[index === -1 ? 0 : index] // 如果未找到,默认取第一个 } else { @@ -130,7 +130,7 @@ const InternalPickerView: ForwardRefRenderFunction< }, [selectedValue]) const handleSelect = useCallback( - (option: PickerOptionItem, index: number) => { + (option: PickerOption, index: number) => { const newValue = option?.value if (!newValue || innerValue[index] === newValue) return changeIndex.current = index @@ -158,7 +158,7 @@ const InternalPickerView: ForwardRefRenderFunction< ...values.splice(startIndex), ] setInnerValue([...combineResult]) - const optionFirst = props?.options?.[0] as PickerOptionItem[] + const optionFirst = props?.options?.[0] as PickerOptions if ( !isEqual( formatCascadeOptions(optionFirst, combineResult), @@ -176,12 +176,12 @@ const InternalPickerView: ForwardRefRenderFunction< return innerOptions .map((columnOptions, index) => { const selectedOption = columnOptions.find( - (item) => item.value === innerValue[index] + (item: PickerOption) => item.value === innerValue[index] ) return selectedOption // return selectedOption || columnOptions[0] }) - .filter(Boolean) as PickerOptionItem[] + .filter(Boolean) as PickerOptions }, [innerOptions, innerValue]) useEffect(() => { diff --git a/src/packages/pickerview/types.ts b/src/packages/pickerview/types.ts index e25d83faf5..57efbd2b7e 100644 --- a/src/packages/pickerview/types.ts +++ b/src/packages/pickerview/types.ts @@ -2,28 +2,28 @@ import { BasicComponent } from '@/utils/typings' export type PickerValue = string | number | null -export interface PickerOptionItem { +export interface PickerOption { label: string | number value: string | number - children?: PickerOptionItem[] + children?: PickerOptions } -export type PickerOptions = PickerOptionItem[] +export type PickerOptions = PickerOption[] export interface PickerRollerProps { - options: PickerOptionItem[] + options: PickerOptions keyIndex: number value: PickerValue threeDimensional?: boolean duration?: number | string - onSelect: (option: PickerOptionItem, index: number) => void - renderLabel: (item: PickerOptionItem) => React.ReactNode + onSelect: (option: PickerOption, index: number) => void + renderLabel: (item: PickerOption) => React.ReactNode } export interface PickerOnChangeCallbackParameter { value: PickerValue[] index: number - selectedOptions: PickerOptionItem[] + selectedOptions: PickerOptions } export interface PickerViewProps extends BasicComponent { @@ -33,6 +33,6 @@ export interface PickerViewProps extends BasicComponent { defaultValue?: PickerValue[] threeDimensional?: boolean duration?: number | string - renderLabel: (item: PickerOptionItem) => React.ReactNode + renderLabel: (item: PickerOption) => React.ReactNode onChange?: (arg0: PickerOnChangeCallbackParameter) => void } diff --git a/src/packages/popover/demos/h5/demo4-1.tsx b/src/packages/popover/demos/h5/demo4-1.tsx index 891b2f4928..0cced79b3d 100644 --- a/src/packages/popover/demos/h5/demo4-1.tsx +++ b/src/packages/popover/demos/h5/demo4-1.tsx @@ -1,15 +1,13 @@ import React, { useState } from 'react' -import { Popover, Cell, Picker, Toast } from '@nutui/nutui-react' +import { + Popover, + Cell, + Picker, + Toast, + PickerOnChangeCallbackParameter, +} from '@nutui/nutui-react' import { Tips, Close } from '@nutui/icons-react' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} - const Demo41 = () => { const [baseDesc, setBaseDesc] = useState('') const [showPicker, setShowPicker] = useState(false) @@ -17,12 +15,14 @@ const Demo41 = () => { const [curPostion, setCurPostion] = useState('') const columns = [ - { text: 'top', value: 'top' }, - { text: 'top-start', value: 'top-start' }, - { text: 'top-end', value: 'top-end' }, - { text: 'bottom', value: 'bottom' }, - { text: 'bottom-start', value: 'bottom-start' }, - { text: 'bottom-end', value: 'bottom-end' }, + [ + { label: 'top', value: 'top' }, + { label: 'top-start', value: 'top-start' }, + { label: 'top-end', value: 'top-end' }, + { label: 'bottom', value: 'bottom' }, + { label: 'bottom-start', value: 'bottom-start' }, + { label: 'bottom-end', value: 'bottom-end' }, + ], ] const positionList = [ { @@ -60,13 +60,13 @@ const Demo41 = () => { onConfirm={(list) => { let description = '' list.forEach((option: any) => { - description += ` ${option.text}` + description += ` ${option.label}` }) setBaseDesc(description) }} - onChange={(options: PickerOption[]) => { - if (options[0]?.value) { - setCurPostion(options[0].value as string) + onChange={({ selectedOptions }: PickerOnChangeCallbackParameter) => { + if (selectedOptions[0]?.value) { + setCurPostion(selectedOptions[0].value as string) } }} onClose={() => { diff --git a/src/packages/popover/demos/h5/demo4.tsx b/src/packages/popover/demos/h5/demo4.tsx index 27ce80a3c9..d75b9bb232 100644 --- a/src/packages/popover/demos/h5/demo4.tsx +++ b/src/packages/popover/demos/h5/demo4.tsx @@ -1,13 +1,10 @@ import React, { useState } from 'react' -import { Popover, Cell, Picker } from '@nutui/nutui-react' - -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} +import { + Popover, + Cell, + Picker, + PickerOnChangeCallbackParameter, +} from '@nutui/nutui-react' const Demo4 = () => { const [baseDesc, setBaseDesc] = useState('') @@ -16,18 +13,20 @@ const Demo4 = () => { const [curPostion, setCurPostion] = useState('') const columns = [ - { text: 'top', value: 'top' }, - { text: 'top-start', value: 'top-start' }, - { text: 'top-end', value: 'top-end' }, - { text: 'right', value: 'right' }, - { text: 'right-start', value: 'right-start' }, - { text: 'right-end', value: 'right-end' }, - { text: 'bottom', value: 'bottom' }, - { text: 'bottom-start', value: 'bottom-start' }, - { text: 'bottom-end', value: 'bottom-end' }, - { text: 'left', value: 'left' }, - { text: 'left-start', value: 'left-start' }, - { text: 'left-end', value: 'left-end' }, + [ + { label: 'top', value: 'top' }, + { label: 'top-start', value: 'top-start' }, + { label: 'top-end', value: 'top-end' }, + { label: 'right', value: 'right' }, + { label: 'right-start', value: 'right-start' }, + { label: 'right-end', value: 'right-end' }, + { label: 'bottom', value: 'bottom' }, + { label: 'bottom-start', value: 'bottom-start' }, + { label: 'bottom-end', value: 'bottom-end' }, + { label: 'left', value: 'left' }, + { label: 'left-start', value: 'left-start' }, + { label: 'left-end', value: 'left-end' }, + ], ] const positionList = [ { @@ -57,13 +56,13 @@ const Demo4 = () => { onConfirm={(list) => { let description = '' list.forEach((option: any) => { - description += ` ${option.text}` + description += ` ${option.label}` }) setBaseDesc(description) }} - onChange={(options: PickerOption[]) => { - if (options[0]?.value) { - setCurPostion(options[0].value as string) + onChange={({ selectedOptions }: PickerOnChangeCallbackParameter) => { + if (selectedOptions[0]?.value) { + setCurPostion(selectedOptions[0].value as string) } }} onClose={() => { diff --git a/src/packages/popover/demos/taro/demo4-1.tsx b/src/packages/popover/demos/taro/demo4-1.tsx index 04147e9466..5d3f4d4326 100644 --- a/src/packages/popover/demos/taro/demo4-1.tsx +++ b/src/packages/popover/demos/taro/demo4-1.tsx @@ -1,15 +1,14 @@ import React, { useState } from 'react' import { View } from '@tarojs/components' -import { Popover, Cell, Picker, Toast } from '@nutui/nutui-react-taro' +import { + Popover, + Cell, + Picker, + Toast, + PickerOnChangeCallbackParameter, +} from '@nutui/nutui-react-taro' import { Tips, Close } from '@nutui/icons-react-taro' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo4 = () => { const [baseDesc, setBaseDesc] = useState('') const [showPicker, setShowPicker] = useState(false) @@ -18,14 +17,16 @@ const Demo4 = () => { const [showToast, SetShowToast] = useState(false) const columns = [ - { text: 'top', value: 'top' }, - { text: 'top-start', value: 'top-start' }, - { text: 'top-end', value: 'top-end' }, - { text: 'right', value: 'right' }, - { text: 'bottom', value: 'bottom' }, - { text: 'bottom-start', value: 'bottom-start' }, - { text: 'bottom-end', value: 'bottom-end' }, - { text: 'left', value: 'left' }, + [ + { label: 'top', value: 'top' }, + { label: 'top-start', value: 'top-start' }, + { label: 'top-end', value: 'top-end' }, + { label: 'right', value: 'right' }, + { label: 'bottom', value: 'bottom' }, + { label: 'bottom-start', value: 'bottom-start' }, + { label: 'bottom-end', value: 'bottom-end' }, + { label: 'left', value: 'left' }, + ], ] const positionList = [ { @@ -63,13 +64,13 @@ const Demo4 = () => { onConfirm={(list) => { let description = '' list.forEach((option: any) => { - description += ` ${option.text}` + description += ` ${option.label}` }) setBaseDesc(description) }} - onChange={(options: PickerOption[]) => { - if (options[0]?.value) { - setCurPostion(options[0].value as string) + onChange={({ selectedOptions }: PickerOnChangeCallbackParameter) => { + if (selectedOptions[0]?.value) { + setCurPostion(selectedOptions[0].value as string) } }} onClose={() => { diff --git a/src/packages/popover/demos/taro/demo4.tsx b/src/packages/popover/demos/taro/demo4.tsx index 633170b9aa..430160cf20 100644 --- a/src/packages/popover/demos/taro/demo4.tsx +++ b/src/packages/popover/demos/taro/demo4.tsx @@ -1,14 +1,12 @@ import React, { useState } from 'react' import { View } from '@tarojs/components' -import { Popover, Cell, Picker } from '@nutui/nutui-react-taro' +import { + Popover, + Cell, + Picker, + PickerOnChangeCallbackParameter, +} from '@nutui/nutui-react-taro' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo4 = () => { const [baseDesc, setBaseDesc] = useState('') const [showPicker, setShowPicker] = useState(false) @@ -16,18 +14,20 @@ const Demo4 = () => { const [curPostion, setCurPostion] = useState('') const columns = [ - { text: 'top', value: 'top' }, - { text: 'top-start', value: 'top-start' }, - { text: 'top-end', value: 'top-end' }, - { text: 'right', value: 'right' }, - { text: 'right-start', value: 'right-start' }, - { text: 'right-end', value: 'right-end' }, - { text: 'bottom', value: 'bottom' }, - { text: 'bottom-start', value: 'bottom-start' }, - { text: 'bottom-end', value: 'bottom-end' }, - { text: 'left', value: 'left' }, - { text: 'left-start', value: 'left-start' }, - { text: 'left-end', value: 'left-end' }, + [ + { label: 'top', value: 'top' }, + { label: 'top-start', value: 'top-start' }, + { label: 'top-end', value: 'top-end' }, + { label: 'right', value: 'right' }, + { label: 'right-start', value: 'right-start' }, + { label: 'right-end', value: 'right-end' }, + { label: 'bottom', value: 'bottom' }, + { label: 'bottom-start', value: 'bottom-start' }, + { label: 'bottom-end', value: 'bottom-end' }, + { label: 'left', value: 'left' }, + { label: 'left-start', value: 'left-start' }, + { label: 'left-end', value: 'left-end' }, + ], ] const positionList = [ { @@ -57,13 +57,13 @@ const Demo4 = () => { onConfirm={(list) => { let description = '' list.forEach((option: any) => { - description += ` ${option.text}` + description += ` ${option.label}` }) setBaseDesc(description) }} - onChange={(options: PickerOption[]) => { - if (options[0]?.value) { - setCurPostion(options[0].value as string) + onChange={({ selectedOptions }: PickerOnChangeCallbackParameter) => { + if (selectedOptions[0]?.value) { + setCurPostion(selectedOptions[0].value as string) } }} onClose={() => {