diff --git a/components/cascader/__docs__/theme/index.tsx b/components/cascader/__docs__/theme/index.tsx index 6b96b11d68..bc10393c85 100644 --- a/components/cascader/__docs__/theme/index.tsx +++ b/components/cascader/__docs__/theme/index.tsx @@ -4,6 +4,7 @@ import '../../../demo-helper/style'; import '../../style'; import { Demo, DemoGroup, initDemo } from '../../../demo-helper'; import Cascader from '../../index'; +import { CascaderDataItem } from '../../types'; const i18nMap = { 'en-us': { @@ -14,8 +15,8 @@ const i18nMap = { }, }; -const createDataSource = (label, hasDisabled) => { - const dataSource = [ +const createDataSource = (label: unknown, hasDisabled?: boolean) => { + const dataSource: CascaderDataItem[] = [ { children: [ { @@ -6080,7 +6081,7 @@ const createDataSource = (label, hasDisabled) => { return dataSource; }; -function render(lang = 'en-us') { +function render(lang: keyof typeof i18nMap = 'en-us') { const i18n = i18nMap[lang]; const dataSource = createDataSource(i18n.option); const disabledDataSource = createDataSource(i18n.option, true); diff --git a/components/cascader/cascader.tsx b/components/cascader/cascader.tsx index 14421ce8ca..8b34b9ef9e 100644 --- a/components/cascader/cascader.tsx +++ b/components/cascader/cascader.tsx @@ -1,4 +1,4 @@ -import React, { Component, type ComponentType, type FocusEvent } from 'react'; +import React, { Component, type ReactElement, type FocusEvent, type ComponentType } from 'react'; import PropTypes from 'prop-types'; import { polyfill } from 'react-lifecycles-compat'; import cloneDeep from 'lodash.clonedeep'; @@ -181,7 +181,7 @@ class Cascader extends Component { immutable, } = props; - const { v2n, p2n } = preHandleData(dataSource, immutable); + const { v2n, p2n } = preHandleData(dataSource!, immutable); let normalizedValue = normalizeValue(typeof value === 'undefined' ? defaultValue : value); @@ -222,7 +222,7 @@ class Cascader extends Component { } static getDerivedStateFromProps(props: CascaderProps, state: CascaderState) { - const { v2n, p2n } = preHandleData(props.dataSource, props.immutable); + const { v2n, p2n } = preHandleData(props.dataSource!, props.immutable); const states = {} as CascaderState; if ('value' in props) { @@ -553,7 +553,7 @@ class Cascader extends Component { const { dataSource, searchValue, filteredPaths } = this.props; return !searchValue - ? this.getFirstFocusKeyByDataSource(dataSource) + ? this.getFirstFocusKeyByDataSource(dataSource!) : this.getFirstFocusKeyByFilteredPaths(filteredPaths); } @@ -645,53 +645,64 @@ class Cascader extends Component { onItemFocus={this.handleFocus} onBlur={this.onBlur} > - {data - .map(item => { - const disabled = !!item.disabled; - const canExpand = - (!!item.children && !!item.children.length) || - (!!loadData && !item.isLeaf); - const expanded = expandedValue[level] === item.value; - const props: CascaderItemProps = { - prefix, - disabled, - canExpand, - expanded, - expandTriggerType, - onExpand: this.handleExpand.bind(this, item.value, level, canExpand), - onFold: this.handleFold, - }; - - if ('title' in item) { - props.title = item.title; - } + { + data! + .map(item => { + const disabled = !!item.disabled; + const canExpand = + (!!item.children && !!item.children.length) || + (!!loadData && !item.isLeaf); + const expanded = expandedValue[level] === item.value; + const props: CascaderItemProps = { + prefix, + disabled, + canExpand, + expanded, + expandTriggerType, + onExpand: this.handleExpand.bind( + this, + item.value, + level, + canExpand + ), + onFold: this.handleFold, + }; + + if ('title' in item) { + props.title = item.title; + } - if (multiple) { - props.checkable = !(canOnlyCheckLeaf && canExpand); - props.checked = value.indexOf(item.value) > -1 || !!item.checked; - props.indeterminate = - (checkStrictly || canOnlyCheckLeaf - ? false - : this.indeterminate.indexOf(item.value) > -1) || - !!item.indeterminate; - props.checkboxDisabled = !!item.checkboxDisabled; - props.onCheck = this.handleCheck.bind(this, item.value); - } else { - props.selected = value[0] === item.value; - props.onSelect = this.handleSelect.bind(this, item.value, canExpand); - } + if (multiple) { + props.checkable = !(canOnlyCheckLeaf && canExpand); + props.checked = value.indexOf(item.value) > -1 || !!item.checked; + props.indeterminate = + (checkStrictly || canOnlyCheckLeaf + ? false + : this.indeterminate.indexOf(item.value) > -1) || + !!item.indeterminate; + props.checkboxDisabled = !!item.checkboxDisabled; + props.onCheck = this.handleCheck.bind(this, item.value); + } else { + props.selected = value[0] === item.value; + props.onSelect = this.handleSelect.bind( + this, + item.value, + canExpand + ); + } - const itemContent = itemRender!(item, props); - if (itemContent === null) { - return null; - } - return ( - - {itemContent} - - ); - }) - .filter(v => v)} + const itemContent = itemRender!(item, props); + if (itemContent === null) { + return null; + } + return ( + + {itemContent} + + ); + }) + .filter(v => v) as ReactElement[] + } ); } @@ -728,8 +739,8 @@ class Cascader extends Component { const { value } = this.state; const lastItem = path[path.length - 1]; - let Item: ComponentType; - const props: CheckboxItemProps | ItemProps = { + let Item: ComponentType; + let props: CheckboxItemProps | ItemProps = { className: `${prefix}cascader-filtered-item`, disabled: path.some(item => item.disabled), children: resultRender!(searchValue!, path), @@ -738,20 +749,24 @@ class Cascader extends Component { if (multiple) { Item = Menu.CheckboxItem; const { checkStrictly, canOnlyCheckLeaf } = this.props; - (props as CheckboxItemProps).checked = value.indexOf(lastItem.value) > -1; - (props as CheckboxItemProps).indeterminate = - !checkStrictly && - !canOnlyCheckLeaf && - this.indeterminate.indexOf(lastItem.value) > -1; - (props as CheckboxItemProps).checkboxDisabled = lastItem.checkboxDisabled; - props.onChange = this.handleCheck.bind(this, lastItem.value); + props = { + ...props, + checked: value.indexOf(lastItem.value) > -1, + indeterminate: + !checkStrictly && + !canOnlyCheckLeaf && + this.indeterminate.indexOf(lastItem.value) > -1, + checkboxDisabled: lastItem.checkboxDisabled, + onChange: this.handleCheck.bind(this, lastItem.value), + }; } else { Item = Menu.Item; - // @ts-expect-error 这里的实现应该是有问题,只有 SelectableItem 才有 selected - (props as ItemProps).selected = value[0] === lastItem.value; - props.onSelect = this.handleSelect.bind(this, lastItem.value, false); + props = { + ...props, + selected: value[0] === lastItem.value, + onSelect: this.handleSelect.bind(this, lastItem.value, false), + }; } - return ; } diff --git a/components/cascader/index.tsx b/components/cascader/index.tsx index 9ca278f3a9..520630c486 100644 --- a/components/cascader/index.tsx +++ b/components/cascader/index.tsx @@ -1,7 +1,7 @@ import ConfigProvider from '../config-provider'; import Cascader from './cascader'; -export type { CascaderProps, CascaderDataItem, CascaderDataItemWithPosInfo } from './types'; +export type { CascaderProps, CascaderDataItem, CascaderDataItemWithPosInfo, Extra } from './types'; export default ConfigProvider.config(Cascader, { transform: (props, deprecated) => { diff --git a/components/cascader/item.tsx b/components/cascader/item.tsx index f3b8b5eafc..712d2fbde1 100644 --- a/components/cascader/item.tsx +++ b/components/cascader/item.tsx @@ -134,7 +134,7 @@ export default class CascaderMenuItem extends Component { } } - let Item: ComponentType, title; + let Item: ComponentType, title; if (checkable) { Item = Menu.CheckboxItem; (itemProps as CheckboxItemProps).checked = checked; @@ -143,7 +143,6 @@ export default class CascaderMenuItem extends Component { (itemProps as CheckboxItemProps).onChange = onCheck; } else { Item = Menu.Item; - // @ts-expect-error 这里的实现应该是有问题,只有 SelectableItem 才有 selected itemProps.selected = selected; itemProps.onSelect = onSelect; } diff --git a/components/cascader/menu.tsx b/components/cascader/menu.tsx index 4db1d4a686..fe0c399445 100644 --- a/components/cascader/menu.tsx +++ b/components/cascader/menu.tsx @@ -2,10 +2,8 @@ import React, { Component, type ReactNode, type LegacyRef, - type ReactElement, type ReactNodeArray, type ComponentElement, - JSXElementConstructor, } from 'react'; import PropTypes from 'prop-types'; import { findDOMNode } from 'react-dom'; @@ -34,7 +32,7 @@ export default class CascaderMenu extends Component { if (!children || (children as ReactNodeArray).length === 0) { return; } - const selectedIndex = (children as Array).findIndex( + const selectedIndex = children.findIndex( item => !!item.props.checked || !!item.props.selected || !!item.props.expanded ); diff --git a/components/cascader/types.ts b/components/cascader/types.ts index 2c35155755..08eb944398 100644 --- a/components/cascader/types.ts +++ b/components/cascader/types.ts @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { type ReactElement } from 'react'; import { CommonProps } from '../util'; import type { CheckboxItemProps, MenuProps, ItemProps as MenuItemProps } from '../menu'; @@ -38,9 +38,9 @@ export type NormalizeValueReturns = T extends undefined | null : [T]; /** - * @api extra + * @api Extra */ -type extra = { +export type Extra = { /** * 单选时选中的数据的路径 */ @@ -95,6 +95,7 @@ export interface ItemState { export interface CascaderMenuProps extends CommonProps, MenuProps { useVirtual?: boolean; + children: Array; } /** @@ -108,7 +109,7 @@ export interface CascaderProps * @en data source * @defaultValue [] */ - dataSource: Array; + dataSource?: Array; /** * (非受控)默认值 @@ -132,7 +133,7 @@ export interface CascaderProps onChange?: ( value: string | Array, data: CascaderDataItem | Array, - extra: extra + extra: Extra ) => void; /** @@ -143,7 +144,7 @@ export interface CascaderProps * @param data - 选中的数据,包括 value 和 label - selected data, including value and label * @param extra - 额外参数 - extra parameters */ - onSelect?: (v: string, data: CascaderDataItemWithPosInfo, extra: extra) => void; + onSelect?: (v: string, data: CascaderDataItemWithPosInfo, extra: Extra) => void; /** * (非受控)默认展开值 diff --git a/components/menu/index.d.ts b/components/menu/index.d.ts index 916474fc59..51c2f6703f 100644 --- a/components/menu/index.d.ts +++ b/components/menu/index.d.ts @@ -19,6 +19,10 @@ export interface ItemProps extends React.HTMLAttributes, CommonProp * 菜单项标签内容 */ children?: React.ReactNode; + /** + * 是否选中 + */ + selected?: boolean; menu?: any; }