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>, + mergedLabelKey: ComputedRef, inputValue: ComputedRef, + mergedGetDisabled: ComputedRef, ): SearchableContext { const mergedSearchFn = useSearchFn(props, mergedLabelKey) const parentEnabled = computed(() => props.multiple || props.strategy === 'off') @@ -34,19 +37,9 @@ export function useSearchable( return NoopArray as unknown as VKey[] } const _parentEnabled = parentEnabled.value + const getDisabledFn = mergedGetDisabled.value const keySet = new Set() - mergedDataMap.value.forEach(data => { - const { key, rawData } = data - if (keySet.has(key)) { - return - } - if (searchFn(rawData, searchValue)) { - if (_parentEnabled || data.isLeaf) { - keySet.add(key) - } - processChildren(keySet, data, _parentEnabled) - } - }) + mergedData.value.forEach(data => doSearch(keySet, data, searchFn, searchValue, _parentEnabled, getDisabledFn)) return [...keySet] }) @@ -75,13 +68,35 @@ function getDefaultSearchFn(labelKey: string): CascaderSearchFn { } } -function processChildren(keySet: Set, data: MergedData, parentEnabled: boolean) { +function doSearch( + keySet: Set, + data: MergedData, + searchFn: CascaderSearchFn, + searchValue: string, + _parentEnabled: boolean, + getDisabledFn: GetDisabledFn, +) { + const { key, rawData } = data + if (keySet.has(key) || getDisabledFn(rawData)) { + return + } + if (searchFn(rawData, searchValue)) { + if (_parentEnabled || data.isLeaf) { + keySet.add(key) + } + processChildren(keySet, data, _parentEnabled, getDisabledFn) + } else if (data.children) { + data.children.forEach(child => doSearch(keySet, child, searchFn, searchValue, _parentEnabled, getDisabledFn)) + } +} + +function processChildren(keySet: Set, data: MergedData, parentEnabled: boolean, getDisabledFn: GetDisabledFn) { if (!data || !data.children) { return } data.children.forEach(child => { - if (child.rawData.disabled || keySet.has(child.key)) { + if (keySet.has(child.key) || getDisabledFn(child.rawData)) { return } @@ -89,6 +104,6 @@ function processChildren(keySet: Set, data: MergedData, parentEnabled: boo keySet.add(child.key) } - processChildren(keySet, child, parentEnabled) + processChildren(keySet, child, parentEnabled, getDisabledFn) }) } diff --git a/packages/components/cascader/src/composables/useSelectedState.ts b/packages/components/cascader/src/composables/useSelectedState.ts index e17a4aec4..4fcbab016 100644 --- a/packages/components/cascader/src/composables/useSelectedState.ts +++ b/packages/components/cascader/src/composables/useSelectedState.ts @@ -12,6 +12,7 @@ import { isNil } from 'lodash-es' import { type FormAccessor } from '@idux/cdk/forms' import { NoopArray, type VKey, callEmit, convertArray } from '@idux/cdk/utils' import { useGlobalConfig } from '@idux/components/config' +import { type GetDisabledFn } from '@idux/components/utils' import { type MergedData } from './useDataSource' import { type CascaderProps, type CascaderStrategy } from '../types' @@ -33,6 +34,7 @@ export function useSelectedState( accessor: FormAccessor, mergedDataMap: ComputedRef>, mergedFullPath: ComputedRef, + mergedGetDisabled: ComputedRef, ): SelectedStateContext { const locale = useGlobalConfig('locale') const selectedKeys = computed(() => { @@ -62,7 +64,9 @@ export function useSelectedState( }) const strategyEnabled = computed(() => props.multiple && props.strategy !== 'off') const selectedWithStrategyKeys = computed(() => { - return strategyEnabled.value ? getCascadedKeys(mergedDataMap.value, selectedKeys.value) : selectedKeys.value + return strategyEnabled.value + ? getCascadedKeys(mergedDataMap.value, selectedKeys.value, mergedGetDisabled.value) + : selectedKeys.value }) const indeterminateKeys = computed(() => { @@ -72,12 +76,13 @@ export function useSelectedState( const indeterminateKeySet = new Set() const cascadedKeys = selectedWithStrategyKeys.value const dataMap = mergedDataMap.value + const getDisabledFn = mergedGetDisabled.value cascadedKeys.forEach(key => { let currData = dataMap.get(key) while (currData && !isNil(currData.parentKey)) { const parentKey = currData.parentKey const parent = dataMap.get(parentKey) - if (parent && !parent.rawData.disabled && !cascadedKeys.includes(parentKey)) { + if (parent && !getDisabledFn(parent.rawData) && !cascadedKeys.includes(parentKey)) { indeterminateKeySet.add(parentKey) } currData = parent @@ -92,15 +97,16 @@ export function useSelectedState( if (!mergedFullPath.value) { currValue = props.multiple ? keys : keys[0] } else { + const getDisabledFn = mergedGetDisabled.value if (!props.multiple) { const currKey = keys[0] const dataMap = mergedDataMap.value - currValue = getParentKeys(dataMap, dataMap.get(currKey), true) + currValue = getParentKeys(dataMap, dataMap.get(currKey), true, getDisabledFn) currValue.push(currKey) } else { const dataMap = mergedDataMap.value currValue = keys.map(currKey => { - const parentKeys = getParentKeys(dataMap, dataMap.get(currKey), true) + const parentKeys = getParentKeys(dataMap, dataMap.get(currKey), true, getDisabledFn) parentKeys.push(currKey) return parentKeys }) @@ -128,7 +134,8 @@ export function useSelectedState( const dataMap = mergedDataMap.value const currData = dataMap.get(key) const _strategyEnabled = strategyEnabled.value - const childrenKeys = _strategyEnabled ? getChildrenKeys(currData, true) : [] + const getDisabledFn = mergedGetDisabled.value + const childrenKeys = _strategyEnabled ? getChildrenKeys(currData, true, getDisabledFn) : [] const keySet = new Set(cascadedKeys) if ( @@ -137,13 +144,13 @@ export function useSelectedState( ) { keySet.delete(key) if (_strategyEnabled) { - getParentKeys(dataMap, currData, true).forEach(key => keySet.delete(key)) + getParentKeys(dataMap, currData, true, getDisabledFn).forEach(key => keySet.delete(key)) childrenKeys.forEach(key => keySet.delete(key)) } } else { keySet.add(key) if (_strategyEnabled) { - setParentChecked(dataMap, currData, keySet) + setParentChecked(dataMap, currData, keySet, getDisabledFn) childrenKeys.forEach(key => keySet.add(key)) } } @@ -173,7 +180,7 @@ export function useSelectedState( * 根据当前选中的 keys 来获取对应级联关系的 keys * 只是看是否开启级联 */ -function getCascadedKeys(dataMap: Map, checkedKys: VKey[]) { +function getCascadedKeys(dataMap: Map, checkedKys: VKey[], getDisabledFn: GetDisabledFn) { const keySet = new Set(checkedKys) let lastParentKey: VKey @@ -183,10 +190,10 @@ function getCascadedKeys(dataMap: Map, checkedKys: VKey[]) { return } const { parentKey } = currData - const childrenKeys = getChildrenKeys(currData, true) + const childrenKeys = getChildrenKeys(currData, true, getDisabledFn) childrenKeys.forEach(key => keySet.add(key)) if (parentKey && lastParentKey !== parentKey) { - setParentChecked(dataMap, currData, keySet) + setParentChecked(dataMap, currData, keySet, getDisabledFn) lastParentKey = parentKey } }) @@ -194,13 +201,18 @@ function getCascadedKeys(dataMap: Map, checkedKys: VKey[]) { return [...keySet] } -function setParentChecked(dataMap: Map, currData: MergedData | undefined, keySet: Set) { +function setParentChecked( + dataMap: Map, + currData: MergedData | undefined, + keySet: Set, + getDisabledFn: GetDisabledFn, +) { let parentSelected = true while (parentSelected && currData && !isNil(currData.parentKey)) { const parentKey = currData.parentKey const parent = dataMap.get(parentKey) - if (parent && !currData.rawData.disabled) { - parentSelected = parent.children!.every(item => item.rawData.disabled || keySet.has(item.key)) + if (parent && !getDisabledFn(currData.rawData)) { + parentSelected = parent.children!.every(item => getDisabledFn(item.rawData) || keySet.has(item.key)) parentSelected && keySet.add(currData.parentKey) } currData = parent diff --git a/packages/components/cascader/src/contents/OverlayOption.tsx b/packages/components/cascader/src/contents/OverlayOption.tsx index ea01ecc62..e9c7c9ea7 100644 --- a/packages/components/cascader/src/contents/OverlayOption.tsx +++ b/packages/components/cascader/src/contents/OverlayOption.tsx @@ -32,6 +32,7 @@ export default defineComponent({ slots, mergedPrefixCls, mergedExpandIcon, + mergedGetDisabled, mergedLabelKey, inputValue, activeKey, @@ -48,7 +49,7 @@ export default defineComponent({ handleExpand, } = inject(cascaderToken)! const isActive = computed(() => key === activeKey.value) - const isDisabled = computed(() => props.rawData.disabled) + const isDisabled = computed(() => mergedGetDisabled.value(props.rawData)) const isExpanded = computed(() => expandedKeys.value.includes(key)) const isLoading = computed(() => loadingKeys.value.includes(key)) const isSelected = computed(() => selectedWithStrategyKeys.value.includes(key)) diff --git a/packages/components/cascader/src/token.ts b/packages/components/cascader/src/token.ts index 9183bf450..2156ec24a 100644 --- a/packages/components/cascader/src/token.ts +++ b/packages/components/cascader/src/token.ts @@ -15,7 +15,7 @@ import type { SelectedStateContext } from './composables/useSelectedState' import type { CascaderProps } from './types' import type { FormAccessor } from '@idux/cdk/forms' import type { CascaderConfig } from '@idux/components/config' -import type { GetKeyFn } from '@idux/components/utils' +import type { GetDisabledFn, GetKeyFn } from '@idux/components/utils' import type { ComputedRef, InjectionKey, Slots } from 'vue' export interface CascaderContext @@ -29,6 +29,7 @@ export interface CascaderContext config: CascaderConfig mergedPrefixCls: ComputedRef mergedGetKey: ComputedRef + mergedGetDisabled: ComputedRef mergedChildrenKey: ComputedRef mergedClearIcon: ComputedRef mergedExpandIcon: ComputedRef diff --git a/packages/components/cascader/src/types.ts b/packages/components/cascader/src/types.ts index ab929d4e2..ff66beb8c 100644 --- a/packages/components/cascader/src/types.ts +++ b/packages/components/cascader/src/types.ts @@ -30,6 +30,7 @@ export const cascaderProps = { customAdditional: { type: Function as PropType, default: undefined }, dataSource: { type: Array as PropType, default: () => [] }, disabled: { type: Boolean, default: false }, + disableData: { type: Function as PropType<(data: CascaderData) => boolean> }, empty: { type: [String, Object] as PropType<'default' | 'simple' | EmptyProps>, default: 'simple' }, expandIcon: { type: String, default: undefined }, expandTrigger: { type: String as PropType, default: 'click' }, @@ -54,6 +55,7 @@ export const cascaderProps = { readonly: { type: Boolean, default: false }, searchable: { type: [Boolean, String] as PropType, default: false }, searchFn: { type: [Boolean, Function] as PropType, default: true }, + separator: { type: String, default: '/' }, size: { type: String as PropType, default: undefined }, status: String as PropType, strategy: { type: String as PropType, default: 'all' }, diff --git a/packages/components/cascader/src/utils/index.ts b/packages/components/cascader/src/utils/index.ts index b631cdf86..25df6192a 100644 --- a/packages/components/cascader/src/utils/index.ts +++ b/packages/components/cascader/src/utils/index.ts @@ -10,6 +10,7 @@ import { type ComputedRef } from 'vue' import { isNil } from 'lodash-es' import { type MaybeArray, type VKey, callEmit } from '@idux/cdk/utils' +import { GetDisabledFn } from '@idux/components/utils' import { type MergedData } from '../composables/useDataSource' import { type CascaderData } from '../types' @@ -30,16 +31,20 @@ export function callChange( } } -export function getChildrenKeys(currData: MergedData | undefined, filterDisabled: boolean): VKey[] { +export function getChildrenKeys( + currData: MergedData | undefined, + filterDisabled: boolean, + getDisabledFn: GetDisabledFn, +): VKey[] { if (!currData || !currData.children) { return [] } const keys: VKey[] = [] currData.children.forEach(item => { const { key, rawData } = item - if (!filterDisabled || !rawData.disabled) { + if (!filterDisabled || !getDisabledFn(rawData)) { keys.push(key) - keys.push(...getChildrenKeys(item, filterDisabled)) + keys.push(...getChildrenKeys(item, filterDisabled, getDisabledFn)) } }) return keys @@ -49,11 +54,12 @@ export function getParentKeys( dataMap: Map, currData: MergedData | undefined, filterDisabled: boolean, + getDisabledFn: GetDisabledFn, ): VKey[] { const keys: VKey[] = [] while (currData && !isNil(currData.parentKey)) { const { parentKey, rawData } = currData - if (!filterDisabled || !rawData.disabled) { + if (!filterDisabled || !getDisabledFn(rawData)) { // 保证父组件的顺序 keys.unshift(parentKey) currData = dataMap.get(parentKey) diff --git a/packages/components/utils/index.ts b/packages/components/utils/index.ts index 83d41f1fa..b3110daa2 100644 --- a/packages/components/utils/index.ts +++ b/packages/components/utils/index.ts @@ -9,5 +9,6 @@ export * from './src/colors' export * from './src/convertTarget' export * from './src/convertVNode' export * from './src/portalTarget' +export * from './src/useDisabled' export * from './src/useKey' export * from './src/zIndex' diff --git a/packages/components/utils/src/useDisabled.ts b/packages/components/utils/src/useDisabled.ts new file mode 100644 index 000000000..4ef0c3c15 --- /dev/null +++ b/packages/components/utils/src/useDisabled.ts @@ -0,0 +1,23 @@ +/** + * @license + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE + */ + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import { type ComputedRef, computed } from 'vue' + +export type GetDisabledFn = (data: { disabled?: boolean }) => boolean + +export function useGetDisabled(props: { + disableData: ((data: { disabled?: boolean }) => boolean) | undefined +}): ComputedRef { + return computed(() => { + const { disableData } = props + return (data: { disabled?: boolean }) => { + return data.disabled || (disableData ? disableData(data) : false) + } + }) +}