diff --git a/packages/components/cascader/__tests__/cascader.spec.ts b/packages/components/cascader/__tests__/cascader.spec.ts
index 0bb3863cc..338da4e4b 100644
--- a/packages/components/cascader/__tests__/cascader.spec.ts
+++ b/packages/components/cascader/__tests__/cascader.spec.ts
@@ -212,6 +212,22 @@ describe('Cascader', () => {
expect(getAllOptionGroup(wrapper).length).toBe(3)
})
+
+ test('disableData work', async () => {
+ const wrapper = CascaderMount({
+ props: {
+ open: true,
+ disableData: data => data.key === 'button',
+ },
+ })
+
+ expect(getAllOptionGroup(wrapper)[2].find('.ix-cascader-option-disabled').text()).toBe('Button')
+
+ await wrapper.setProps({ disableData: (data: CascaderData) => data.key === 'pro' })
+
+ expect(getAllOptionGroup(wrapper)[2].find('.ix-cascader-option-disabled').exists()).toBe(false)
+ expect(getAllOptionGroup(wrapper)[0].find('.ix-cascader-option-disabled').text()).toBe('Pro')
+ })
})
describe('multiple work', () => {
diff --git a/packages/components/cascader/demo/Disabled.md b/packages/components/cascader/demo/Disabled.md
new file mode 100644
index 000000000..b50a6494d
--- /dev/null
+++ b/packages/components/cascader/demo/Disabled.md
@@ -0,0 +1,18 @@
+---
+title:
+ zh: 禁用状态
+ en: Disabled status
+order: 3
+---
+
+## zh
+
+可以设置 `disabled` 来禁用整个组件
+
+也可以设置 `disableData` 来动态禁用某些选项,它的优先级低于 `dataSource` 的 `disabled`
+
+## en
+
+You can set `disabled` to disable the cascader component.
+
+You can also set `disableData` to dynamically disable some options, which have a lower priority than `disabled` of `dataSource`.
diff --git a/packages/components/cascader/demo/Disabled.vue b/packages/components/cascader/demo/Disabled.vue
new file mode 100644
index 000000000..34f7778fb
--- /dev/null
+++ b/packages/components/cascader/demo/Disabled.vue
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/components/cascader/docs/Api.zh.md b/packages/components/cascader/docs/Api.zh.md
index 1f6df70f0..ccb17e4bb 100644
--- a/packages/components/cascader/docs/Api.zh.md
+++ b/packages/components/cascader/docs/Api.zh.md
@@ -19,6 +19,7 @@
| `customAdditional` | 自定义下拉选项的额外属性 | `CascaderCustomAdditional` | - | - | 例如 `class`, 或者原生事件 |
| `dataSource` | 树型数据数组,参见[CascaderData](#CascaderData) | `CascaderData[]` | `[]` | - | - |
| `disabled` | 禁用选择器 | `boolean` | - | - | - |
+| `disableData` | 动态禁用某些项 | `(data: CascaderData) => boolean` | - | - | - |
| `empty` | 空数据时的内容 | `'default' \| 'simple' \| EmptyProps` | `'simple'` | - | - |
| `expandIcon` | 展开图标 | `string \| #expandIcon="{key: VKey, expanded: boolean, data: CascaderData}"` | `right` | ✅ | - |
| `expandTrigger` | 触发展开的方式 | `'click' \| 'hover'` | `click` | - | - |
@@ -37,6 +38,7 @@
| `readonly` | 只读模式 | `boolean` | - | - | - |
| `searchable` | 是否可搜索 | `boolean \| 'overlay'` | `false` | - | 当为 `true` 时搜索功能集成在选择器上,当为 `overlay` 时,搜索功能集成在悬浮层上 |
| `searchFn` | 根据搜索的文本进行筛选 | `boolean \| SelectSearchFn` | `true` | - | 为 `true` 时使用默认的搜索规则, 如果使用远程搜索,应该设置为 `false` |
+| `separator` | 设置分割符 | `string` | `/` | - | - |
| `size` | 设置选择器大小 | `'sm' \| 'md' \| 'lg'` | `md` | ✅ | - |
| `status` | 手动指定校验状态 | `valid \| invalid \| validating` | - | - | - |
| `strategy` | 设置级联策略 | `'all' \| 'parent' \| 'child' \| 'off'` | `'all'` | - | 具体用法参见 [级联策略](#components-cascader-demo-Strategy) |
diff --git a/packages/components/cascader/src/Cascader.tsx b/packages/components/cascader/src/Cascader.tsx
index 3b597b115..632a4cc75 100644
--- a/packages/components/cascader/src/Cascader.tsx
+++ b/packages/components/cascader/src/Cascader.tsx
@@ -14,7 +14,7 @@ import { ɵSelector, type ɵSelectorInstance } from '@idux/components/_private/s
import { useGlobalConfig } from '@idux/components/config'
import { useFormItemRegister, useFormSize, useFormStatus } from '@idux/components/form'
import { ɵUseOverlayState } from '@idux/components/select'
-import { useGetKey } from '@idux/components/utils'
+import { useGetDisabled, useGetKey } from '@idux/components/utils'
import { useActiveState } from './composables/useActiveState'
import { useDataSource } from './composables/useDataSource'
@@ -41,6 +41,7 @@ export default defineComponent({
const mergedExpandIcon = computed(() => props.expandIcon ?? config.expandIcon)
const mergedFullPath = computed(() => props.fullPath ?? config.fullPath)
const mergedGetKey = useGetKey(props, config, 'components/cascader')
+ const mergedGetDisabled = useGetDisabled(props)
const mergedLabelKey = computed(() => props.labelKey ?? config.labelKey)
const triggerRef = ref<ɵSelectorInstance>()
@@ -68,11 +69,19 @@ export default defineComponent({
mergedFullPath,
)
const activeStateContext = useActiveState(props, mergedDataMap)
- const selectedStateContext = useSelectedState(props, accessor, mergedDataMap, mergedFullPath)
- const { searchedData } = useSearchable(props, mergedLabelKey, mergedDataMap, inputValue)
+ const selectedStateContext = useSelectedState(props, accessor, mergedDataMap, mergedFullPath, mergedGetDisabled)
+ const { searchedData } = useSearchable(
+ props,
+ mergedData,
+ mergedDataMap,
+ mergedLabelKey,
+ inputValue,
+ mergedGetDisabled,
+ )
const expandableContext = useExpandable(
props,
mergedGetKey,
+ mergedGetDisabled,
mergedChildrenKey,
mergedLabelKey,
mergedFullPath,
@@ -107,6 +116,7 @@ export default defineComponent({
mergedExpandIcon,
mergedFullPath,
mergedGetKey,
+ mergedGetDisabled,
mergedLabelKey,
accessor,
inputValue,
diff --git a/packages/components/cascader/src/composables/useDataSource.ts b/packages/components/cascader/src/composables/useDataSource.ts
index fab28b2d2..dc56e4508 100644
--- a/packages/components/cascader/src/composables/useDataSource.ts
+++ b/packages/components/cascader/src/composables/useDataSource.ts
@@ -65,9 +65,9 @@ export function convertMergedData(
parentKey?: VKey,
parentLabel?: string,
): MergedData[] {
- const { loadChildren } = props
+ const { loadChildren, separator } = props
return data.map(item =>
- convertMergedItem(item, getKey, childrenKey, labelKey, fullPath, !!loadChildren, parentKey, parentLabel),
+ convertMergedItem(item, getKey, childrenKey, labelKey, separator, fullPath, !!loadChildren, parentKey, parentLabel),
)
}
@@ -76,16 +76,19 @@ function convertMergedItem(
getKey: GetKeyFn,
childrenKey: string,
labelKey: string,
+ separator: string,
fullPath: boolean,
hasLoad: boolean,
parentKey?: VKey,
parentLabel?: string,
): MergedData {
const key = getKey(rawData)
- const label = (fullPath && !isNil(parentLabel) ? `${parentLabel}/${rawData[labelKey]}` : rawData[labelKey]) as string
+ const label = (
+ fullPath && !isNil(parentLabel) ? `${parentLabel}${separator}${rawData[labelKey]}` : rawData[labelKey]
+ ) as string
const subData = rawData[childrenKey] as CascaderData[] | undefined
const children = subData?.map(item =>
- convertMergedItem(item, getKey, childrenKey, labelKey, fullPath, hasLoad, key, label),
+ convertMergedItem(item, getKey, childrenKey, labelKey, separator, fullPath, hasLoad, key, label),
)
return {
children,
diff --git a/packages/components/cascader/src/composables/useExpandable.ts b/packages/components/cascader/src/composables/useExpandable.ts
index 6f7a562f1..094ebef01 100644
--- a/packages/components/cascader/src/composables/useExpandable.ts
+++ b/packages/components/cascader/src/composables/useExpandable.ts
@@ -10,7 +10,7 @@ import { type ComputedRef, type Ref, ref } from 'vue'
import { isNil } from 'lodash-es'
import { type VKey, callEmit, useControlledProp } from '@idux/cdk/utils'
-import { type GetKeyFn } from '@idux/components/utils'
+import { type GetDisabledFn, type GetKeyFn } from '@idux/components/utils'
import { type MergedData, convertMergedData, convertMergedDataMap } from './useDataSource'
import { type CascaderData, type CascaderProps } from '../types'
@@ -26,6 +26,7 @@ export interface ExpandableContext {
export function useExpandable(
props: CascaderProps,
mergedGetKey: ComputedRef,
+ mergedGetDisabled: ComputedRef,
mergedChildrenKey: ComputedRef,
mergedLabelKey: ComputedRef,
mergedFullPath: ComputedRef,
@@ -38,7 +39,7 @@ export function useExpandable(
}
const dataMap = mergedDataMap.value
const currData = dataMap.get(firstSelectedKey)
- return getParentKeys(dataMap, currData, false)
+ return getParentKeys(dataMap, currData, false, mergedGetDisabled.value)
}
const [expandedKeys, setExpandedKeys] = useControlledProp(props, 'expandedKeys', () =>
getDefaultExpandedKeys(selectedKeys.value[0]),
@@ -91,7 +92,7 @@ export function useExpandable(
if (!currExpanded) {
const dataMap = mergedDataMap.value
- const newKeys = getParentKeys(dataMap, dataMap.get(key), false)
+ const newKeys = getParentKeys(dataMap, dataMap.get(key), false, mergedGetDisabled.value)
newKeys.push(key)
handleChange(newKeys, !currExpanded, currData!.rawData)
}
diff --git a/packages/components/cascader/src/composables/useSearchable.ts b/packages/components/cascader/src/composables/useSearchable.ts
index bf5bd6af7..51e1e78e9 100644
--- a/packages/components/cascader/src/composables/useSearchable.ts
+++ b/packages/components/cascader/src/composables/useSearchable.ts
@@ -10,6 +10,7 @@ import { type ComputedRef, computed } from 'vue'
import { isFunction } from 'lodash-es'
import { NoopArray, type VKey } from '@idux/cdk/utils'
+import { type GetDisabledFn } from '@idux/components/utils'
import { type MergedData } from './useDataSource'
import { type CascaderData, type CascaderProps, type CascaderSearchFn } from '../types'
@@ -20,9 +21,11 @@ export interface SearchableContext {
export function useSearchable(
props: CascaderProps,
- mergedLabelKey: ComputedRef,
+ mergedData: ComputedRef,
mergedDataMap: ComputedRef