Skip to content

Commit

Permalink
Merge branch 'main' into fix-ui-issues2
Browse files Browse the repository at this point in the history
  • Loading branch information
saint3347 authored Jan 21, 2025
2 parents 01516aa + fb6ec85 commit 1a9cf2e
Show file tree
Hide file tree
Showing 11 changed files with 231 additions and 18 deletions.
8 changes: 6 additions & 2 deletions packages/base/src/cascader/cascader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const Cascader = <DataItem, Value extends KeygenResult[]>(
mode,
innerTitle,
multiple,
disabled,
disabled: disabledProp,
clearable,
underline,
loading,
Expand Down Expand Up @@ -92,6 +92,10 @@ const Cascader = <DataItem, Value extends KeygenResult[]>(

const showInput = util.isFunc(onFilterProp);

const disabled = util.isOptionalDisabled<DataItem>(disabledProp)
? disabledProp.disabled
: disabledProp;

const styles = jssStyle?.cascader?.() as CascaderClasses;
const rootStyle: React.CSSProperties = Object.assign({ width }, style);
const { locale } = useConfig();
Expand Down Expand Up @@ -135,7 +139,7 @@ const Cascader = <DataItem, Value extends KeygenResult[]>(
control: 'value' in props,
keygen,
unmatch,
disabled,
disabled: disabledProp,
mode,
defaultValue,
childrenKey,
Expand Down
8 changes: 4 additions & 4 deletions packages/base/src/cascader/cascader.type.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { KeygenResult, ObjectKey, TreeModeType } from '@sheinx/hooks';
import { KeygenResult, ObjectKey, TreeModeType, DisabledOption } from '@sheinx/hooks';
import { AbsoluteListProps } from '../absolute-list/absolute-list.type';
import { CommonType } from '../common/type';
import { TagClasses } from '../tag/tag.type';
Expand Down Expand Up @@ -265,11 +265,11 @@ export interface CascaderProps<DataItem, Value extends KeygenResult[]>
*/
loader?: (key: KeygenResult, data: DataItem) => void;
/**
* @en When it is true, all nodes disable the selection; when it is a function, it determines whether it is disabled according to the return result of the function.
* @cn 当 disabled 为 true 时,禁用整个选择框。如果 disabled 为函数,根据函数反回结果禁用选项
* @en When disabled is true, the entire selection box is disabled. If disabled is a function, the option is disabled according to the return result of the function. For performance reasons, by default, disabled
* @cn 当 disabled 为 true 时,禁用整个选择框。如果 disabled 为函数,根据函数反回结果禁用选项。出于性能考虑,默认情况下 disabled 只会在初始化时调用一次,如果 disabled 为函数且内部依赖外部状态,可以使用配置模式,将 disabled 设置为对象,对象中包含 disabled 函数 和 isRealtime 属性,当 isRealtime 为 true 时,每次状态更新都会调用 disabled 函数重新计算禁用状态
* @default false
*/
disabled?: ((data: DataItem) => boolean) | boolean;
disabled?: ((data: DataItem) => boolean) | boolean | DisabledOption<DataItem>;
/**
* @en Expand mode
* @cn 节点展开触发方式
Expand Down
1 change: 1 addition & 0 deletions packages/hooks/src/components/use-cascader/use-cascader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const useCascader = <DataItem, Value extends KeygenResult[]>(
onChange: onChangeProp,
filterSameChange,
});

const { datum } = useTree({
value,
data,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { KeygenResult, TreeKeygenType, ObjectKey } from '../../common/type';
import { DisabledOption } from '../use-tree';
import { TreeModeType } from '../use-tree/use-tree.type';

export interface BaseCascaderProps<DataItem, Value extends KeygenResult[]> {
Expand All @@ -12,6 +13,6 @@ export interface BaseCascaderProps<DataItem, Value extends KeygenResult[]> {
beforeChange?: (value: Value) => any;
mode?: TreeModeType;
keygen: TreeKeygenType<DataItem>;
disabled?: ((data: DataItem) => boolean) | boolean;
disabled?: DisabledOption<DataItem> | boolean | ((item: DataItem) => boolean);
filterSameChange?: boolean;
}
}
8 changes: 7 additions & 1 deletion packages/hooks/src/components/use-tree/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
export { default, default as useTree } from './use-tree';
export type { BaseTreeProps, UpdateFunc, TreePathType, TreeModeType } from './use-tree.type';
export type {
BaseTreeProps,
UpdateFunc,
TreePathType,
TreeModeType,
DisabledOption,
} from './use-tree.type';

export { default as useTreeNode } from './use-tree-node';
export type { BaseTreeNodeProps, UpdateType } from './use-tree-node.type';
28 changes: 25 additions & 3 deletions packages/hooks/src/components/use-tree/use-tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,14 @@ import {
} from './use-tree.type';
import { usePersistFn } from '../../common/use-persist-fn';
import { KeygenResult } from '../../common/type';
import { isFunc, isString, isNumber, isArray, isUnMatchedData } from '../../utils/is';
import {
isFunc,
isString,
isNumber,
isArray,
isUnMatchedData,
isOptionalDisabled,
} from '../../utils/is';
import { devUseWarning } from '../../utils';

function toArray<Value>(value: Value) {
Expand Down Expand Up @@ -60,11 +67,18 @@ const useTree = <DataItem>(props: BaseTreeProps<DataItem>) => {
dataUpdate = true,
defaultExpanded = [],
defaultExpandAll,
disabled: disabledProps,
unmatch,
isControlled,
onExpand: onExpandProp,
} = props;

const disabledProps = isOptionalDisabled<DataItem>(props.disabled)
? props.disabled.disabled
: props.disabled;

const isRealtime = isOptionalDisabled<DataItem>(props.disabled)
? props.disabled.isRealtime
: false;

const [inited, setInited] = useState(false);

Expand Down Expand Up @@ -352,7 +366,15 @@ const useTree = <DataItem>(props: BaseTreeProps<DataItem>) => {
const isDisabled = (id: KeygenResult) => {
if (isFunc(disabledProps)) {
const node = context.pathMap.get(id);
if (node) return node.isDisabled;
if (node) {
if (isRealtime) {
const item = context.dataMap.get(id);
if (!item) return false;
return getDisabled()(item);
} else {
return node.isDisabled;
}
}
return false;
}
return !!disabledProps;
Expand Down
7 changes: 6 additions & 1 deletion packages/hooks/src/components/use-tree/use-tree.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ export interface TreePathType {
index: number;
}

export interface DisabledOption<DataItem> {
disabled: (data: DataItem) => boolean;
isRealtime: boolean;
}

export interface BaseTreeProps<DataItem> {
/**
* @private 内部属性
Expand Down Expand Up @@ -69,7 +74,7 @@ export interface BaseTreeProps<DataItem> {
* @cn 显示选择框时有效,为 true 时,所有节点禁用选择,为函数时,根据函数返回结果确定是否禁用
* @default false
*/
disabled?: boolean | ((item: DataItem) => boolean);
disabled?: boolean | ((item: DataItem) => boolean) | DisabledOption<DataItem>;
/**
* @en Auxiliary method for generating key. When it is a function, use the return value of this function. When it is a string, use the data value corresponding to this string. For example, "id" is the same thing as (d) => d.id
* @cn 生成 key 的辅助方法, 为函数时,使用此函数返回值, 为 string 时,使用这个 string 对应的数据值。如 "id",相当于 (d) => d.id
Expand Down
7 changes: 7 additions & 0 deletions packages/hooks/src/utils/is.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ObjectType } from '../common/type';
import { DisabledOption } from '../components/use-tree/use-tree.type';
import { UnMatchedData } from '../common/use-list-select/use-list.type';
import React from 'react';

Expand Down Expand Up @@ -106,3 +107,9 @@ export function isDomElement(element: any): element is HTMLElement {
element.nodeType === 1 &&
typeof element.nodeName === 'string';
}

export const isOptionalDisabled = <DataItem>(
disabled: unknown,
): disabled is DisabledOption<DataItem> => {
return isObject(disabled) && disabled.hasOwnProperty('isRealtime');
};
6 changes: 6 additions & 0 deletions packages/shineout/src/cascader/__doc__/changelog.cn.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 3.5.8-beta.7
2025-01-21

### 💎 Enhancement
- `Cascader` 新增 `disabled` 配置模式,支持实时计算 disabled 状态 ([#936](https://github.com/sheinsight/shineout-next/pull/936))

## 3.5.8-beta.3
2025-01-15

Expand Down
38 changes: 34 additions & 4 deletions packages/shineout/src/cascader/__example__/04-disabled.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
/**
* cn - 禁用/禁用选项
* -- 通过设置`disabled`属性可以禁用组件。disabled为函数时,支持禁用单个选项
* -- 通过设置`disabled`属性可以禁用组件。`disabled` 为函数时,支持禁用单个选项
* -- 出于性能考虑,默认情况下 disabled 只会在初始化时调用一次
* -- 如果 disabled 为函数且内部依赖外部状态,可以将其设置为一个对象来使用配置模式,以确保禁用结果计算的准确性
* -- 配置模式包含 `disabled` 函数 和 `isRealtime` 属性
* -- 当 `isRealtime` 为 true 时,每次状态更新都会调用 disabled 函数重新计算禁用结果
* -- 注意,配置模式下 disabled 函数会在每次状态更新时调用,可能会带来额外的性能开销,建议配合虚拟列表使用
* en - Disabled
* -- Set the `disabled` property to disable the component. When `disabled` is a function, support disabling a single option
*/
import React from 'react';
import { Cascader, TYPE } from 'shineout';
import React, { useState } from 'react';
import { Cascader, Switch, TYPE } from 'shineout';

type CascaderProps = TYPE.Cascader.Props<DataItem, string[]>;

Expand Down Expand Up @@ -44,14 +49,20 @@ const data: DataItem[] = [
];

export default () => {
const [checked, setChecked] = useState(false);

const handleDisabled: CascaderProps['disabled'] = (item) => {
return item.value === 'jiangsu';
};

const handleDisabledStatus: CascaderProps['disabled'] = (item) => {
return checked ? item.value === 'jiangsu' : false;
};

const renderItem: CascaderProps['renderItem'] = (n) => `${n.value}`;

return (
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 32, width: 632 }}>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 32, width: 632, marginBottom: 104 }}>
<Cascader
width={300}
disabled
Expand Down Expand Up @@ -91,6 +102,25 @@ export default () => {
keygen='value'
renderItem={renderItem}
/>
<div>
<Switch value={checked} onChange={setChecked} style={{ marginRight: 12 }} />
<Cascader
clearable
open
width={246}
height={100}
adjust={false}
onChange={(v) => console.log(v)}
disabled={{
disabled: handleDisabledStatus,
isRealtime: true,
}}
placeholder='Please select city'
data={data}
keygen='value'
renderItem={renderItem}
/>
</div>
</div>
);
};
Loading

0 comments on commit 1a9cf2e

Please sign in to comment.