@akinon/ui-tree-select 1.1.3 → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.d.ts +3 -3
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +110 -14
- package/dist/cjs/types.d.ts +424 -0
- package/dist/esm/index.d.ts +3 -3
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +111 -15
- package/dist/esm/types.d.ts +424 -0
- package/package.json +7 -3
package/dist/cjs/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { TreeSelectProps as AntTreeSelectProps } from 'antd';
|
|
2
1
|
import * as React from 'react';
|
|
3
|
-
|
|
4
|
-
export declare const TreeSelect:
|
|
2
|
+
import type { TreeSelectDataNode, TreeSelectProps } from './types';
|
|
3
|
+
export declare const TreeSelect: <ValueType = unknown, OptionType extends TreeSelectDataNode = TreeSelectDataNode>(props: TreeSelectProps<ValueType, OptionType>) => React.JSX.Element;
|
|
4
|
+
export type { TreeSelectDataNode, TreeSelectProps };
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/cjs/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAInE,eAAO,MAAM,UAAU,GACrB,SAAS,GAAG,OAAO,EACnB,UAAU,SAAS,kBAAkB,GAAG,kBAAkB,EAE1D,OAAO,eAAe,CAAC,SAAS,EAAE,UAAU,CAAC,sBA8I9C,CAAC;AAEF,YAAY,EAAE,kBAAkB,EAAE,eAAe,EAAE,CAAC"}
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,21 +1,117 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
|
-
var t = {};
|
|
4
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
-
t[p] = s[p];
|
|
6
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
-
t[p[i]] = s[p[i]];
|
|
10
|
-
}
|
|
11
|
-
return t;
|
|
12
|
-
};
|
|
13
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
3
|
exports.TreeSelect = void 0;
|
|
4
|
+
const icons_1 = require("@akinon/icons");
|
|
5
|
+
const ui_theme_1 = require("@akinon/ui-theme");
|
|
6
|
+
const cssinjs_1 = require("@ant-design/cssinjs");
|
|
15
7
|
const antd_1 = require("antd");
|
|
8
|
+
const classnames_1 = require("classnames");
|
|
16
9
|
const React = require("react");
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
10
|
+
const TREE_LINE = { showLeafIcon: false };
|
|
11
|
+
const TreeSelect = (props) => {
|
|
12
|
+
const { getPrefixCls, theme } = React.useContext(antd_1.ConfigProvider.ConfigContext);
|
|
13
|
+
const { token, hashId } = (0, ui_theme_1.useToken)();
|
|
14
|
+
const treeSelectToken = token.TreeSelect;
|
|
15
|
+
const treeSelectPrefixCls = `${getPrefixCls()}-tree-select`;
|
|
16
|
+
const selectTreePrefixCls = `${getPrefixCls()}-select-tree`;
|
|
17
|
+
const dropdownPrefixCls = `${treeSelectPrefixCls}-dropdown`;
|
|
18
|
+
const dropdownPrefixClsWithHash = `:where(.${hashId}).${dropdownPrefixCls}`;
|
|
19
|
+
const switcherIconCls = `${treeSelectPrefixCls}-switcher-icon`;
|
|
20
|
+
const switcherIconExpandedCls = `${switcherIconCls}-expanded`;
|
|
21
|
+
const switcherIconCollapsedCls = `${switcherIconCls}-collapsed`;
|
|
22
|
+
const useStyle = (0, cssinjs_1.useStyleRegister)({
|
|
23
|
+
token: token,
|
|
24
|
+
path: ['TreeSelect'],
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
|
+
theme: theme
|
|
27
|
+
}, () => {
|
|
28
|
+
return {
|
|
29
|
+
[dropdownPrefixClsWithHash]: {
|
|
30
|
+
[`.${selectTreePrefixCls}-title`]: {
|
|
31
|
+
color: treeSelectToken.optionTitleColor
|
|
32
|
+
},
|
|
33
|
+
[`.${selectTreePrefixCls}-node-selected`]: {
|
|
34
|
+
[`.${selectTreePrefixCls}-title`]: {
|
|
35
|
+
color: treeSelectToken.optionActiveColor,
|
|
36
|
+
fontWeight: treeSelectToken.optionActiveFontWeight
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
[`.${selectTreePrefixCls}`]: {
|
|
40
|
+
[`.${selectTreePrefixCls}-switcher`]: {
|
|
41
|
+
color: treeSelectToken.optionSwitcherColor,
|
|
42
|
+
[`&.${selectTreePrefixCls}-switcher_close`]: {
|
|
43
|
+
height: treeSelectToken.titleHeight
|
|
44
|
+
},
|
|
45
|
+
[`&.${selectTreePrefixCls}-switcher_open`]: {
|
|
46
|
+
height: treeSelectToken.titleHeight
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
[`.${selectTreePrefixCls}-treenode-active`]: {
|
|
50
|
+
[`.${selectTreePrefixCls}-node-content-wrapper`]: {
|
|
51
|
+
backgroundColor: treeSelectToken.nodeContentWrapperActiveHoverBg
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
[`.${selectTreePrefixCls}-treenode`]: {
|
|
55
|
+
marginBottom: `${treeSelectToken.treeNodeMarginBottom} !important`,
|
|
56
|
+
'&::before': {
|
|
57
|
+
display: treeSelectToken.treeNodeBeforeDisplay
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
[`.${treeSelectPrefixCls}-switcher-icon-wrapper`]: {
|
|
62
|
+
border: treeSelectToken.switcherIconWrapperBorder,
|
|
63
|
+
borderRadius: treeSelectToken.optionSwitcherBorderRadius,
|
|
64
|
+
height: treeSelectToken.switcherIconWrapperSize,
|
|
65
|
+
width: treeSelectToken.switcherIconWrapperSize,
|
|
66
|
+
marginTop: treeSelectToken.switcherIconWrapperMarginTop,
|
|
67
|
+
backgroundColor: treeSelectToken.switcherIconWrapperBg
|
|
68
|
+
},
|
|
69
|
+
[`.${switcherIconCls}`]: {
|
|
70
|
+
marginLeft: treeSelectToken.switcherIconMarginLeft,
|
|
71
|
+
marginBottom: treeSelectToken.switcherIconMarginBottom
|
|
72
|
+
},
|
|
73
|
+
[`.${switcherIconExpandedCls}`]: {
|
|
74
|
+
transform: treeSelectToken.switcherIconExpandedTransform
|
|
75
|
+
},
|
|
76
|
+
[`.${switcherIconCollapsedCls}`]: {
|
|
77
|
+
transform: treeSelectToken.switcherIconCollapsedTransform
|
|
78
|
+
},
|
|
79
|
+
[`.${selectTreePrefixCls}-indent-unit::before`]: {
|
|
80
|
+
borderInlineEnd: `${treeSelectToken.nodeBeforeLineBorder} !important`,
|
|
81
|
+
insetInlineEnd: `${treeSelectToken.indentLineInsetEnd} !important`
|
|
82
|
+
},
|
|
83
|
+
[`.${selectTreePrefixCls}-indent-unit.${selectTreePrefixCls}-indent-unit-end::before`]: {
|
|
84
|
+
display: 'block !important',
|
|
85
|
+
borderInlineEnd: `${treeSelectToken.nodeBeforeLineBorder} !important`,
|
|
86
|
+
insetInlineEnd: `${treeSelectToken.indentLineInsetEnd} !important`
|
|
87
|
+
},
|
|
88
|
+
[`.${selectTreePrefixCls}-switcher-leaf-line`]: {
|
|
89
|
+
'&::before': {
|
|
90
|
+
borderInlineEnd: `${treeSelectToken.nodeBeforeLineBorder} !important`,
|
|
91
|
+
insetInlineStart: `${treeSelectToken.leafLineInsetStart} !important`
|
|
92
|
+
},
|
|
93
|
+
'&::after': {
|
|
94
|
+
borderBottom: `${treeSelectToken.nodeBeforeLineBorder} !important`
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
[`.${selectTreePrefixCls}-treenode`]: {
|
|
98
|
+
'&:hover': {
|
|
99
|
+
backgroundColor: treeSelectToken.nodeContentWrapperActiveBg
|
|
100
|
+
},
|
|
101
|
+
[`&.${selectTreePrefixCls}-treenode-selected`]: {
|
|
102
|
+
backgroundColor: treeSelectToken.nodeContentWrapperActiveBg
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
[`.${selectTreePrefixCls}-node-content-wrapper, .${selectTreePrefixCls}-node-content-wrapper-normal`]: {
|
|
106
|
+
marginInlineStart: treeSelectToken.nodeContentWrapperMarginInlineStart
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
});
|
|
111
|
+
const renderSwitcherIcon = (nodeProps) => (React.createElement("span", { className: `${treeSelectPrefixCls}-switcher-icon-wrapper` },
|
|
112
|
+
React.createElement(icons_1.Icon, { icon: "triangle", size: 8, className: (0, classnames_1.default)(switcherIconCls, nodeProps.expanded
|
|
113
|
+
? switcherIconExpandedCls
|
|
114
|
+
: switcherIconCollapsedCls) })));
|
|
115
|
+
return useStyle(React.createElement(antd_1.TreeSelect, Object.assign({ size: "large", popupMatchSelectWidth: true }, props, { treeLine: TREE_LINE, switcherIcon: renderSwitcherIcon })));
|
|
20
116
|
};
|
|
21
117
|
exports.TreeSelect = TreeSelect;
|
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
import type { DO_NOT_USE_OR_YOU_WILL_BE_FIRED_INTERNAL_STYLE } from '@akinon/ui-theme';
|
|
2
|
+
import type * as React from 'react';
|
|
3
|
+
|
|
4
|
+
type Key = string | number;
|
|
5
|
+
|
|
6
|
+
type SafeKey = string | number;
|
|
7
|
+
|
|
8
|
+
export interface TreeSelectDataNode extends Record<string, unknown> {
|
|
9
|
+
/** Unique key for the node */
|
|
10
|
+
key?: Key;
|
|
11
|
+
/** Value used for selection and filtering */
|
|
12
|
+
value?: SafeKey;
|
|
13
|
+
/** Node label */
|
|
14
|
+
title?: React.ReactNode;
|
|
15
|
+
children?: TreeSelectDataNode[];
|
|
16
|
+
/** Disable this node */
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
/** Whether the node can be selected */
|
|
19
|
+
selectable?: boolean;
|
|
20
|
+
/** Show checkbox for this node when tree is checkable */
|
|
21
|
+
checkable?: boolean;
|
|
22
|
+
/** Disable checkbox for this node */
|
|
23
|
+
disableCheckbox?: boolean;
|
|
24
|
+
/** Treat as leaf (no children) */
|
|
25
|
+
isLeaf?: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface TreeNodeProps {
|
|
29
|
+
checkable?: boolean;
|
|
30
|
+
disableCheckbox?: boolean;
|
|
31
|
+
disabled?: boolean;
|
|
32
|
+
isLeaf?: boolean;
|
|
33
|
+
key?: Key;
|
|
34
|
+
selectable?: boolean;
|
|
35
|
+
title?: React.ReactNode;
|
|
36
|
+
value?: SafeKey;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface FieldNames {
|
|
40
|
+
/** Field name for value */
|
|
41
|
+
value?: string;
|
|
42
|
+
/** Field name for label */
|
|
43
|
+
label?: string;
|
|
44
|
+
/** Field name for children */
|
|
45
|
+
children?: string;
|
|
46
|
+
_title?: string[];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface SimpleModeConfig {
|
|
50
|
+
id?: SafeKey;
|
|
51
|
+
pId?: SafeKey;
|
|
52
|
+
rootPId?: SafeKey;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
interface LabeledValueType {
|
|
56
|
+
key?: Key;
|
|
57
|
+
value?: SafeKey;
|
|
58
|
+
label?: React.ReactNode;
|
|
59
|
+
/** Option is partially checked (e.g. parent with some children selected) */
|
|
60
|
+
halfChecked?: boolean;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface ChangeEventExtra {
|
|
64
|
+
preValue: LabeledValueType[];
|
|
65
|
+
triggerValue: SafeKey;
|
|
66
|
+
selected?: boolean;
|
|
67
|
+
checked?: boolean;
|
|
68
|
+
triggerNode: React.ReactElement;
|
|
69
|
+
allCheckedNodes: unknown[];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
interface LegacyDataNode extends TreeSelectDataNode {
|
|
73
|
+
props: unknown;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
type CheckedStrategy = 'SHOW_ALL' | 'SHOW_PARENT' | 'SHOW_CHILD';
|
|
77
|
+
|
|
78
|
+
type TreeExpandAction = false | 'click' | 'doubleclick';
|
|
79
|
+
|
|
80
|
+
type SizeType = 'small' | 'middle' | 'large' | undefined;
|
|
81
|
+
|
|
82
|
+
type SelectCommonPlacement =
|
|
83
|
+
| 'bottomLeft'
|
|
84
|
+
| 'bottomRight'
|
|
85
|
+
| 'topLeft'
|
|
86
|
+
| 'topRight';
|
|
87
|
+
|
|
88
|
+
type InputStatus = 'warning' | 'error' | '';
|
|
89
|
+
|
|
90
|
+
type Variant = 'outlined' | 'borderless' | 'filled' | 'underlined';
|
|
91
|
+
|
|
92
|
+
type TreeShowLine = boolean | { showLeafIcon?: boolean | React.ReactNode };
|
|
93
|
+
|
|
94
|
+
interface TreeNodePropsForSwitcher {
|
|
95
|
+
expanded?: boolean;
|
|
96
|
+
isLeaf?: boolean;
|
|
97
|
+
[key: string]: unknown;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
type SwitcherIcon =
|
|
101
|
+
| React.ReactNode
|
|
102
|
+
| ((props: TreeNodePropsForSwitcher) => React.ReactNode);
|
|
103
|
+
|
|
104
|
+
type TreeIconType =
|
|
105
|
+
| React.ReactNode
|
|
106
|
+
| ((props: TreeNodePropsForSwitcher) => React.ReactNode);
|
|
107
|
+
|
|
108
|
+
type SemanticDOM = 'root';
|
|
109
|
+
|
|
110
|
+
type PopupSemanticDOM = 'root';
|
|
111
|
+
|
|
112
|
+
interface ClassNamesStylesInfo<
|
|
113
|
+
V = unknown,
|
|
114
|
+
O extends TreeSelectDataNode = TreeSelectDataNode
|
|
115
|
+
> {
|
|
116
|
+
props: TreeSelectProps<V, O>;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
type SemanticName = 'root';
|
|
120
|
+
type PopupSemantic = 'root';
|
|
121
|
+
|
|
122
|
+
interface ShowSearchObject {
|
|
123
|
+
/** Clear search when selection changes (multiple mode) */
|
|
124
|
+
autoClearSearchValue?: boolean;
|
|
125
|
+
/** Filter nodes by search; use treeNodeFilterProp field or custom function */
|
|
126
|
+
filterTreeNode?:
|
|
127
|
+
| boolean
|
|
128
|
+
| ((inputValue: string, treeNode: TreeSelectDataNode) => boolean);
|
|
129
|
+
/** Controlled search value; use with onSearch */
|
|
130
|
+
searchValue?: string;
|
|
131
|
+
/** Property name used for filtering */
|
|
132
|
+
treeNodeFilterProp?: string;
|
|
133
|
+
/** Called when search input changes */
|
|
134
|
+
onSearch?: (value: string) => void;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
interface LabeledValue {
|
|
138
|
+
key?: string;
|
|
139
|
+
value: string | number;
|
|
140
|
+
label: React.ReactNode;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
type SelectValue =
|
|
144
|
+
| (string | number)
|
|
145
|
+
| (string | number)[]
|
|
146
|
+
| LabeledValue
|
|
147
|
+
| LabeledValue[];
|
|
148
|
+
|
|
149
|
+
interface TagRenderProps {
|
|
150
|
+
label: React.ReactNode;
|
|
151
|
+
value: SafeKey | LabeledValueType;
|
|
152
|
+
disabled?: boolean;
|
|
153
|
+
onClose: () => void;
|
|
154
|
+
closable: boolean;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
interface TreeSelectRef {
|
|
158
|
+
blur: () => void;
|
|
159
|
+
focus: () => void;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export interface TreeSelectProps<
|
|
163
|
+
ValueType = unknown,
|
|
164
|
+
OptionType extends TreeSelectDataNode = TreeSelectDataNode
|
|
165
|
+
> extends React.AriaAttributes {
|
|
166
|
+
/** Whether to show a clear button to remove the selection. */
|
|
167
|
+
allowClear?: boolean | { clearIcon?: React.ReactNode };
|
|
168
|
+
|
|
169
|
+
/** CSS class names for component parts (object or function) */
|
|
170
|
+
classNames?:
|
|
171
|
+
| (Partial<Record<SemanticName, string>> & {
|
|
172
|
+
popup?: Partial<Record<PopupSemantic, string>>;
|
|
173
|
+
})
|
|
174
|
+
| ((
|
|
175
|
+
info: ClassNamesStylesInfo<ValueType, OptionType>
|
|
176
|
+
) => Partial<Record<SemanticDOM, string>>);
|
|
177
|
+
|
|
178
|
+
/** Dropdown open by default */
|
|
179
|
+
defaultOpen?: boolean;
|
|
180
|
+
|
|
181
|
+
/** Initial selected value(s) */
|
|
182
|
+
defaultValue?: ValueType;
|
|
183
|
+
|
|
184
|
+
/** Whether the tree select is disabled */
|
|
185
|
+
disabled?: boolean;
|
|
186
|
+
|
|
187
|
+
/** Match dropdown width to input; false disables virtual scroll */
|
|
188
|
+
popupMatchSelectWidth?: boolean | number;
|
|
189
|
+
|
|
190
|
+
/** Customize dropdown content wrapper */
|
|
191
|
+
popupRender?: (
|
|
192
|
+
originNode: React.ReactNode,
|
|
193
|
+
props: { menu: React.ReactNode }
|
|
194
|
+
) => React.ReactNode;
|
|
195
|
+
|
|
196
|
+
/** Map data fields to label, value, children */
|
|
197
|
+
fieldNames?: FieldNames;
|
|
198
|
+
|
|
199
|
+
/** Container element for dropdown */
|
|
200
|
+
getPopupContainer?: (triggerNode: HTMLElement) => HTMLElement;
|
|
201
|
+
|
|
202
|
+
/** Value shape: { value, label, halfChecked } instead of raw value */
|
|
203
|
+
labelInValue?: boolean;
|
|
204
|
+
|
|
205
|
+
/** Dropdown list height (px) */
|
|
206
|
+
listHeight?: number;
|
|
207
|
+
|
|
208
|
+
/** Load children asynchronously for a node */
|
|
209
|
+
loadData?: (node: LegacyDataNode) => Promise<unknown>;
|
|
210
|
+
|
|
211
|
+
/** Max number of tags shown in multiple mode; 'responsive' adapts to width */
|
|
212
|
+
maxTagCount?: number | 'responsive';
|
|
213
|
+
|
|
214
|
+
/** Max selected items when multiple (and not using parent-only strategy) */
|
|
215
|
+
maxCount?: number;
|
|
216
|
+
|
|
217
|
+
/** Placeholder when tags are collapsed (e.g. "+ N more") */
|
|
218
|
+
maxTagPlaceholder?:
|
|
219
|
+
| React.ReactNode
|
|
220
|
+
| ((omittedValues: unknown[]) => React.ReactNode);
|
|
221
|
+
|
|
222
|
+
/** Max length of tag text before truncation */
|
|
223
|
+
maxTagTextLength?: number;
|
|
224
|
+
|
|
225
|
+
/** Allow multiple selection */
|
|
226
|
+
multiple?: boolean;
|
|
227
|
+
|
|
228
|
+
/** Content when no options match */
|
|
229
|
+
notFoundContent?: React.ReactNode;
|
|
230
|
+
|
|
231
|
+
/** Controlled dropdown open state */
|
|
232
|
+
open?: boolean;
|
|
233
|
+
|
|
234
|
+
/** Placeholder for the input */
|
|
235
|
+
placeholder?: React.ReactNode;
|
|
236
|
+
|
|
237
|
+
/** Dropdown position */
|
|
238
|
+
placement?: SelectCommonPlacement;
|
|
239
|
+
|
|
240
|
+
/** Prefix content */
|
|
241
|
+
prefix?: React.ReactNode;
|
|
242
|
+
|
|
243
|
+
/** Which checked nodes to show in multiple: all, parent only, or child only */
|
|
244
|
+
showCheckedStrategy?: CheckedStrategy;
|
|
245
|
+
|
|
246
|
+
/** Enable search; use object for options (filter, onSearch, etc.) */
|
|
247
|
+
showSearch?: boolean | ShowSearchObject;
|
|
248
|
+
|
|
249
|
+
size?: SizeType;
|
|
250
|
+
|
|
251
|
+
/** Validation state */
|
|
252
|
+
status?: InputStatus;
|
|
253
|
+
|
|
254
|
+
/** Suffix content */
|
|
255
|
+
suffixIcon?: React.ReactNode;
|
|
256
|
+
|
|
257
|
+
/** Custom expand/collapse icon */
|
|
258
|
+
switcherIcon?: SwitcherIcon;
|
|
259
|
+
|
|
260
|
+
styles?: DO_NOT_USE_OR_YOU_WILL_BE_FIRED_INTERNAL_STYLE;
|
|
261
|
+
|
|
262
|
+
/** Custom tag render in multiple mode */
|
|
263
|
+
tagRender?: (props: TagRenderProps) => React.ReactNode;
|
|
264
|
+
|
|
265
|
+
/** Show checkboxes on nodes */
|
|
266
|
+
treeCheckable?: boolean;
|
|
267
|
+
|
|
268
|
+
/** Parent/child checkboxes independent; enables labelInValue */
|
|
269
|
+
treeCheckStrictly?: boolean;
|
|
270
|
+
|
|
271
|
+
/** Tree data (array of nodes); each value should be unique */
|
|
272
|
+
treeData?: OptionType[];
|
|
273
|
+
|
|
274
|
+
/** Use flat data with id/pId; optional config for custom id/pId keys */
|
|
275
|
+
treeDataSimpleMode?: boolean | SimpleModeConfig;
|
|
276
|
+
|
|
277
|
+
/** Custom render for node title */
|
|
278
|
+
treeTitleRender?: (nodeData: OptionType) => React.ReactNode;
|
|
279
|
+
|
|
280
|
+
/** Expand all nodes initially */
|
|
281
|
+
treeDefaultExpandAll?: boolean;
|
|
282
|
+
|
|
283
|
+
/** Initially expanded node keys */
|
|
284
|
+
treeDefaultExpandedKeys?: SafeKey[];
|
|
285
|
+
|
|
286
|
+
/** Expand on click, double-click, or disable */
|
|
287
|
+
treeExpandAction?: TreeExpandAction;
|
|
288
|
+
|
|
289
|
+
/** Controlled expanded keys */
|
|
290
|
+
treeExpandedKeys?: SafeKey[];
|
|
291
|
+
|
|
292
|
+
/** Icon before node title */
|
|
293
|
+
treeIcon?: TreeIconType;
|
|
294
|
+
|
|
295
|
+
/** Loaded node keys (with loadData); controlled */
|
|
296
|
+
treeLoadedKeys?: SafeKey[];
|
|
297
|
+
|
|
298
|
+
/** Show connection lines between nodes */
|
|
299
|
+
treeLine?: TreeShowLine;
|
|
300
|
+
|
|
301
|
+
/** Data property to use as node label in select */
|
|
302
|
+
treeNodeLabelProp?: string;
|
|
303
|
+
|
|
304
|
+
/** Controlled selected value(s) */
|
|
305
|
+
value?: ValueType;
|
|
306
|
+
|
|
307
|
+
/** Variant of the tree select */
|
|
308
|
+
variant?: Variant;
|
|
309
|
+
|
|
310
|
+
/** Use virtual scroll in dropdown */
|
|
311
|
+
virtual?: boolean;
|
|
312
|
+
|
|
313
|
+
/** Called when selection or input value changes */
|
|
314
|
+
onChange?: (
|
|
315
|
+
value: ValueType,
|
|
316
|
+
labelList: React.ReactNode[],
|
|
317
|
+
extra: ChangeEventExtra
|
|
318
|
+
) => void;
|
|
319
|
+
|
|
320
|
+
/** Called when a node is selected */
|
|
321
|
+
onSelect?: (
|
|
322
|
+
value: ValueType,
|
|
323
|
+
node: OptionType,
|
|
324
|
+
extra: ChangeEventExtra
|
|
325
|
+
) => void;
|
|
326
|
+
|
|
327
|
+
/** Called when expanded keys change */
|
|
328
|
+
onTreeExpand?: (expandedKeys: SafeKey[]) => void;
|
|
329
|
+
|
|
330
|
+
/** Called when the popup scrolls */
|
|
331
|
+
onPopupScroll?: React.UIEventHandler<HTMLDivElement>;
|
|
332
|
+
|
|
333
|
+
/** Clear search when selection changes (when showSearch is true) */
|
|
334
|
+
autoClearSearchValue?: boolean;
|
|
335
|
+
|
|
336
|
+
/** Filter tree by search; boolean or custom filter function */
|
|
337
|
+
filterTreeNode?:
|
|
338
|
+
| boolean
|
|
339
|
+
| ((inputValue: string, treeNode: OptionType) => boolean);
|
|
340
|
+
|
|
341
|
+
/** Controlled search value */
|
|
342
|
+
searchValue?: string;
|
|
343
|
+
|
|
344
|
+
/** Data property used for search filtering */
|
|
345
|
+
treeNodeFilterProp?: string;
|
|
346
|
+
|
|
347
|
+
/** Called when search input changes */
|
|
348
|
+
onSearch?: (value: string) => void;
|
|
349
|
+
|
|
350
|
+
/** CSS class name */
|
|
351
|
+
className?: string;
|
|
352
|
+
|
|
353
|
+
style?: DO_NOT_USE_OR_YOU_WILL_BE_FIRED_INTERNAL_STYLE;
|
|
354
|
+
|
|
355
|
+
/** Tooltip text (title attribute) for the trigger element */
|
|
356
|
+
title?: string;
|
|
357
|
+
/** Text direction for the input and dropdown */
|
|
358
|
+
direction?: 'ltr' | 'rtl';
|
|
359
|
+
/** Maximum number of characters allowed in the input */
|
|
360
|
+
maxLength?: number;
|
|
361
|
+
/** Tab order index of the trigger element */
|
|
362
|
+
tabIndex?: number;
|
|
363
|
+
/** Auto focus the input on mount */
|
|
364
|
+
autoFocus?: boolean;
|
|
365
|
+
/** Called after the clear icon clears the current value */
|
|
366
|
+
onClear?: () => void;
|
|
367
|
+
/** Show loading state and spinner */
|
|
368
|
+
loading?: boolean;
|
|
369
|
+
/** Inline style object applied to the dropdown menu */
|
|
370
|
+
dropdownStyle?: DO_NOT_USE_OR_YOU_WILL_BE_FIRED_INTERNAL_STYLE;
|
|
371
|
+
/** Additional CSS class name for the dropdown menu */
|
|
372
|
+
dropdownClassName?: string;
|
|
373
|
+
/** Match dropdown width to select; number sets explicit pixel width */
|
|
374
|
+
dropdownMatchSelectWidth?: boolean | number;
|
|
375
|
+
/** Custom render function for the dropdown; lets you wrap or extend the default menu */
|
|
376
|
+
dropdownRender?: (menu: React.ReactElement) => React.ReactElement;
|
|
377
|
+
/** Called when the trigger loses focus */
|
|
378
|
+
onBlur?: React.FocusEventHandler<HTMLElement>;
|
|
379
|
+
/** Called when the trigger receives focus */
|
|
380
|
+
onFocus?: React.FocusEventHandler<HTMLElement>;
|
|
381
|
+
/** Keyboard keyup event handler on the trigger wrapper */
|
|
382
|
+
onKeyUp?: React.KeyboardEventHandler<HTMLDivElement>;
|
|
383
|
+
/** Keyboard keydown event handler on the trigger wrapper */
|
|
384
|
+
onKeyDown?: React.KeyboardEventHandler<HTMLDivElement>;
|
|
385
|
+
/** Mousedown event handler on the trigger wrapper */
|
|
386
|
+
onMouseDown?: React.MouseEventHandler<HTMLDivElement>;
|
|
387
|
+
/** Keyboard keydown handler for the internal input element */
|
|
388
|
+
onInputKeyDown?: React.KeyboardEventHandler<
|
|
389
|
+
HTMLInputElement | HTMLTextAreaElement
|
|
390
|
+
>;
|
|
391
|
+
/** Mouse enter event handler on the trigger wrapper */
|
|
392
|
+
onMouseEnter?: React.MouseEventHandler<HTMLDivElement>;
|
|
393
|
+
/** Mouse leave event handler on the trigger wrapper */
|
|
394
|
+
onMouseLeave?: React.MouseEventHandler<HTMLDivElement>;
|
|
395
|
+
/** Click event handler on the trigger wrapper */
|
|
396
|
+
onClick?: React.MouseEventHandler<HTMLDivElement>;
|
|
397
|
+
/** HTML id attribute for the trigger element */
|
|
398
|
+
id?: string;
|
|
399
|
+
/** Option nodes rendered as children instead of using treeData */
|
|
400
|
+
children?: React.ReactNode;
|
|
401
|
+
/** Controlled input text value (typically used with search) */
|
|
402
|
+
inputValue?: string;
|
|
403
|
+
/** Called when a value is deselected (mainly in multiple mode) */
|
|
404
|
+
onDeselect?: (value: ValueType, option: OptionType) => void;
|
|
405
|
+
/** Virtual list item height in pixels */
|
|
406
|
+
listItemHeight?: number;
|
|
407
|
+
/** Virtual list scroll offset per item for performance tuning */
|
|
408
|
+
listItemScrollOffset?: number;
|
|
409
|
+
/** Whether to render switcher/leaf icons next to each tree node */
|
|
410
|
+
showTreeIcon?: boolean;
|
|
411
|
+
prefixCls?: string;
|
|
412
|
+
/** Additional CSS class name for the popup container */
|
|
413
|
+
popupClassName?: string;
|
|
414
|
+
/** Called when dropdown visibility changes */
|
|
415
|
+
onDropdownVisibleChange?: (visible: boolean) => void;
|
|
416
|
+
/** Called when the controlled open state of the dropdown changes */
|
|
417
|
+
onOpenChange?: (open: boolean) => void;
|
|
418
|
+
/** Whether to show the input border */
|
|
419
|
+
bordered?: boolean;
|
|
420
|
+
/** Additional CSS class name for the outermost wrapper */
|
|
421
|
+
rootClassName?: string;
|
|
422
|
+
/** Whether to show the dropdown arrow icon */
|
|
423
|
+
showArrow?: boolean;
|
|
424
|
+
}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { TreeSelectProps as AntTreeSelectProps } from 'antd';
|
|
2
1
|
import * as React from 'react';
|
|
3
|
-
|
|
4
|
-
export declare const TreeSelect:
|
|
2
|
+
import type { TreeSelectDataNode, TreeSelectProps } from './types';
|
|
3
|
+
export declare const TreeSelect: <ValueType = unknown, OptionType extends TreeSelectDataNode = TreeSelectDataNode>(props: TreeSelectProps<ValueType, OptionType>) => React.JSX.Element;
|
|
4
|
+
export type { TreeSelectDataNode, TreeSelectProps };
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/esm/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAInE,eAAO,MAAM,UAAU,GACrB,SAAS,GAAG,OAAO,EACnB,UAAU,SAAS,kBAAkB,GAAG,kBAAkB,EAE1D,OAAO,eAAe,CAAC,SAAS,EAAE,UAAU,CAAC,sBA8I9C,CAAC;AAEF,YAAY,EAAE,kBAAkB,EAAE,eAAe,EAAE,CAAC"}
|
package/dist/esm/index.js
CHANGED
|
@@ -1,17 +1,113 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
-
t[p[i]] = s[p[i]];
|
|
9
|
-
}
|
|
10
|
-
return t;
|
|
11
|
-
};
|
|
12
|
-
import { TreeSelect as AntTreeSelect } from 'antd';
|
|
1
|
+
import { Icon } from '@akinon/icons';
|
|
2
|
+
import { useToken } from '@akinon/ui-theme';
|
|
3
|
+
import { useStyleRegister } from '@ant-design/cssinjs';
|
|
4
|
+
import { ConfigProvider, TreeSelect as AntTreeSelect } from 'antd';
|
|
5
|
+
import classNames from 'classnames';
|
|
13
6
|
import * as React from 'react';
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
const TREE_LINE = { showLeafIcon: false };
|
|
8
|
+
export const TreeSelect = (props) => {
|
|
9
|
+
const { getPrefixCls, theme } = React.useContext(ConfigProvider.ConfigContext);
|
|
10
|
+
const { token, hashId } = useToken();
|
|
11
|
+
const treeSelectToken = token.TreeSelect;
|
|
12
|
+
const treeSelectPrefixCls = `${getPrefixCls()}-tree-select`;
|
|
13
|
+
const selectTreePrefixCls = `${getPrefixCls()}-select-tree`;
|
|
14
|
+
const dropdownPrefixCls = `${treeSelectPrefixCls}-dropdown`;
|
|
15
|
+
const dropdownPrefixClsWithHash = `:where(.${hashId}).${dropdownPrefixCls}`;
|
|
16
|
+
const switcherIconCls = `${treeSelectPrefixCls}-switcher-icon`;
|
|
17
|
+
const switcherIconExpandedCls = `${switcherIconCls}-expanded`;
|
|
18
|
+
const switcherIconCollapsedCls = `${switcherIconCls}-collapsed`;
|
|
19
|
+
const useStyle = useStyleRegister({
|
|
20
|
+
token: token,
|
|
21
|
+
path: ['TreeSelect'],
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
23
|
+
theme: theme
|
|
24
|
+
}, () => {
|
|
25
|
+
return {
|
|
26
|
+
[dropdownPrefixClsWithHash]: {
|
|
27
|
+
[`.${selectTreePrefixCls}-title`]: {
|
|
28
|
+
color: treeSelectToken.optionTitleColor
|
|
29
|
+
},
|
|
30
|
+
[`.${selectTreePrefixCls}-node-selected`]: {
|
|
31
|
+
[`.${selectTreePrefixCls}-title`]: {
|
|
32
|
+
color: treeSelectToken.optionActiveColor,
|
|
33
|
+
fontWeight: treeSelectToken.optionActiveFontWeight
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
[`.${selectTreePrefixCls}`]: {
|
|
37
|
+
[`.${selectTreePrefixCls}-switcher`]: {
|
|
38
|
+
color: treeSelectToken.optionSwitcherColor,
|
|
39
|
+
[`&.${selectTreePrefixCls}-switcher_close`]: {
|
|
40
|
+
height: treeSelectToken.titleHeight
|
|
41
|
+
},
|
|
42
|
+
[`&.${selectTreePrefixCls}-switcher_open`]: {
|
|
43
|
+
height: treeSelectToken.titleHeight
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
[`.${selectTreePrefixCls}-treenode-active`]: {
|
|
47
|
+
[`.${selectTreePrefixCls}-node-content-wrapper`]: {
|
|
48
|
+
backgroundColor: treeSelectToken.nodeContentWrapperActiveHoverBg
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
[`.${selectTreePrefixCls}-treenode`]: {
|
|
52
|
+
marginBottom: `${treeSelectToken.treeNodeMarginBottom} !important`,
|
|
53
|
+
'&::before': {
|
|
54
|
+
display: treeSelectToken.treeNodeBeforeDisplay
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
[`.${treeSelectPrefixCls}-switcher-icon-wrapper`]: {
|
|
59
|
+
border: treeSelectToken.switcherIconWrapperBorder,
|
|
60
|
+
borderRadius: treeSelectToken.optionSwitcherBorderRadius,
|
|
61
|
+
height: treeSelectToken.switcherIconWrapperSize,
|
|
62
|
+
width: treeSelectToken.switcherIconWrapperSize,
|
|
63
|
+
marginTop: treeSelectToken.switcherIconWrapperMarginTop,
|
|
64
|
+
backgroundColor: treeSelectToken.switcherIconWrapperBg
|
|
65
|
+
},
|
|
66
|
+
[`.${switcherIconCls}`]: {
|
|
67
|
+
marginLeft: treeSelectToken.switcherIconMarginLeft,
|
|
68
|
+
marginBottom: treeSelectToken.switcherIconMarginBottom
|
|
69
|
+
},
|
|
70
|
+
[`.${switcherIconExpandedCls}`]: {
|
|
71
|
+
transform: treeSelectToken.switcherIconExpandedTransform
|
|
72
|
+
},
|
|
73
|
+
[`.${switcherIconCollapsedCls}`]: {
|
|
74
|
+
transform: treeSelectToken.switcherIconCollapsedTransform
|
|
75
|
+
},
|
|
76
|
+
[`.${selectTreePrefixCls}-indent-unit::before`]: {
|
|
77
|
+
borderInlineEnd: `${treeSelectToken.nodeBeforeLineBorder} !important`,
|
|
78
|
+
insetInlineEnd: `${treeSelectToken.indentLineInsetEnd} !important`
|
|
79
|
+
},
|
|
80
|
+
[`.${selectTreePrefixCls}-indent-unit.${selectTreePrefixCls}-indent-unit-end::before`]: {
|
|
81
|
+
display: 'block !important',
|
|
82
|
+
borderInlineEnd: `${treeSelectToken.nodeBeforeLineBorder} !important`,
|
|
83
|
+
insetInlineEnd: `${treeSelectToken.indentLineInsetEnd} !important`
|
|
84
|
+
},
|
|
85
|
+
[`.${selectTreePrefixCls}-switcher-leaf-line`]: {
|
|
86
|
+
'&::before': {
|
|
87
|
+
borderInlineEnd: `${treeSelectToken.nodeBeforeLineBorder} !important`,
|
|
88
|
+
insetInlineStart: `${treeSelectToken.leafLineInsetStart} !important`
|
|
89
|
+
},
|
|
90
|
+
'&::after': {
|
|
91
|
+
borderBottom: `${treeSelectToken.nodeBeforeLineBorder} !important`
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
[`.${selectTreePrefixCls}-treenode`]: {
|
|
95
|
+
'&:hover': {
|
|
96
|
+
backgroundColor: treeSelectToken.nodeContentWrapperActiveBg
|
|
97
|
+
},
|
|
98
|
+
[`&.${selectTreePrefixCls}-treenode-selected`]: {
|
|
99
|
+
backgroundColor: treeSelectToken.nodeContentWrapperActiveBg
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
[`.${selectTreePrefixCls}-node-content-wrapper, .${selectTreePrefixCls}-node-content-wrapper-normal`]: {
|
|
103
|
+
marginInlineStart: treeSelectToken.nodeContentWrapperMarginInlineStart
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
});
|
|
108
|
+
const renderSwitcherIcon = (nodeProps) => (React.createElement("span", { className: `${treeSelectPrefixCls}-switcher-icon-wrapper` },
|
|
109
|
+
React.createElement(Icon, { icon: "triangle", size: 8, className: classNames(switcherIconCls, nodeProps.expanded
|
|
110
|
+
? switcherIconExpandedCls
|
|
111
|
+
: switcherIconCollapsedCls) })));
|
|
112
|
+
return useStyle(React.createElement(AntTreeSelect, Object.assign({ size: "large", popupMatchSelectWidth: true }, props, { treeLine: TREE_LINE, switcherIcon: renderSwitcherIcon })));
|
|
17
113
|
};
|
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
import type { DO_NOT_USE_OR_YOU_WILL_BE_FIRED_INTERNAL_STYLE } from '@akinon/ui-theme';
|
|
2
|
+
import type * as React from 'react';
|
|
3
|
+
|
|
4
|
+
type Key = string | number;
|
|
5
|
+
|
|
6
|
+
type SafeKey = string | number;
|
|
7
|
+
|
|
8
|
+
export interface TreeSelectDataNode extends Record<string, unknown> {
|
|
9
|
+
/** Unique key for the node */
|
|
10
|
+
key?: Key;
|
|
11
|
+
/** Value used for selection and filtering */
|
|
12
|
+
value?: SafeKey;
|
|
13
|
+
/** Node label */
|
|
14
|
+
title?: React.ReactNode;
|
|
15
|
+
children?: TreeSelectDataNode[];
|
|
16
|
+
/** Disable this node */
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
/** Whether the node can be selected */
|
|
19
|
+
selectable?: boolean;
|
|
20
|
+
/** Show checkbox for this node when tree is checkable */
|
|
21
|
+
checkable?: boolean;
|
|
22
|
+
/** Disable checkbox for this node */
|
|
23
|
+
disableCheckbox?: boolean;
|
|
24
|
+
/** Treat as leaf (no children) */
|
|
25
|
+
isLeaf?: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface TreeNodeProps {
|
|
29
|
+
checkable?: boolean;
|
|
30
|
+
disableCheckbox?: boolean;
|
|
31
|
+
disabled?: boolean;
|
|
32
|
+
isLeaf?: boolean;
|
|
33
|
+
key?: Key;
|
|
34
|
+
selectable?: boolean;
|
|
35
|
+
title?: React.ReactNode;
|
|
36
|
+
value?: SafeKey;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface FieldNames {
|
|
40
|
+
/** Field name for value */
|
|
41
|
+
value?: string;
|
|
42
|
+
/** Field name for label */
|
|
43
|
+
label?: string;
|
|
44
|
+
/** Field name for children */
|
|
45
|
+
children?: string;
|
|
46
|
+
_title?: string[];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface SimpleModeConfig {
|
|
50
|
+
id?: SafeKey;
|
|
51
|
+
pId?: SafeKey;
|
|
52
|
+
rootPId?: SafeKey;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
interface LabeledValueType {
|
|
56
|
+
key?: Key;
|
|
57
|
+
value?: SafeKey;
|
|
58
|
+
label?: React.ReactNode;
|
|
59
|
+
/** Option is partially checked (e.g. parent with some children selected) */
|
|
60
|
+
halfChecked?: boolean;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface ChangeEventExtra {
|
|
64
|
+
preValue: LabeledValueType[];
|
|
65
|
+
triggerValue: SafeKey;
|
|
66
|
+
selected?: boolean;
|
|
67
|
+
checked?: boolean;
|
|
68
|
+
triggerNode: React.ReactElement;
|
|
69
|
+
allCheckedNodes: unknown[];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
interface LegacyDataNode extends TreeSelectDataNode {
|
|
73
|
+
props: unknown;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
type CheckedStrategy = 'SHOW_ALL' | 'SHOW_PARENT' | 'SHOW_CHILD';
|
|
77
|
+
|
|
78
|
+
type TreeExpandAction = false | 'click' | 'doubleclick';
|
|
79
|
+
|
|
80
|
+
type SizeType = 'small' | 'middle' | 'large' | undefined;
|
|
81
|
+
|
|
82
|
+
type SelectCommonPlacement =
|
|
83
|
+
| 'bottomLeft'
|
|
84
|
+
| 'bottomRight'
|
|
85
|
+
| 'topLeft'
|
|
86
|
+
| 'topRight';
|
|
87
|
+
|
|
88
|
+
type InputStatus = 'warning' | 'error' | '';
|
|
89
|
+
|
|
90
|
+
type Variant = 'outlined' | 'borderless' | 'filled' | 'underlined';
|
|
91
|
+
|
|
92
|
+
type TreeShowLine = boolean | { showLeafIcon?: boolean | React.ReactNode };
|
|
93
|
+
|
|
94
|
+
interface TreeNodePropsForSwitcher {
|
|
95
|
+
expanded?: boolean;
|
|
96
|
+
isLeaf?: boolean;
|
|
97
|
+
[key: string]: unknown;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
type SwitcherIcon =
|
|
101
|
+
| React.ReactNode
|
|
102
|
+
| ((props: TreeNodePropsForSwitcher) => React.ReactNode);
|
|
103
|
+
|
|
104
|
+
type TreeIconType =
|
|
105
|
+
| React.ReactNode
|
|
106
|
+
| ((props: TreeNodePropsForSwitcher) => React.ReactNode);
|
|
107
|
+
|
|
108
|
+
type SemanticDOM = 'root';
|
|
109
|
+
|
|
110
|
+
type PopupSemanticDOM = 'root';
|
|
111
|
+
|
|
112
|
+
interface ClassNamesStylesInfo<
|
|
113
|
+
V = unknown,
|
|
114
|
+
O extends TreeSelectDataNode = TreeSelectDataNode
|
|
115
|
+
> {
|
|
116
|
+
props: TreeSelectProps<V, O>;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
type SemanticName = 'root';
|
|
120
|
+
type PopupSemantic = 'root';
|
|
121
|
+
|
|
122
|
+
interface ShowSearchObject {
|
|
123
|
+
/** Clear search when selection changes (multiple mode) */
|
|
124
|
+
autoClearSearchValue?: boolean;
|
|
125
|
+
/** Filter nodes by search; use treeNodeFilterProp field or custom function */
|
|
126
|
+
filterTreeNode?:
|
|
127
|
+
| boolean
|
|
128
|
+
| ((inputValue: string, treeNode: TreeSelectDataNode) => boolean);
|
|
129
|
+
/** Controlled search value; use with onSearch */
|
|
130
|
+
searchValue?: string;
|
|
131
|
+
/** Property name used for filtering */
|
|
132
|
+
treeNodeFilterProp?: string;
|
|
133
|
+
/** Called when search input changes */
|
|
134
|
+
onSearch?: (value: string) => void;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
interface LabeledValue {
|
|
138
|
+
key?: string;
|
|
139
|
+
value: string | number;
|
|
140
|
+
label: React.ReactNode;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
type SelectValue =
|
|
144
|
+
| (string | number)
|
|
145
|
+
| (string | number)[]
|
|
146
|
+
| LabeledValue
|
|
147
|
+
| LabeledValue[];
|
|
148
|
+
|
|
149
|
+
interface TagRenderProps {
|
|
150
|
+
label: React.ReactNode;
|
|
151
|
+
value: SafeKey | LabeledValueType;
|
|
152
|
+
disabled?: boolean;
|
|
153
|
+
onClose: () => void;
|
|
154
|
+
closable: boolean;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
interface TreeSelectRef {
|
|
158
|
+
blur: () => void;
|
|
159
|
+
focus: () => void;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export interface TreeSelectProps<
|
|
163
|
+
ValueType = unknown,
|
|
164
|
+
OptionType extends TreeSelectDataNode = TreeSelectDataNode
|
|
165
|
+
> extends React.AriaAttributes {
|
|
166
|
+
/** Whether to show a clear button to remove the selection. */
|
|
167
|
+
allowClear?: boolean | { clearIcon?: React.ReactNode };
|
|
168
|
+
|
|
169
|
+
/** CSS class names for component parts (object or function) */
|
|
170
|
+
classNames?:
|
|
171
|
+
| (Partial<Record<SemanticName, string>> & {
|
|
172
|
+
popup?: Partial<Record<PopupSemantic, string>>;
|
|
173
|
+
})
|
|
174
|
+
| ((
|
|
175
|
+
info: ClassNamesStylesInfo<ValueType, OptionType>
|
|
176
|
+
) => Partial<Record<SemanticDOM, string>>);
|
|
177
|
+
|
|
178
|
+
/** Dropdown open by default */
|
|
179
|
+
defaultOpen?: boolean;
|
|
180
|
+
|
|
181
|
+
/** Initial selected value(s) */
|
|
182
|
+
defaultValue?: ValueType;
|
|
183
|
+
|
|
184
|
+
/** Whether the tree select is disabled */
|
|
185
|
+
disabled?: boolean;
|
|
186
|
+
|
|
187
|
+
/** Match dropdown width to input; false disables virtual scroll */
|
|
188
|
+
popupMatchSelectWidth?: boolean | number;
|
|
189
|
+
|
|
190
|
+
/** Customize dropdown content wrapper */
|
|
191
|
+
popupRender?: (
|
|
192
|
+
originNode: React.ReactNode,
|
|
193
|
+
props: { menu: React.ReactNode }
|
|
194
|
+
) => React.ReactNode;
|
|
195
|
+
|
|
196
|
+
/** Map data fields to label, value, children */
|
|
197
|
+
fieldNames?: FieldNames;
|
|
198
|
+
|
|
199
|
+
/** Container element for dropdown */
|
|
200
|
+
getPopupContainer?: (triggerNode: HTMLElement) => HTMLElement;
|
|
201
|
+
|
|
202
|
+
/** Value shape: { value, label, halfChecked } instead of raw value */
|
|
203
|
+
labelInValue?: boolean;
|
|
204
|
+
|
|
205
|
+
/** Dropdown list height (px) */
|
|
206
|
+
listHeight?: number;
|
|
207
|
+
|
|
208
|
+
/** Load children asynchronously for a node */
|
|
209
|
+
loadData?: (node: LegacyDataNode) => Promise<unknown>;
|
|
210
|
+
|
|
211
|
+
/** Max number of tags shown in multiple mode; 'responsive' adapts to width */
|
|
212
|
+
maxTagCount?: number | 'responsive';
|
|
213
|
+
|
|
214
|
+
/** Max selected items when multiple (and not using parent-only strategy) */
|
|
215
|
+
maxCount?: number;
|
|
216
|
+
|
|
217
|
+
/** Placeholder when tags are collapsed (e.g. "+ N more") */
|
|
218
|
+
maxTagPlaceholder?:
|
|
219
|
+
| React.ReactNode
|
|
220
|
+
| ((omittedValues: unknown[]) => React.ReactNode);
|
|
221
|
+
|
|
222
|
+
/** Max length of tag text before truncation */
|
|
223
|
+
maxTagTextLength?: number;
|
|
224
|
+
|
|
225
|
+
/** Allow multiple selection */
|
|
226
|
+
multiple?: boolean;
|
|
227
|
+
|
|
228
|
+
/** Content when no options match */
|
|
229
|
+
notFoundContent?: React.ReactNode;
|
|
230
|
+
|
|
231
|
+
/** Controlled dropdown open state */
|
|
232
|
+
open?: boolean;
|
|
233
|
+
|
|
234
|
+
/** Placeholder for the input */
|
|
235
|
+
placeholder?: React.ReactNode;
|
|
236
|
+
|
|
237
|
+
/** Dropdown position */
|
|
238
|
+
placement?: SelectCommonPlacement;
|
|
239
|
+
|
|
240
|
+
/** Prefix content */
|
|
241
|
+
prefix?: React.ReactNode;
|
|
242
|
+
|
|
243
|
+
/** Which checked nodes to show in multiple: all, parent only, or child only */
|
|
244
|
+
showCheckedStrategy?: CheckedStrategy;
|
|
245
|
+
|
|
246
|
+
/** Enable search; use object for options (filter, onSearch, etc.) */
|
|
247
|
+
showSearch?: boolean | ShowSearchObject;
|
|
248
|
+
|
|
249
|
+
size?: SizeType;
|
|
250
|
+
|
|
251
|
+
/** Validation state */
|
|
252
|
+
status?: InputStatus;
|
|
253
|
+
|
|
254
|
+
/** Suffix content */
|
|
255
|
+
suffixIcon?: React.ReactNode;
|
|
256
|
+
|
|
257
|
+
/** Custom expand/collapse icon */
|
|
258
|
+
switcherIcon?: SwitcherIcon;
|
|
259
|
+
|
|
260
|
+
styles?: DO_NOT_USE_OR_YOU_WILL_BE_FIRED_INTERNAL_STYLE;
|
|
261
|
+
|
|
262
|
+
/** Custom tag render in multiple mode */
|
|
263
|
+
tagRender?: (props: TagRenderProps) => React.ReactNode;
|
|
264
|
+
|
|
265
|
+
/** Show checkboxes on nodes */
|
|
266
|
+
treeCheckable?: boolean;
|
|
267
|
+
|
|
268
|
+
/** Parent/child checkboxes independent; enables labelInValue */
|
|
269
|
+
treeCheckStrictly?: boolean;
|
|
270
|
+
|
|
271
|
+
/** Tree data (array of nodes); each value should be unique */
|
|
272
|
+
treeData?: OptionType[];
|
|
273
|
+
|
|
274
|
+
/** Use flat data with id/pId; optional config for custom id/pId keys */
|
|
275
|
+
treeDataSimpleMode?: boolean | SimpleModeConfig;
|
|
276
|
+
|
|
277
|
+
/** Custom render for node title */
|
|
278
|
+
treeTitleRender?: (nodeData: OptionType) => React.ReactNode;
|
|
279
|
+
|
|
280
|
+
/** Expand all nodes initially */
|
|
281
|
+
treeDefaultExpandAll?: boolean;
|
|
282
|
+
|
|
283
|
+
/** Initially expanded node keys */
|
|
284
|
+
treeDefaultExpandedKeys?: SafeKey[];
|
|
285
|
+
|
|
286
|
+
/** Expand on click, double-click, or disable */
|
|
287
|
+
treeExpandAction?: TreeExpandAction;
|
|
288
|
+
|
|
289
|
+
/** Controlled expanded keys */
|
|
290
|
+
treeExpandedKeys?: SafeKey[];
|
|
291
|
+
|
|
292
|
+
/** Icon before node title */
|
|
293
|
+
treeIcon?: TreeIconType;
|
|
294
|
+
|
|
295
|
+
/** Loaded node keys (with loadData); controlled */
|
|
296
|
+
treeLoadedKeys?: SafeKey[];
|
|
297
|
+
|
|
298
|
+
/** Show connection lines between nodes */
|
|
299
|
+
treeLine?: TreeShowLine;
|
|
300
|
+
|
|
301
|
+
/** Data property to use as node label in select */
|
|
302
|
+
treeNodeLabelProp?: string;
|
|
303
|
+
|
|
304
|
+
/** Controlled selected value(s) */
|
|
305
|
+
value?: ValueType;
|
|
306
|
+
|
|
307
|
+
/** Variant of the tree select */
|
|
308
|
+
variant?: Variant;
|
|
309
|
+
|
|
310
|
+
/** Use virtual scroll in dropdown */
|
|
311
|
+
virtual?: boolean;
|
|
312
|
+
|
|
313
|
+
/** Called when selection or input value changes */
|
|
314
|
+
onChange?: (
|
|
315
|
+
value: ValueType,
|
|
316
|
+
labelList: React.ReactNode[],
|
|
317
|
+
extra: ChangeEventExtra
|
|
318
|
+
) => void;
|
|
319
|
+
|
|
320
|
+
/** Called when a node is selected */
|
|
321
|
+
onSelect?: (
|
|
322
|
+
value: ValueType,
|
|
323
|
+
node: OptionType,
|
|
324
|
+
extra: ChangeEventExtra
|
|
325
|
+
) => void;
|
|
326
|
+
|
|
327
|
+
/** Called when expanded keys change */
|
|
328
|
+
onTreeExpand?: (expandedKeys: SafeKey[]) => void;
|
|
329
|
+
|
|
330
|
+
/** Called when the popup scrolls */
|
|
331
|
+
onPopupScroll?: React.UIEventHandler<HTMLDivElement>;
|
|
332
|
+
|
|
333
|
+
/** Clear search when selection changes (when showSearch is true) */
|
|
334
|
+
autoClearSearchValue?: boolean;
|
|
335
|
+
|
|
336
|
+
/** Filter tree by search; boolean or custom filter function */
|
|
337
|
+
filterTreeNode?:
|
|
338
|
+
| boolean
|
|
339
|
+
| ((inputValue: string, treeNode: OptionType) => boolean);
|
|
340
|
+
|
|
341
|
+
/** Controlled search value */
|
|
342
|
+
searchValue?: string;
|
|
343
|
+
|
|
344
|
+
/** Data property used for search filtering */
|
|
345
|
+
treeNodeFilterProp?: string;
|
|
346
|
+
|
|
347
|
+
/** Called when search input changes */
|
|
348
|
+
onSearch?: (value: string) => void;
|
|
349
|
+
|
|
350
|
+
/** CSS class name */
|
|
351
|
+
className?: string;
|
|
352
|
+
|
|
353
|
+
style?: DO_NOT_USE_OR_YOU_WILL_BE_FIRED_INTERNAL_STYLE;
|
|
354
|
+
|
|
355
|
+
/** Tooltip text (title attribute) for the trigger element */
|
|
356
|
+
title?: string;
|
|
357
|
+
/** Text direction for the input and dropdown */
|
|
358
|
+
direction?: 'ltr' | 'rtl';
|
|
359
|
+
/** Maximum number of characters allowed in the input */
|
|
360
|
+
maxLength?: number;
|
|
361
|
+
/** Tab order index of the trigger element */
|
|
362
|
+
tabIndex?: number;
|
|
363
|
+
/** Auto focus the input on mount */
|
|
364
|
+
autoFocus?: boolean;
|
|
365
|
+
/** Called after the clear icon clears the current value */
|
|
366
|
+
onClear?: () => void;
|
|
367
|
+
/** Show loading state and spinner */
|
|
368
|
+
loading?: boolean;
|
|
369
|
+
/** Inline style object applied to the dropdown menu */
|
|
370
|
+
dropdownStyle?: DO_NOT_USE_OR_YOU_WILL_BE_FIRED_INTERNAL_STYLE;
|
|
371
|
+
/** Additional CSS class name for the dropdown menu */
|
|
372
|
+
dropdownClassName?: string;
|
|
373
|
+
/** Match dropdown width to select; number sets explicit pixel width */
|
|
374
|
+
dropdownMatchSelectWidth?: boolean | number;
|
|
375
|
+
/** Custom render function for the dropdown; lets you wrap or extend the default menu */
|
|
376
|
+
dropdownRender?: (menu: React.ReactElement) => React.ReactElement;
|
|
377
|
+
/** Called when the trigger loses focus */
|
|
378
|
+
onBlur?: React.FocusEventHandler<HTMLElement>;
|
|
379
|
+
/** Called when the trigger receives focus */
|
|
380
|
+
onFocus?: React.FocusEventHandler<HTMLElement>;
|
|
381
|
+
/** Keyboard keyup event handler on the trigger wrapper */
|
|
382
|
+
onKeyUp?: React.KeyboardEventHandler<HTMLDivElement>;
|
|
383
|
+
/** Keyboard keydown event handler on the trigger wrapper */
|
|
384
|
+
onKeyDown?: React.KeyboardEventHandler<HTMLDivElement>;
|
|
385
|
+
/** Mousedown event handler on the trigger wrapper */
|
|
386
|
+
onMouseDown?: React.MouseEventHandler<HTMLDivElement>;
|
|
387
|
+
/** Keyboard keydown handler for the internal input element */
|
|
388
|
+
onInputKeyDown?: React.KeyboardEventHandler<
|
|
389
|
+
HTMLInputElement | HTMLTextAreaElement
|
|
390
|
+
>;
|
|
391
|
+
/** Mouse enter event handler on the trigger wrapper */
|
|
392
|
+
onMouseEnter?: React.MouseEventHandler<HTMLDivElement>;
|
|
393
|
+
/** Mouse leave event handler on the trigger wrapper */
|
|
394
|
+
onMouseLeave?: React.MouseEventHandler<HTMLDivElement>;
|
|
395
|
+
/** Click event handler on the trigger wrapper */
|
|
396
|
+
onClick?: React.MouseEventHandler<HTMLDivElement>;
|
|
397
|
+
/** HTML id attribute for the trigger element */
|
|
398
|
+
id?: string;
|
|
399
|
+
/** Option nodes rendered as children instead of using treeData */
|
|
400
|
+
children?: React.ReactNode;
|
|
401
|
+
/** Controlled input text value (typically used with search) */
|
|
402
|
+
inputValue?: string;
|
|
403
|
+
/** Called when a value is deselected (mainly in multiple mode) */
|
|
404
|
+
onDeselect?: (value: ValueType, option: OptionType) => void;
|
|
405
|
+
/** Virtual list item height in pixels */
|
|
406
|
+
listItemHeight?: number;
|
|
407
|
+
/** Virtual list scroll offset per item for performance tuning */
|
|
408
|
+
listItemScrollOffset?: number;
|
|
409
|
+
/** Whether to render switcher/leaf icons next to each tree node */
|
|
410
|
+
showTreeIcon?: boolean;
|
|
411
|
+
prefixCls?: string;
|
|
412
|
+
/** Additional CSS class name for the popup container */
|
|
413
|
+
popupClassName?: string;
|
|
414
|
+
/** Called when dropdown visibility changes */
|
|
415
|
+
onDropdownVisibleChange?: (visible: boolean) => void;
|
|
416
|
+
/** Called when the controlled open state of the dropdown changes */
|
|
417
|
+
onOpenChange?: (open: boolean) => void;
|
|
418
|
+
/** Whether to show the input border */
|
|
419
|
+
bordered?: boolean;
|
|
420
|
+
/** Additional CSS class name for the outermost wrapper */
|
|
421
|
+
rootClassName?: string;
|
|
422
|
+
/** Whether to show the dropdown arrow icon */
|
|
423
|
+
showArrow?: boolean;
|
|
424
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akinon/ui-tree-select",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/esm/index.js",
|
|
@@ -9,14 +9,18 @@
|
|
|
9
9
|
"dist"
|
|
10
10
|
],
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"
|
|
12
|
+
"@ant-design/cssinjs": "^1.24.0",
|
|
13
|
+
"antd": "^5.27.0",
|
|
14
|
+
"classnames": "^2.5.1",
|
|
15
|
+
"@akinon/icons": "1.2.5",
|
|
16
|
+
"@akinon/ui-theme": "1.2.5"
|
|
13
17
|
},
|
|
14
18
|
"devDependencies": {
|
|
15
19
|
"clean-package": "2.2.0",
|
|
16
20
|
"copyfiles": "^2.4.1",
|
|
17
21
|
"rimraf": "^5.0.5",
|
|
18
22
|
"typescript": "*",
|
|
19
|
-
"@akinon/typescript-config": "1.1.
|
|
23
|
+
"@akinon/typescript-config": "1.1.5"
|
|
20
24
|
},
|
|
21
25
|
"peerDependencies": {
|
|
22
26
|
"react": "^18 || ^19",
|