conditional-selection 1.0.0

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.
@@ -0,0 +1,134 @@
1
+ import React from 'react';
2
+ import ConditionalChoose from './conditional-choose';
3
+ import ConditionalHandle from './conditional-handle';
4
+ import {
5
+ EConditionalSelectionLink,
6
+ type TConditionalSelection,
7
+ type TConditionalSelectionDisabledProps,
8
+ } from '../types';
9
+ import { isGroup } from '../composables/useConditionalHandle';
10
+ interface IConditionalContentProps {
11
+ levelData: TConditionalSelection;
12
+ level: number;
13
+ disabledConfig: Required<TConditionalSelectionDisabledProps>;
14
+ onUpdateNode: (nodeId: string, patch: Partial<TConditionalSelection>) => void;
15
+ onCreateRules: (ruleData: TConditionalSelection) => void;
16
+ onCreateChildRules: (ruleData: TConditionalSelection) => void;
17
+ onDelRules: (ruleData: TConditionalSelection, index: number) => void;
18
+ /** 渲染单行条件内容 */
19
+ renderConditionItem?: (rulesLevelItem: TConditionalSelection) => React.ReactNode;
20
+ }
21
+
22
+ /**
23
+ * 获取是否是"最后一个条件"位置,用于控制同级新增按钮
24
+ */
25
+ function getLastCondition(index: number, group: TConditionalSelection[]): boolean {
26
+ const lastIndex = group.length - 1;
27
+ const tempInfo = group[lastIndex];
28
+ let flag = index === lastIndex;
29
+ if (!flag && tempInfo && isGroup(tempInfo)) {
30
+ flag = index === group.length - 2;
31
+ }
32
+ return flag;
33
+ }
34
+
35
+ /**
36
+ * 条件内容组件(递归渲染嵌套规则树)
37
+ * 对应 Vue 版 relation-content.vue
38
+ */
39
+ const ConditionalContent: React.FC<IConditionalContentProps> = ({
40
+ levelData,
41
+ level,
42
+ disabledConfig,
43
+ onUpdateNode,
44
+ onCreateRules,
45
+ onCreateChildRules,
46
+ onDelRules,
47
+ renderConditionItem,
48
+ }) => {
49
+ const group = levelData.group as TConditionalSelection[];
50
+
51
+ function handleLinkChange(value: EConditionalSelectionLink) {
52
+ onUpdateNode(levelData._id, { link: value });
53
+ }
54
+
55
+ return (
56
+ <div className="relative-box">
57
+ {/* 且/或 切换 */}
58
+ <ConditionalChoose
59
+ value={levelData.link ?? EConditionalSelectionLink.AND}
60
+ disabled={disabledConfig.linkChange}
61
+ onChange={handleLinkChange}
62
+ />
63
+
64
+ <div className="conditional-list-box right-box">
65
+ {group.map((item, index) => {
66
+ if (isGroup(item)) {
67
+ const childRules = item.group as TConditionalSelection[];
68
+ return (
69
+ <div key={item._id} className="conditional-list">
70
+ <div className="relative-box">
71
+ <ConditionalChoose
72
+ value={item.link ?? EConditionalSelectionLink.AND}
73
+ disabled={disabledConfig.linkChange}
74
+ onChange={val => onUpdateNode(item._id, { link: val })}
75
+ />
76
+ {childRules.map((child, childIndex) => {
77
+ if (isGroup(child) && (child.group as TConditionalSelection[]).length > 0) {
78
+ return (
79
+ <div key={child._id} className="conditional-item right-box">
80
+ <ConditionalContent
81
+ levelData={child}
82
+ level={level}
83
+ disabledConfig={disabledConfig}
84
+ onUpdateNode={onUpdateNode}
85
+ onCreateRules={onCreateRules}
86
+ onCreateChildRules={onCreateChildRules}
87
+ onDelRules={onDelRules}
88
+ renderConditionItem={renderConditionItem}
89
+ />
90
+ </div>
91
+ );
92
+ }
93
+ return (
94
+ <div key={child._id} className="conditional-item right-box">
95
+ {renderConditionItem?.(child)}
96
+ <ConditionalHandle
97
+ level={level}
98
+ disabledConfig={disabledConfig}
99
+ currentItemInfo={child}
100
+ isLast={getLastCondition(childIndex, childRules)}
101
+ onCreate={() => onCreateRules(item)}
102
+ onCreateChildRules={() => onCreateChildRules(child)}
103
+ onDel={() => onDelRules(item, childIndex)}
104
+ />
105
+ </div>
106
+ );
107
+ })}
108
+ </div>
109
+ </div>
110
+ );
111
+ }
112
+ return (
113
+ <div key={item._id} className="conditional-list">
114
+ <div className="conditional-item">
115
+ {renderConditionItem?.(item)}
116
+ <ConditionalHandle
117
+ level={level}
118
+ disabledConfig={disabledConfig}
119
+ currentItemInfo={item}
120
+ isLast={getLastCondition(index, group)}
121
+ onCreate={() => onCreateRules(levelData)}
122
+ onCreateChildRules={() => onCreateChildRules(item)}
123
+ onDel={() => onDelRules(levelData, index)}
124
+ />
125
+ </div>
126
+ </div>
127
+ );
128
+ })}
129
+ </div>
130
+ </div>
131
+ );
132
+ };
133
+
134
+ export default ConditionalContent;
@@ -0,0 +1,83 @@
1
+ import React, { useMemo } from 'react';
2
+ import type {
3
+ TConditionalSelection,
4
+ TConditionalSelectionDisabledProps,
5
+ } from '../types';
6
+
7
+ interface IConditionalHandleProps {
8
+ level: number;
9
+ currentItemInfo: TConditionalSelection;
10
+ isLast: boolean;
11
+ disabledConfig: Required<TConditionalSelectionDisabledProps>;
12
+ onCreate: () => void;
13
+ onCreateChildRules: () => void;
14
+ onDel: () => void;
15
+ }
16
+
17
+ function isEmptyValue(val: unknown): boolean {
18
+ if (val === null || val === undefined || val === '') return true;
19
+ if (Array.isArray(val)) return val.length === 0;
20
+ if (val !== null && typeof val === 'object') return Object.keys(val as object).length === 0;
21
+ return false;
22
+ }
23
+
24
+ function allHave(individual?: Record<string, any>): boolean {
25
+ return (
26
+ !!individual &&
27
+ Object.keys(individual).length > 0 &&
28
+ Object.keys(individual).every((key: string) => !isEmptyValue(individual[key]))
29
+ );
30
+ }
31
+
32
+ /**
33
+ * 规则操作按钮组(同级/子集/删除)
34
+ */
35
+ const ConditionalHandle: React.FC<IConditionalHandleProps> = ({
36
+ level,
37
+ currentItemInfo,
38
+ isLast,
39
+ disabledConfig,
40
+ onCreate,
41
+ onCreateChildRules,
42
+ onDel,
43
+ }) => {
44
+ /** 是否显示同级新增按钮:当前节点 level >= 1 且是最后一个 */
45
+ const showCreate = useMemo(() => currentItemInfo.level >= 1 && isLast, [currentItemInfo.level, isLast]);
46
+
47
+ /** 是否显示子集新增按钮:全局 level > 1 且当前节点 level 未达到上限 */
48
+ const showCreateChild = useMemo(() => level > 1 && currentItemInfo.level < level, [level, currentItemInfo.level]);
49
+
50
+ /** 整体新增按钮是否显示:level > 1 && 当前条件已填写完整 && 未禁用新增 */
51
+ const createShow = useMemo(
52
+ () => !!(level > 1 && allHave(currentItemInfo.individual) && !disabledConfig.addItem),
53
+ [level, currentItemInfo.individual, disabledConfig.addItem],
54
+ );
55
+
56
+ return (
57
+ <div className="conditional-handle">
58
+ {createShow && (
59
+ <>
60
+ {showCreate && (
61
+ <span className="create-handle" onClick={onCreate}>
62
+ <span style={{ color: '#c85000', marginRight: 4 }}>+</span>
63
+ 同级
64
+ </span>
65
+ )}
66
+ {showCreateChild && (
67
+ <span className="create-handle" onClick={onCreateChildRules}>
68
+ <span style={{ color: '#c85000', marginRight: 4 }}>+</span>
69
+ 子级
70
+ </span>
71
+ )}
72
+ </>
73
+ )}
74
+ {!disabledConfig.delItem && (
75
+ <span className="del-handle" onClick={onDel}>
76
+
77
+ </span>
78
+ )}
79
+ </div>
80
+ );
81
+ };
82
+
83
+ export default ConditionalHandle;
@@ -0,0 +1,234 @@
1
+ import { useMemo, useCallback } from 'react';
2
+ import { useImmer } from 'use-immer';
3
+ import { cloneDeep } from 'lodash-es';
4
+ import {
5
+ EConditionalSelectionLink,
6
+ EConditionalSelectionFramework,
7
+ type TConditionalSelection,
8
+ type TConditionalSelectionProps,
9
+ type TConditionalSelectionDisabledProps,
10
+ } from '../types';
11
+
12
+ function isObject(val: unknown): val is Record<string, any> {
13
+ return val !== null && typeof val === 'object' && !Array.isArray(val);
14
+ }
15
+
16
+ function isEmptyValue(val: unknown): boolean {
17
+ if (val === null || val === undefined || val === '') return true;
18
+ if (Array.isArray(val)) return val.length === 0;
19
+ if (isObject(val)) return Object.keys(val).length === 0;
20
+ return false;
21
+ }
22
+
23
+ export function getTempRules(level = 0): TConditionalSelection {
24
+ return cloneDeep({
25
+ _id: crypto.randomUUID(),
26
+ framework: EConditionalSelectionFramework.INDIVIDUAL,
27
+ // INDIVIDUAL 节点只保留 individual,不初始化 group
28
+ individual: {},
29
+ level,
30
+ }) as TConditionalSelection;
31
+ }
32
+
33
+ export function isGroup(ruleData: TConditionalSelection): boolean {
34
+ return ruleData.framework === EConditionalSelectionFramework.GROUP;
35
+ }
36
+
37
+ function allHave(individual?: Record<string, any>): boolean {
38
+ return (
39
+ !!individual &&
40
+ Object.keys(individual).length > 0 &&
41
+ Object.keys(individual).every((key: string) => !isEmptyValue(individual[key]))
42
+ );
43
+ }
44
+
45
+ function checkData(data: TConditionalSelection): boolean {
46
+ if (isGroup(data) && Array.isArray(data.group)) {
47
+ // GROUP 节点:递归检查 group 数组中的每个子项
48
+ return data.group.some(item => checkData(item));
49
+ }
50
+ // INDIVIDUAL 节点:检查 individual 是否填写完整
51
+ return !allHave(data.individual);
52
+ }
53
+
54
+ function subtractLevel(rulesData: TConditionalSelection): void {
55
+ // 只有 GROUP 节点才有 group 数组
56
+ if (isGroup(rulesData) && Array.isArray(rulesData.group) && rulesData.group.length > 1) {
57
+ rulesData.group.forEach(item => subtractLevel(item));
58
+ }
59
+ rulesData.level = rulesData.level - 1 < 0 ? 0 : rulesData.level - 1;
60
+ }
61
+
62
+ /** 在树中按 _id 深度优先查找节点 */
63
+ export function findNode(root: TConditionalSelection, id: string): TConditionalSelection | null {
64
+ if (root._id === id) return root;
65
+ if (Array.isArray(root.group)) {
66
+ for (const child of root.group) {
67
+ const found = findNode(child, id);
68
+ if (found) return found;
69
+ }
70
+ }
71
+ return null;
72
+ }
73
+
74
+ export interface IUseConditionalHandleReturn {
75
+ rulesData: TConditionalSelection;
76
+ setRulesData: (data: TConditionalSelection) => void;
77
+ updateRulesData: (updater: (draft: TConditionalSelection) => void) => void;
78
+ level: number;
79
+ disabledConfig: Required<TConditionalSelectionDisabledProps>;
80
+ createRules: (ruleData: TConditionalSelection) => void;
81
+ createChildRules: (ruleData: TConditionalSelection) => void;
82
+ delRules: (ruleData: TConditionalSelection, index: number) => void;
83
+ getConditionalSelectionData: (validate?: boolean) => Promise<TConditionalSelection>;
84
+ isGroup: (ruleData: TConditionalSelection) => boolean;
85
+ getTempRules: (level?: number) => TConditionalSelection;
86
+ }
87
+
88
+ export function useConditionalHandle(props: TConditionalSelectionProps): IUseConditionalHandleReturn {
89
+ const [rulesData, updateRulesData] = useImmer<TConditionalSelection>(() => getTempRules());
90
+
91
+ // 对外保持 setRulesData 接口不变(直接替换整棵树)
92
+ const setRulesData = useCallback((data: TConditionalSelection) => {
93
+ updateRulesData(() => data);
94
+ }, [updateRulesData]);
95
+
96
+ // level 计算
97
+ const level = useMemo(() => {
98
+ const v = Math.abs(Number(props.maxLevel ?? 1)) || 1;
99
+ if (Number(props.maxLevel ?? 1) < 1) {
100
+ console.warn('[TConditionalSelection] Invalid props.maxLevel: maxLevel must be greater than 0.');
101
+ }
102
+ return v;
103
+ }, [props.maxLevel]);
104
+
105
+ // disabledConfig 计算
106
+ const disabledConfig = useMemo<Required<TConditionalSelectionDisabledProps>>(() => {
107
+ const isObj = isObject(props.disabled);
108
+ return {
109
+ addItem: !!(isObj ? (props.disabled as TConditionalSelectionDisabledProps)?.addItem : props.disabled),
110
+ delItem: !!(isObj ? (props.disabled as TConditionalSelectionDisabledProps)?.delItem : props.disabled),
111
+ linkChange: !!(isObj ? (props.disabled as TConditionalSelectionDisabledProps)?.linkChange : props.disabled),
112
+ };
113
+ }, [props.disabled]);
114
+
115
+ // 创建同级规则:向当前 GROUP 节点的 group 数组追加一个新 INDIVIDUAL 节点
116
+ const createRules = useCallback(
117
+ (ruleData: TConditionalSelection) => {
118
+ if (!isGroup(ruleData)) return;
119
+ const maxLen = Math.abs(Number(props.zeroLevelMaxLength));
120
+ if (maxLen) {
121
+ if (Number(props.zeroLevelMaxLength) < 2) {
122
+ console.warn(
123
+ '[TConditionalSelection] Invalid props.zeroLevelMaxLength: zeroLevelMaxLength must be greater than 1.',
124
+ );
125
+ }
126
+ if (ruleData.level === 0 && (ruleData.group as TConditionalSelection[]).length === maxLen) {
127
+ console.warn(`最外层子项最多添加${maxLen}个条件`);
128
+ return;
129
+ }
130
+ }
131
+ updateRulesData(draft => {
132
+ const target = findNode(draft, ruleData._id);
133
+ if (target && Array.isArray(target.group)) {
134
+ target.group.push(getTempRules(target.level + 1));
135
+ }
136
+ });
137
+ },
138
+ [props.zeroLevelMaxLength, updateRulesData],
139
+ );
140
+
141
+ // 创建子级规则:将当前 INDIVIDUAL 节点升级为 GROUP 节点
142
+ const createChildRules = useCallback(
143
+ (ruleData: TConditionalSelection) => {
144
+ updateRulesData(draft => {
145
+ const target = findNode(draft, ruleData._id);
146
+ if (!target) return;
147
+
148
+ if (target.framework === EConditionalSelectionFramework.INDIVIDUAL) {
149
+ const firstChild: TConditionalSelection = {
150
+ _id: crypto.randomUUID(),
151
+ framework: EConditionalSelectionFramework.INDIVIDUAL,
152
+ individual: cloneDeep(target.individual ?? {}),
153
+ level: target.level + 1,
154
+ };
155
+ const secondChild = getTempRules(target.level + 1);
156
+ target.framework = EConditionalSelectionFramework.GROUP;
157
+ target.link = EConditionalSelectionLink.AND;
158
+ target._id = crypto.randomUUID();
159
+ target.group = [firstChild, secondChild];
160
+ delete target.individual;
161
+ } else {
162
+ // 已是 GROUP,追加子项
163
+ if (Array.isArray(target.group)) {
164
+ target.group.push(getTempRules(target.level + 1));
165
+ }
166
+ }
167
+ });
168
+ },
169
+ [updateRulesData],
170
+ );
171
+
172
+ // 删除规则
173
+ const delRules = useCallback((ruleData: TConditionalSelection, index: number) => {
174
+ updateRulesData(draft => {
175
+ const target = findNode(draft, ruleData._id);
176
+ if (!target || !Array.isArray(target.group)) return;
177
+
178
+ target.group.splice(index, 1);
179
+
180
+ if (target.framework === EConditionalSelectionFramework.GROUP && target.group.length === 1) {
181
+ const onlyChild = target.group[0];
182
+ if (
183
+ onlyChild.framework === EConditionalSelectionFramework.GROUP &&
184
+ Array.isArray(onlyChild.group) &&
185
+ onlyChild.group.length > 1
186
+ ) {
187
+ // 唯一子项是 GROUP,提升到当前节点
188
+ target.framework = EConditionalSelectionFramework.GROUP;
189
+ target.link = onlyChild.link;
190
+ target._id = onlyChild._id;
191
+ target.group = onlyChild.group;
192
+ delete target.individual;
193
+ } else {
194
+ // 唯一子项是 INDIVIDUAL,降级
195
+ target.framework = EConditionalSelectionFramework.INDIVIDUAL;
196
+ target._id = onlyChild._id;
197
+ target.individual = cloneDeep(onlyChild.individual ?? {});
198
+ delete target.link;
199
+ delete target.group;
200
+ }
201
+ subtractLevel(onlyChild);
202
+ }
203
+ });
204
+ }, [updateRulesData]);
205
+
206
+ // 获取并校验数据
207
+ const getConditionalSelectionData = useCallback(
208
+ (validate = true): Promise<TConditionalSelection> => {
209
+ return new Promise((resolve, reject) => {
210
+ if (validate && checkData(rulesData)) {
211
+ console.error('请填写完整');
212
+ reject('含有未填写完整的项');
213
+ return;
214
+ }
215
+ resolve(cloneDeep(rulesData));
216
+ });
217
+ },
218
+ [rulesData],
219
+ );
220
+
221
+ return {
222
+ rulesData,
223
+ setRulesData,
224
+ level,
225
+ disabledConfig,
226
+ createRules,
227
+ createChildRules,
228
+ delRules,
229
+ getConditionalSelectionData,
230
+ isGroup,
231
+ getTempRules,
232
+ updateRulesData,
233
+ };
234
+ }
@@ -0,0 +1,109 @@
1
+ import { useEffect, useRef, useImperativeHandle, forwardRef, useCallback } from 'react';
2
+ import { cloneDeep } from 'lodash-es';
3
+ import ConditionalContent from './components/conditional-content';
4
+ import { useConditionalHandle, getTempRules, isGroup, findNode } from './composables/useConditionalHandle';
5
+ import { type TConditionalSelectionProps } from './types';
6
+ import './index.less';
7
+
8
+ export type { TConditionalSelectionProps };
9
+
10
+ const ConditionalSelection = forwardRef<
11
+ { getConditionalSelectionData: (validate?: boolean) => Promise<any> },
12
+ TConditionalSelectionProps
13
+ >((props, ref) => {
14
+ const { conditionalRules, onChange, renderConditionRules, renderCreateCondition } = props;
15
+
16
+ const { rulesData, setRulesData, level, disabledConfig, createRules, createChildRules, delRules, getConditionalSelectionData, updateRulesData } =
17
+ useConditionalHandle(props);
18
+
19
+ // 暴露 getConditionalSelectionData 给父组件
20
+ useImperativeHandle(ref, () => ({ getConditionalSelectionData }), [getConditionalSelectionData]);
21
+
22
+ // 监听 rulesData 变化并抛出 onChange
23
+ const isFirstRender = useRef(true);
24
+ useEffect(() => {
25
+ if (isFirstRender.current) {
26
+ isFirstRender.current = false;
27
+ return;
28
+ }
29
+ onChange?.(rulesData);
30
+ }, [rulesData]);
31
+
32
+ //初始化
33
+ useEffect(() => {
34
+ if (conditionalRules && Object.keys(conditionalRules).length !== 0) {
35
+ setRulesData(cloneDeep(conditionalRules));
36
+ } else {
37
+ setRulesData(getTempRules());
38
+ }
39
+ }, []);
40
+
41
+ // 递归/slot相关 handler 用 useCallback 包裹,依赖项只放 updateRulesData/findNode/renderConditionRules
42
+ const handleUpdateNode = useCallback((nodeId: string, patch: Partial<any>) => {
43
+ updateRulesData(draft => {
44
+ const target = findNode(draft, nodeId);
45
+ if (!target) return;
46
+ Object.assign(target, patch);
47
+ });
48
+ }, [updateRulesData]);
49
+
50
+ const handleRenderConditionItem = useCallback(
51
+ (item: any) => renderConditionRules?.(item, (val: Record<string, any>) => {
52
+ updateRulesData(draft => {
53
+ const target = findNode(draft, item._id);
54
+ if (!target) return;
55
+ target.individual = val;
56
+ });
57
+ }),
58
+ [renderConditionRules, updateRulesData]
59
+ );
60
+
61
+ const handleRenderConditionRules = useCallback(
62
+ (rulesData: any, change: (val: Record<string, any>) => void) =>
63
+ renderConditionRules?.(rulesData, change),
64
+ [renderConditionRules]
65
+ );
66
+
67
+ return (
68
+ <div className="conditional-selection">
69
+ {/* 新增条件按钮区域 */}
70
+ {!disabledConfig.addItem &&
71
+ (renderCreateCondition ? (
72
+ renderCreateCondition({ createRules: createChildRules, rulesData })
73
+ ) : (
74
+ <span className="create-box" onClick={() => createChildRules(rulesData)}>
75
+ <span style={{ color: '#00c8be', marginRight: 4 }}>➕</span>
76
+ 添加条件
77
+ </span>
78
+ ))}
79
+
80
+ {/* 规则内容区域 */}
81
+ <div className="conditional-content">
82
+ {isGroup(rulesData) && (rulesData.group as any[]).length > 0 ? (
83
+ <ConditionalContent
84
+ levelData={rulesData}
85
+ level={level}
86
+ disabledConfig={disabledConfig}
87
+ onUpdateNode={handleUpdateNode}
88
+ onCreateRules={createRules}
89
+ onCreateChildRules={createChildRules}
90
+ onDelRules={delRules}
91
+ renderConditionItem={handleRenderConditionItem}
92
+ />
93
+ ) : (
94
+ handleRenderConditionRules(rulesData, (val: Record<string, any>) => {
95
+ updateRulesData(draft => {
96
+ const target = findNode(draft, rulesData._id);
97
+ if (!target) return;
98
+ target.individual = val;
99
+ });
100
+ })
101
+ )}
102
+ </div>
103
+ </div>
104
+ );
105
+ });
106
+
107
+ ConditionalSelection.displayName = 'ConditionalSelection';
108
+
109
+ export default ConditionalSelection;
@@ -0,0 +1,91 @@
1
+ .conditional-selection {
2
+ width: 100%;
3
+
4
+ .create-box {
5
+ display: inline-block;
6
+ margin-bottom: 8px;
7
+ cursor: pointer;
8
+ }
9
+
10
+ .conditional-content {
11
+ width: 100%;
12
+ }
13
+ }
14
+
15
+ .relative-box {
16
+ position: relative;
17
+ width: 100%;
18
+
19
+ .conditional-list-box {
20
+ flex: 1;
21
+ }
22
+
23
+ .conditional-item {
24
+ display: flex;
25
+ align-items: center;
26
+ margin-top: 8px;
27
+ }
28
+
29
+ .conditional-list:first-child {
30
+ margin-top: -8px;
31
+ }
32
+
33
+ .right-box {
34
+ margin-left: 32px;
35
+ }
36
+ }
37
+
38
+ .link-line {
39
+ position: absolute;
40
+ z-index: 999;
41
+ height: 100%;
42
+ margin: 0 4px;
43
+
44
+ .link-label {
45
+ position: absolute;
46
+ top: 50%;
47
+ width: 22px;
48
+ color: #c85000;
49
+ text-align: center;
50
+ cursor: pointer;
51
+ user-select: none;
52
+ background-color: #f9e5e5;
53
+ border-radius: 4px;
54
+ transform: translateY(-50%);
55
+ }
56
+ }
57
+
58
+ .link-line::before {
59
+ position: absolute;
60
+ top: 0;
61
+ bottom: 0;
62
+ left: 10px;
63
+ width: 2px;
64
+ content: '';
65
+ background-color: #c85000;
66
+ opacity: 0.2;
67
+ }
68
+
69
+ .conditional-handle {
70
+ display: flex;
71
+ gap: 8px;
72
+ align-items: center;
73
+
74
+ .create-handle {
75
+ display: inline-block;
76
+ width: 50px;
77
+ cursor: pointer;
78
+ font-size: 14px;
79
+ }
80
+
81
+ .del-handle {
82
+ display: inline-block;
83
+ font-size: 14px;
84
+ width: 24px;
85
+ cursor: pointer;
86
+ }
87
+
88
+ .del-handle:hover {
89
+ color: red;
90
+ }
91
+ }
@@ -0,0 +1,5 @@
1
+ import ConditionalSelection from './conditional-selection';
2
+ export * from './types';
3
+ export {
4
+ ConditionalSelection
5
+ }