@capillarytech/blaze-ui 0.1.6-alpha.53 → 0.1.6-alpha.55

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.
@@ -23,6 +23,7 @@ const CapUnifiedSelect = ({
23
23
  style,
24
24
  isError = false,
25
25
  errorMessage,
26
+ containerClassName,
26
27
  popoverClassName,
27
28
  allowClear = false,
28
29
  headerLabel,
@@ -41,117 +42,196 @@ const CapUnifiedSelect = ({
41
42
  noResultCustomIcon = 'warning',
42
43
  ...rest
43
44
  }) => {
44
-
45
45
  const [searchText, setSearchText] = useState('');
46
46
  const [tempValue, setTempValue] = useState(value);
47
- const [allSelected, setAllSelected] = useState(false);
48
47
  const [dropdownOpen, setDropdownOpen] = useState(false);
49
48
 
50
-
51
49
  useEffect(() => {
52
50
  setTempValue(value);
53
51
  }, [value]);
54
52
 
55
- const treeSelectVirtualizationProps = useMemo(() => ({
56
- listHeight: 256,
53
+ const treeSelectVirtualizationProps = {
54
+ listHeight: 256,
57
55
  listItemHeight: 32,
58
- }), []);
56
+ };
59
57
 
60
- const NoResult = memo(({ noResultCustomText, className, showUpload, options }) => (
61
- <CapRow
62
- className={classnames(className, "cap-unified-select-no-result")}
63
- align="middle"
58
+ const NoResult = ({ noResultCustomText, className, showUpload, options }) => (
59
+ <CapRow
60
+ className={classnames(className, 'cap-unified-select-no-result')}
61
+ align="middle"
64
62
  gap={8}
65
63
  >
66
64
  <CapIcon type={noResultCustomIcon} size="m" />
67
- <CapLabel className="cap-unified-select-no-result-text">{showUpload && options?.length === 0 ? noResultCustomText : 'No results found'}</CapLabel>
65
+ <CapLabel className="cap-unified-select-no-result-text">
66
+ {showUpload && options?.length === 0
67
+ ? noResultCustomText
68
+ : 'No results found'}
69
+ </CapLabel>
68
70
  </CapRow>
69
- ));
70
-
71
- const getFilteredTreeData = useCallback((data, search) => {
72
- if (!search) return data;
73
-
74
- const filterNode = node => {
75
- if (!node) return false;
76
- if (searchBasedOn === 'value') {
77
- const valueText = String(node?.value || '').toLowerCase();
78
- return valueText.includes(search.toLowerCase());
79
- } else if (searchBasedOn === 'key') {
80
- const keyText = String(node?.key || '').toLowerCase();
81
- return keyText.includes(search.toLowerCase());
82
- } else {
83
- const labelText = node?.label?.toLowerCase() || '';
84
- return labelText.includes(search.toLowerCase());
85
- }
71
+ );
72
+
73
+ const getFilteredTreeData = useCallback(
74
+ (data, search) => {
75
+ if (!search || !data || data.length === 0) return data;
76
+ const searchLower = search.toLowerCase();
77
+
78
+ const filterNode = (node) => {
79
+ if (!node) return false;
80
+
81
+ let textToSearch = '';
82
+
83
+ if (searchBasedOn === 'value') {
84
+ textToSearch = String(node.value || '').toLowerCase();
85
+ } else if (searchBasedOn === 'key') {
86
+ textToSearch = String(node.key || '').toLowerCase();
87
+ } else {
88
+ textToSearch = String(node.label || node.title || '').toLowerCase();
89
+ }
90
+
91
+ return textToSearch.includes(searchLower);
92
+ };
93
+
94
+ const loop = (data) => {
95
+ if (!data) return [];
96
+
97
+ return data
98
+ .map((item) => {
99
+ if (!item) return null;
100
+
101
+ const children =
102
+ item.children && item.children.length > 0
103
+ ? loop(item.children)
104
+ : [];
105
+
106
+ if (filterNode(item) || children.length > 0) {
107
+ return { ...item, children };
108
+ }
109
+ return null;
110
+ })
111
+ .filter(Boolean);
112
+ };
113
+
114
+ return loop(data);
115
+ },
116
+ [searchBasedOn],
117
+ );
118
+
119
+ const processTreeData = useCallback((nodes, selectedValues = null) => {
120
+ const result = {
121
+ leafValues: [],
122
+ parentChildMap: {},
123
+ nodeMap: {},
124
+ selectedCount: 0,
86
125
  };
87
126
 
88
- const loop = data =>
89
- data.map(item => {
90
- const children = item.children ? loop(item.children) : [];
91
- if (filterNode(item) || children.length) {
92
- return { ...item, children };
127
+ if (!nodes) return result;
128
+
129
+ const traverse = (items) => {
130
+ items.forEach((item) => {
131
+ result.nodeMap[item.value] = item;
132
+
133
+ if (item.children && item.children.length > 0) {
134
+ result.parentChildMap[item.value] = item.children.map(
135
+ (child) => child.value,
136
+ );
137
+ traverse(item.children);
138
+ } else {
139
+ result.leafValues.push(item.value);
93
140
  }
94
- return null;
95
- }).filter(Boolean);
141
+ });
142
+ };
143
+ traverse(nodes);
144
+
145
+ if (
146
+ selectedValues &&
147
+ Array.isArray(selectedValues) &&
148
+ selectedValues.length > 0
149
+ ) {
150
+ const expandedSet = new Set(selectedValues);
151
+
152
+ const processNode = (value) => {
153
+ const children = result.parentChildMap[value];
154
+ if (!children) return;
155
+
156
+ children.forEach((childValue) => {
157
+ expandedSet.add(childValue);
158
+ processNode(childValue);
159
+ });
160
+ };
161
+
162
+ selectedValues.forEach(processNode);
163
+
164
+ result.leafValues.forEach((value) => {
165
+ if (expandedSet.has(value)) result.selectedCount++;
166
+ });
167
+ }
96
168
 
97
- return loop(data);
98
- }, [searchBasedOn]);
169
+ return result;
170
+ }, []);
99
171
 
100
- const flattenLeafValues = useCallback(nodes =>
101
- nodes?.flatMap(node => node?.children ? flattenLeafValues(node.children) : [node?.value]) || [], []);
172
+ const isMulti = useMemo(
173
+ () => type === 'multiSelect' || type === 'multiTreeSelect',
174
+ [type],
175
+ );
176
+ const isTree = useMemo(
177
+ () => type === 'treeSelect' || type === 'multiTreeSelect',
178
+ [type],
179
+ );
102
180
 
103
- const isMulti = useMemo(() => type === 'multiSelect' || type === 'multiTreeSelect', [type]);
104
- const isTree = useMemo(() => type === 'treeSelect' || type === 'multiTreeSelect', [type]);
105
-
106
181
  const dataSource = useMemo(() => {
107
- return isTree ? options : options?.map(opt => ({ title: opt?.label, value: opt?.value, key: opt?.key || opt?.value }));
182
+ // Skip transformation if options is empty or undefined
183
+ if (!options || options.length === 0) return [];
184
+
185
+ // Only transform if not a tree select
186
+ return isTree
187
+ ? options
188
+ : options.map((opt) => ({
189
+ title: opt?.label,
190
+ value: opt?.value,
191
+ key: opt?.key || opt?.value,
192
+ }));
108
193
  }, [isTree, options]);
109
194
 
110
- const filteredTree = useMemo(() => getFilteredTreeData(dataSource, searchText), [dataSource, searchText]);
111
- const leafValues = useMemo(() => flattenLeafValues(filteredTree), [filteredTree]);
112
-
113
- const handleSelectAll = useCallback(() => {
114
- const availableValues = leafValues;
115
- if (allSelected) {
116
- setTempValue([]);
117
- setAllSelected(false);
118
- } else {
119
- setTempValue(availableValues);
120
- setAllSelected(true);
121
- }
122
- }, [allSelected, leafValues]);
195
+ const filteredTree = useMemo(() => {
196
+ // Skip filtering if search text is empty
197
+ if (!searchText) return dataSource;
123
198
 
124
- useEffect(() => {
125
- if (isMulti && Array.isArray(tempValue)) {
126
- const allItemsSelected = tempValue.length > 0 && leafValues.length > 0 && tempValue.length === leafValues.length;
127
- setAllSelected(allItemsSelected);
128
- }
129
- }, [tempValue, leafValues, isMulti]);
199
+ return getFilteredTreeData(dataSource, searchText);
200
+ }, [dataSource, searchText, getFilteredTreeData]);
130
201
 
131
202
  const handleConfirm = useCallback(() => {
132
203
  if (onChange) onChange(tempValue);
133
204
  setDropdownOpen(false);
134
- }, [onChange, tempValue]);
205
+ if (onConfirm) onConfirm(tempValue);
206
+ }, [onChange, onConfirm, tempValue]);
135
207
 
136
208
  const handleCancel = useCallback(() => {
137
209
  setTempValue(value);
138
210
  setDropdownOpen(false);
139
- }, [value]);
211
+ if (onCancel) onCancel();
212
+ }, [value, onCancel]);
140
213
 
141
- const handleTempChange = useCallback(newValue => {
214
+ const handleTempChange = useCallback((newValue) => {
142
215
  setTempValue(newValue);
143
216
  }, []);
144
217
 
145
- const handleDropdownVisibilityChange = useCallback(open => {
146
- if (open === false) {
147
- setTempValue(value);
148
- }
149
- setDropdownOpen(open);
150
- }, [value]);
218
+ const handleDropdownVisibilityChange = useCallback(
219
+ (open) => {
220
+ if (open === false && !customPopupRender) {
221
+ if (onChange) onChange(tempValue);
222
+ } else if (open === false) {
223
+ setTempValue(value);
224
+ }
225
+ setDropdownOpen(open);
226
+ },
227
+ [value, onChange, tempValue, customPopupRender],
228
+ );
151
229
 
152
230
  const suffix = useMemo(() => {
153
231
  const displayValue = dropdownOpen ? tempValue : value;
154
- return isMulti && Array.isArray(displayValue) && displayValue?.length > 1 ? (
232
+ return isMulti &&
233
+ Array.isArray(displayValue) &&
234
+ displayValue?.length > 1 ? (
155
235
  <>
156
236
  <span>+{displayValue.length - 1} more </span>
157
237
  <CapIcon type={`${dropdownOpen ? 'up' : 'down'}`} size="s" />
@@ -165,12 +245,15 @@ const CapUnifiedSelect = ({
165
245
  if (isMulti) {
166
246
  if (Array.isArray(tempValue) && tempValue?.length > 0) {
167
247
  const firstSelectedValue = tempValue[0];
168
- const firstSelectedOption = options?.find(opt => opt?.value === firstSelectedValue);
248
+ const firstSelectedOption = options?.find(
249
+ (opt) => opt?.value === firstSelectedValue,
250
+ );
169
251
  return firstSelectedOption?.label || null;
170
- }
171
- else if (Array.isArray(value) && value?.length > 0) {
252
+ } else if (Array.isArray(value) && value?.length > 0) {
172
253
  const firstSelectedValue = value[0];
173
- const firstSelectedOption = options?.find(opt => opt?.value === firstSelectedValue);
254
+ const firstSelectedOption = options?.find(
255
+ (opt) => opt?.value === firstSelectedValue,
256
+ );
174
257
  return firstSelectedOption?.label || null;
175
258
  }
176
259
  }
@@ -181,115 +264,215 @@ const CapUnifiedSelect = ({
181
264
  if (!headerLabel && !tooltip) return null;
182
265
  return (
183
266
  <>
184
- <HeaderWrapper className={classnames(disabled ? 'disabled' : '', 'cap-unified-select-header')}>
185
- {headerLabel && <CapLabel type="label16" className={classnames(disabled ? 'disabled' : '', 'cap-unified-select-header-label')}>{headerLabel}</CapLabel>}
186
- {tooltip && (
187
- <CapTooltipWithInfo
188
- title={tooltip}
189
- className={classnames(disabled ? 'disabled' : '', 'cap-unified-select-header-tooltip')}
190
- iconProps={{ disabled }}
191
- />
267
+ <HeaderWrapper
268
+ className={classnames(
269
+ disabled ? 'disabled' : '',
270
+ 'cap-unified-select-header',
271
+ )}
272
+ >
273
+ {headerLabel && (
274
+ <CapLabel
275
+ type="label16"
276
+ className={classnames(
277
+ disabled ? 'disabled' : '',
278
+ 'cap-unified-select-header-label',
279
+ )}
280
+ >
281
+ {headerLabel}
282
+ </CapLabel>
283
+ )}
284
+ {tooltip && (
285
+ <CapTooltipWithInfo
286
+ title={tooltip}
287
+ className={classnames(
288
+ disabled ? 'disabled' : '',
289
+ 'cap-unified-select-header-tooltip',
290
+ )}
291
+ iconProps={{ disabled }}
292
+ />
293
+ )}
294
+ </HeaderWrapper>
295
+ {bylineText && (
296
+ <div className="cap-unified-select-header-byline-text">
297
+ <CapLabel
298
+ className={classnames(
299
+ disabled ? 'disabled' : '',
300
+ 'cap-unified-select-header-byline-text',
301
+ )}
302
+ >
303
+ {bylineText}
304
+ </CapLabel>
305
+ </div>
192
306
  )}
193
- </HeaderWrapper>
194
- {bylineText &&
195
- <div className="cap-unified-select-header-byline-text">
196
- <CapLabel className={classnames(disabled ? 'disabled' : '', 'cap-unified-select-header-byline-text')}>{bylineText}</CapLabel>
197
- </div>
198
- }
199
307
  </>
200
308
  );
201
309
  }, [headerLabel, tooltip, bylineText, disabled]);
202
310
 
203
311
  const renderDropdown = useCallback(() => {
204
312
  const currentItems = filteredTree;
205
- const selectedCount = Array.isArray(tempValue)
206
- ? isTree
207
- ? tempValue?.filter(val => leafValues?.includes(val))?.length || 0
208
- : tempValue?.length || 0
209
- : (tempValue ? 1 : 0);
210
-
211
- const renderCustomDropdown = useCallback(menu => {
212
- if (!customPopupRender) return menu;
213
-
214
- return (
215
- <div className={classnames(popoverClassName, `${type}-popup-container`)}>
216
- {showSearch && (
217
- <CapRow className={classnames("cap-unified-select-search-container")} align="middle">
218
- <Input
219
- prefix={<CapIcon type="search" size="s" style={{ color: styledVars.CAP_G06 }} />}
220
- placeholder="Search"
221
- variant="borderless"
222
- value={searchText}
223
- onChange={e => setSearchText(e.target.value)}
224
- />
225
- </CapRow>
313
+ const selectedCount = Array.isArray(tempValue)
314
+ ? isTree
315
+ ? processTreeData(dataSource, tempValue).selectedCount
316
+ : tempValue?.length || 0
317
+ : tempValue
318
+ ? 1
319
+ : 0;
320
+
321
+ const renderCustomDropdown = useCallback(
322
+ (menu) => {
323
+ if (!customPopupRender) return menu;
324
+
325
+ return (
326
+ <div
327
+ className={classnames(popoverClassName, `${type}-popup-container`)}
328
+ >
329
+ {showSearch && (
330
+ <CapRow
331
+ className={classnames('cap-unified-select-search-container')}
332
+ align="middle"
333
+ >
334
+ <Input
335
+ prefix={
336
+ <CapIcon
337
+ type="search"
338
+ size="s"
339
+ style={{ color: styledVars.CAP_G06 }}
340
+ />
341
+ }
342
+ placeholder="Search"
343
+ variant="borderless"
344
+ value={searchText}
345
+ onChange={(e) => setSearchText(e.target.value)}
346
+ />
347
+ </CapRow>
226
348
  )}
227
- {isMulti && showUpload && (
228
- <CapRow className={classnames("cap-unified-select-upload-container")} align="middle" onClick={onUpload}>
229
- <CapIcon type="upload" size="s" style={{ color: styledVars.CAP_SECONDARY.base }}/>
230
- <CapLabel type="label14" className={classnames("cap-unified-select-upload-label")}>Upload</CapLabel>
231
- </CapRow>
232
- )}
233
- {isMulti && currentItems.length > 0 && (() => {
234
- const totalAvailable = leafValues.length;
235
- const selectedInScope = Array.isArray(tempValue)
236
- ? tempValue.filter(val => leafValues.includes(val)).length
237
- : 0;
238
- return (
349
+ {isMulti && showUpload && (
239
350
  <CapRow
240
- className={classnames("cap-unified-select-select-all-container")}
351
+ className={classnames('cap-unified-select-upload-container')}
241
352
  align="middle"
353
+ onClick={onUpload}
242
354
  >
243
- <Checkbox
244
- className={classnames("cap-unified-select-select-all-checkbox")}
245
- checked={totalAvailable > 0 && selectedInScope === totalAvailable}
246
- indeterminate={selectedInScope > 0 && selectedInScope < totalAvailable}
247
- onChange={e => {
248
- setTempValue(e.target.checked ? leafValues : []);
249
- }}
355
+ <CapIcon
356
+ type="upload"
357
+ size="s"
358
+ style={{ color: styledVars.CAP_SECONDARY.base }}
359
+ />
360
+ <CapLabel
361
+ type="label14"
362
+ className={classnames('cap-unified-select-upload-label')}
250
363
  >
251
- <CapLabel type="label14" className={classnames("cap-unified-select-select-all-label")}>Select all</CapLabel>
252
- </Checkbox>
364
+ Upload
365
+ </CapLabel>
253
366
  </CapRow>
254
- );
255
- })()}
256
-
257
- {currentItems.length === 0 ? <NoResult noResultCustomText={noResultCustomText} className={classnames(className, "cap-unified-select-no-result")} showUpload={showUpload} options={options}/> : menu}
258
-
259
- {currentItems.length > 0 && isMulti && (
260
- <div className="cap-unified-select-confirm-container">
261
- <div className="cap-unified-select-confirm-button-group">
262
- <Button
263
- type="primary"
264
- size="small"
265
- className="cap-unified-select-confirm-button"
266
- onClick={handleConfirm}
267
- >
268
- Confirm
269
- </Button>
270
- <Button
271
- type="text"
272
- className="cap-unified-select-cancel-button"
273
- size="small"
274
- onClick={handleCancel}
275
- >
276
- Cancel
277
- </Button>
278
- <CapLabel className="cap-unified-select-selected-count">
279
- {selectedCount} selected
280
- </CapLabel>
281
- </div>
282
- </div>
283
-
284
- )}
285
- </div>
286
- );
287
- }, [customPopupRender, popoverClassName, type, showSearch, searchText, isMulti, showUpload, currentItems?.length, allSelected, className, noResultCustomText, onUpload, handleSelectAll, handleConfirm, handleCancel]);
367
+ )}
368
+ {isMulti &&
369
+ currentItems.length > 0 &&
370
+ (() => {
371
+ const { leafValues } = processTreeData(currentItems);
372
+ const totalAvailable = leafValues.length;
373
+ const selectedInScope = processTreeData(
374
+ currentItems,
375
+ tempValue,
376
+ ).selectedCount;
377
+
378
+ return (
379
+ <CapRow
380
+ className={classnames(
381
+ 'cap-unified-select-select-all-container',
382
+ )}
383
+ align="middle"
384
+ >
385
+ <Checkbox
386
+ className={classnames(
387
+ 'cap-unified-select-select-all-checkbox',
388
+ )}
389
+ checked={
390
+ totalAvailable > 0 && selectedInScope === totalAvailable
391
+ }
392
+ indeterminate={
393
+ selectedInScope > 0 && selectedInScope < totalAvailable
394
+ }
395
+ onChange={(e) => {
396
+ setTempValue(e.target.checked ? leafValues : []);
397
+ }}
398
+ >
399
+ <CapLabel
400
+ type="label14"
401
+ className={classnames(
402
+ 'cap-unified-select-select-all-label',
403
+ )}
404
+ >
405
+ Select all
406
+ </CapLabel>
407
+ </Checkbox>
408
+ </CapRow>
409
+ );
410
+ })()}
411
+
412
+ {currentItems.length === 0 ? (
413
+ <NoResult
414
+ noResultCustomText={noResultCustomText}
415
+ className={classnames(
416
+ className,
417
+ 'cap-unified-select-no-result',
418
+ )}
419
+ showUpload={showUpload}
420
+ options={options}
421
+ />
422
+ ) : (
423
+ menu
424
+ )}
425
+
426
+ {currentItems.length > 0 && isMulti && (
427
+ <div className="cap-unified-select-confirm-container">
428
+ <div className="cap-unified-select-confirm-button-group">
429
+ <Button
430
+ type="primary"
431
+ size="small"
432
+ className="cap-unified-select-confirm-button"
433
+ onClick={handleConfirm}
434
+ >
435
+ Confirm
436
+ </Button>
437
+ <Button
438
+ type="text"
439
+ className="cap-unified-select-cancel-button"
440
+ size="small"
441
+ onClick={handleCancel}
442
+ >
443
+ Cancel
444
+ </Button>
445
+ <CapLabel className="cap-unified-select-selected-count">
446
+ {selectedCount} selected
447
+ </CapLabel>
448
+ </div>
449
+ </div>
450
+ )}
451
+ </div>
452
+ );
453
+ },
454
+ [
455
+ customPopupRender,
456
+ popoverClassName,
457
+ type,
458
+ showSearch,
459
+ searchText,
460
+ isMulti,
461
+ showUpload,
462
+ currentItems,
463
+ tempValue,
464
+ className,
465
+ noResultCustomText,
466
+ onUpload,
467
+ handleConfirm,
468
+ handleCancel,
469
+ processTreeData,
470
+ ],
471
+ );
288
472
 
289
473
  return (
290
474
  <>
291
475
  <StyledTreeSelect
292
- {...rest}
293
476
  type={type}
294
477
  treeData={filteredTree}
295
478
  value={customPopupRender ? tempValue : value}
@@ -300,7 +483,14 @@ const CapUnifiedSelect = ({
300
483
  maxTagPlaceholder={() => null}
301
484
  prefix={tempValue?.length > 0 ? prefix : undefined}
302
485
  suffixIcon={suffix}
303
- className={classnames(`cap-unified-tree-select cap-unified-tree-select-${size}`, className)}
486
+ className={classnames(
487
+ containerClassName,
488
+ `cap-unified-tree-select`,
489
+ className,
490
+ )}
491
+ classNames={{
492
+ popup: { root: classnames('custom-popup-container', className) },
493
+ }}
304
494
  style={style}
305
495
  status={isError ? 'error' : ''}
306
496
  allowClear={allowClear}
@@ -314,22 +504,57 @@ const CapUnifiedSelect = ({
314
504
  filterTreeNode={false}
315
505
  {...treeSelectVirtualizationProps}
316
506
  popupRender={renderCustomDropdown}
507
+ {...rest}
317
508
  />
318
- {isError && <CapLabel className={classnames("cap-unified-select-status")} style={{ color: 'red' }}>{errorMessage}</CapLabel>}
509
+ {isError && (
510
+ <CapLabel
511
+ className={classnames('cap-unified-select-status')}
512
+ style={{ color: 'red' }}
513
+ >
514
+ {errorMessage}
515
+ </CapLabel>
516
+ )}
319
517
  </>
320
518
  );
321
- }, [filteredTree, tempValue, value, prefix, suffix, className, style, isError, errorMessage, allowClear, isMulti, dropdownOpen, customPopupRender, handleTempChange, onChange, disabled, handleDropdownVisibilityChange, treeSelectVirtualizationProps]);
519
+ }, [
520
+ filteredTree,
521
+ tempValue,
522
+ value,
523
+ prefix,
524
+ suffix,
525
+ className,
526
+ style,
527
+ isError,
528
+ errorMessage,
529
+ allowClear,
530
+ isMulti,
531
+ isTree,
532
+ dropdownOpen,
533
+ customPopupRender,
534
+ handleTempChange,
535
+ onChange,
536
+ disabled,
537
+ handleDropdownVisibilityChange,
538
+ treeSelectVirtualizationProps,
539
+ dataSource,
540
+ processTreeData,
541
+ ]);
322
542
 
323
543
  return (
324
- <SelectWrapper className={classnames(className, 'cap-unified-select-container')}>
544
+ <CapRow className={classnames(className, 'cap-unified-select-container')}>
325
545
  {renderHeader()}
326
546
  {renderDropdown()}
327
- </SelectWrapper>
547
+ </CapRow>
328
548
  );
329
549
  };
330
550
 
331
551
  CapUnifiedSelect.propTypes = {
332
- type: PropTypes.oneOf(['select', 'multiSelect', 'treeSelect', 'multiTreeSelect']),
552
+ type: PropTypes.oneOf([
553
+ 'select',
554
+ 'multiSelect',
555
+ 'treeSelect',
556
+ 'multiTreeSelect',
557
+ ]),
333
558
  options: PropTypes.array,
334
559
  value: PropTypes.any,
335
560
  onChange: PropTypes.func,
@@ -372,7 +597,7 @@ CapUnifiedSelect.defaultProps = {
372
597
  onUpload: () => {},
373
598
  onChange: () => {},
374
599
  onConfirm: () => {},
375
- onCancel: () => {}
600
+ onCancel: () => {},
376
601
  };
377
602
 
378
603
  export default withStyles(CapUnifiedSelect, selectStyles);
@@ -1,17 +1,6 @@
1
1
  import styled, { css } from 'styled-components';
2
2
  import * as styledVars from '../styled/variables';
3
3
 
4
- export const SelectWrapper = styled.div`
5
- display: flex;
6
- flex-direction: column;
7
- gap: 8px;
8
- width: 100%;
9
-
10
- &.disabled {
11
- cursor: not-allowed;
12
- }
13
- `;
14
-
15
4
  export const HeaderWrapper = styled.div`
16
5
  display: flex;
17
6
  align-items: center;
@@ -23,130 +12,146 @@ export const HeaderWrapper = styled.div`
23
12
  }
24
13
  `;
25
14
 
26
- export const DropdownFooter = styled.div`
27
- display: flex;
28
- justify-content: space-between;
29
- align-items: center;
30
- padding: 8px;
31
- border-top: 1px solid #f0f0f0;
32
-
33
- .footer-buttons {
15
+ export const selectStyles = css`
16
+ &.cap-unified-select-container {
34
17
  display: flex;
35
- align-items: center;
18
+ flex-direction: column;
36
19
  gap: 8px;
37
- }
38
-
39
- .total-count {
40
- color: #8c8c8c;
41
- font-size: 12px;
42
- }
43
- `;
44
20
 
45
- export const SearchInputWrapper = styled.div`
46
- padding: 8px;
47
- border-bottom: 1px solid #f0f0f0;
48
- `;
21
+ &.disabled {
22
+ cursor: not-allowed;
23
+ }
24
+ text-align: justify;
25
+ .ant-select-prefix {
26
+ font-size: 14px;
27
+ font-weight: 400;
28
+ color: #091e42;
29
+ line-height: 20px;
30
+ }
31
+ .cap-unified-select-header-label {
32
+ font-family: ${styledVars.FONT_FAMILY};
33
+ font-weight: 500;
34
+ font-size: 14px;
35
+ line-height: 20px;
36
+ letter-spacing: 0px;
37
+ }
38
+ .cap-unified-select-header-byline-text {
39
+ font-family: ${styledVars.FONT_FAMILY};
40
+ font-weight: 400;
41
+ font-size: 12px;
42
+ margin-top: -5px;
43
+ letter-spacing: 0px;
44
+ color: #97a0af;
45
+ }
46
+ .ant-input-affix-wrapper .ant-input-prefix {
47
+ left: 12px;
48
+ }
49
+ .cap-tooltip-with-info-icon {
50
+ margin-top: 2px;
51
+ }
49
52
 
50
- export const SelectAllCheckbox = styled.div`
51
- display: flex;
52
- align-items: center;
53
- padding: 8px 12px;
54
- cursor: pointer;
55
- font-weight: 500;
56
- border-bottom: 1px solid #f0f0f0;
57
- user-select: none;
58
-
59
- input[type="checkbox"] {
60
- cursor: pointer;
53
+ .cap-unified-tree-select {
54
+ min-width: 200px;
55
+ }
61
56
  }
62
- `;
63
-
64
- export const NoResultWrapper = styled.div`
65
- display: flex;
66
- flex-direction: column;
67
- align-items: center;
68
- justify-content: center;
69
- height: 200px;
70
- color: #8c8c8c;
71
- font-size: 14px;
72
- `;
73
-
74
57
 
58
+ .ant-select.ant-select-focused.ant-select-outlined:not(.ant-select-disabled)
59
+ .ant-select-selector {
60
+ border-color: #7a869a !important;
61
+ box-shadow: none;
62
+ outline: 0;
63
+ }
75
64
 
76
- export const StyledInfoIcon = styled.span`
77
- color: ${styledVars.CAP_G05};
78
- font-size: 16px;
79
- cursor: help;
80
- margin-left: 4px;
81
- display: flex;
82
- align-items: center;
65
+ .ant-btn-variant-solid:not(:disabled):not(.ant-btn-disabled):hover {
66
+ background-color: #42b040;
67
+ }
68
+ .ant-select-dropdown {
69
+ margin-top: -8px !important;
70
+ border-radius: 4px;
71
+ box-shadow:
72
+ 0px 4px 8px -2px #091e4240,
73
+ 0px 0px 1px 0px #091e424f;
74
+ max-height: 360px;
75
+ overflow: visible;
76
+ }
83
77
 
84
- &:hover {
85
- color: ${styledVars.CAP_G03};
78
+ .ant-select-selection-item {
79
+ background: transparent;
80
+ }
81
+ .ant-select-multiple .ant-select-selection-wrap {
82
+ align-self: center;
83
+ }
84
+ .cap-unified-tree-select .ant-select-selector:hover {
85
+ border: 1px solid #7a869a;
86
+ }
87
+ .cap-unified-tree-select .ant-select-selector:focus {
88
+ border: 1px solid #7a869a;
89
+ }
90
+ .cap-unified-tree-select .ant-select-tree-treenode {
91
+ padding-left: 4px;
86
92
  }
87
93
 
88
- &.disabled {
89
- cursor: not-allowed;
90
- &:hover {
91
- color: ${styledVars.CAP_G05};
92
- }
94
+ .cap-unified-select-status {
95
+ color: #e83135;
93
96
  }
94
- `;
95
97
 
96
- export const selectStyles = css`
97
- &.cap-unified-select-container {
98
- text-align: justify;
99
- .ant-tree-select-dropdown{
100
- padding: 0px;
101
- .ant-select-tree{
102
- .ant-select-tree-node-content-wrapper{
103
- background-color: transparent;
104
- }
105
- .ant-select-tree-node-content-wrapper:hover {
106
- background-color: transparent;
107
- }
108
- .ant-select-tree-treenode{
109
- line-height: 40px;
110
- margin-bottom: 0px;
111
- .ant-select-tree-checkbox .ant-select-tree-checkbox-inner{
112
- height: 18px;
113
- width: 18px;
114
- border: 2px solid #B3BAC5;
115
- border-radius: 4px;
116
- }
117
- &:hover{
118
- background-color: #FFFBE6;
119
- }
120
- &:not(.ant-select-tree-treenode-disabled) .ant-select-tree-node-content-wrapper:hover{
121
- background-color: none;
122
- }
123
- }
124
- .ant-select-tree-node-content-wrapper{
125
- border-radius: 0px;
126
- padding-left: 3px;
127
- }
128
- .ant-select-tree-indent{
129
- margin-left: 11px;
98
+ /* Common styles for all types */
99
+ &.custom-popup-container {
100
+ width: max-content !important;
101
+
102
+ .ant-select-tree {
103
+ .ant-select-tree-node-content-wrapper {
104
+ background-color: transparent;
105
+ }
106
+ .ant-select-tree-node-content-wrapper:hover {
107
+ background-color: transparent;
108
+ }
109
+ .ant-select-tree-treenode {
110
+ line-height: 40px;
111
+ margin-bottom: 0px;
112
+ .ant-select-tree-checkbox .ant-select-tree-checkbox-inner {
113
+ height: 18px;
114
+ width: 18px;
115
+ border: 2px solid #b3bac5;
116
+ border-radius: 4px;
130
117
  }
131
- .ant-select-tree-switcher:not(.ant-select-tree-switcher-noop):hover:before{
132
- background-color: transparent;
118
+ &:hover {
119
+ background-color: #fffbe6;
133
120
  }
134
- .ant-select-tree-checkbox-checked .ant-select-tree-checkbox-inner{
135
- background-color: #42B040;
136
- border: 2px solid #42B040 !important;
137
- &:hover{
138
- background-color: #42B040;
139
- border: 2px solid #42B040 !important;
140
- }
121
+ &:not(.ant-select-tree-treenode-disabled)
122
+ .ant-select-tree-node-content-wrapper:hover {
123
+ background-color: none;
141
124
  }
142
- .ant-select-tree-switcher .ant-select-tree-switcher-icon{
143
- font-size: 12px;
125
+ }
126
+ .ant-select-tree-node-content-wrapper {
127
+ border-radius: 0px;
128
+ padding-left: 3px;
129
+ }
130
+ .ant-select-tree-indent {
131
+ margin-left: 11px;
132
+ }
133
+ .ant-select-tree-switcher:not(
134
+ .ant-select-tree-switcher-noop
135
+ ):hover:before {
136
+ background-color: transparent;
137
+ }
138
+ .ant-select-tree-checkbox-checked .ant-select-tree-checkbox-inner {
139
+ background-color: #42b040;
140
+ border: 2px solid #42b040 !important;
141
+ &:hover {
142
+ background-color: #42b040;
143
+ border: 2px solid #42b040 !important;
144
144
  }
145
+ }
146
+ .ant-select-tree-switcher .ant-select-tree-switcher-icon {
147
+ font-size: 12px;
148
+ }
145
149
  }
146
- }
147
- .ant-checkbox-wrapper:not(.ant-checkbox-wrapper-disabled):hover .ant-checkbox-checked:not(.ant-checkbox-disabled) .ant-checkbox-inner{
148
- background-color: #42B040;
149
- border: 2px solid #42B040 !important;
150
+ .ant-checkbox-wrapper:not(.ant-checkbox-wrapper-disabled):hover
151
+ .ant-checkbox-checked:not(.ant-checkbox-disabled)
152
+ .ant-checkbox-inner {
153
+ background-color: #42b040;
154
+ border: 2px solid #42b040 !important;
150
155
  }
151
156
  .ant-select-tree-checkbox.ant-select-tree-checkbox-indeterminate
152
157
  .ant-select-tree-checkbox-inner {
@@ -156,7 +161,7 @@ export const selectStyles = css`
156
161
 
157
162
  .ant-select-tree-checkbox.ant-select-tree-checkbox-indeterminate
158
163
  .ant-select-tree-checkbox-inner::after {
159
- content: "";
164
+ content: '';
160
165
  position: absolute;
161
166
  top: 50%;
162
167
  left: 50%;
@@ -166,23 +171,7 @@ export const selectStyles = css`
166
171
  transform: translate(-50%, -50%);
167
172
  border-radius: 1px;
168
173
  }
169
- .cap-unified-tree-select-s{
170
- height: 40px;
171
- width: 160px;
172
- }
173
- .cap-unified-tree-select-m{
174
- height: 40px;
175
- width: 340px;
176
- }
177
- .cap-unified-tree-select-l{
178
- height: 40px;
179
- width: 400px;
180
- }
181
- .cap-unified-tree-select-xl{
182
- height: 40px;
183
- width: 480px;
184
- }
185
- .cap-unified-select-upload-container{
174
+ .cap-unified-select-upload-container {
186
175
  cursor: pointer;
187
176
  display: flex;
188
177
  align-items: center;
@@ -190,24 +179,24 @@ export const selectStyles = css`
190
179
  height: 40px;
191
180
  padding-left: 16px;
192
181
 
193
- .cap-unified-select-upload-label{
182
+ .cap-unified-select-upload-label {
194
183
  margin-left: 12px;
195
- color: #2466EA;
184
+ color: #2466ea;
196
185
  }
197
186
  }
198
- .cap-unified-select-select-all-container{
187
+ .cap-unified-select-select-all-container {
199
188
  padding: 9px 15px;
200
189
  cursor: pointer;
201
190
  display: flex;
202
191
  align-items: center;
203
192
  border-bottom: 1px solid #f0f0f0;
204
193
  height: 40px;
205
- .cap-unified-select-select-all-checkbox{
194
+ .cap-unified-select-select-all-checkbox {
206
195
  display: contents !important;
207
- .ant-checkbox-inner{
196
+ .ant-checkbox-inner {
208
197
  height: 18px;
209
198
  width: 18px;
210
- border: 2px solid #B3BAC5;
199
+ border: 2px solid #b3bac5;
211
200
  border-radius: 4px;
212
201
  }
213
202
  }
@@ -216,7 +205,7 @@ export const selectStyles = css`
216
205
  border-color: #42b040 !important;
217
206
  }
218
207
  .ant-checkbox-indeterminate .ant-checkbox-inner::after {
219
- content: "";
208
+ content: '';
220
209
  position: absolute;
221
210
  top: 50%;
222
211
  left: 50%;
@@ -227,73 +216,21 @@ export const selectStyles = css`
227
216
  border-radius: 1px;
228
217
  }
229
218
  }
230
- .ant-select-outlined:not(.ant-select-disabled):not(.ant-select-customize-input):not(.ant-pagination-size-changer):hover .ant-select-selector {
231
- border-color: #7A869A !important;
232
- }
233
- .ant-select.ant-select-focused.ant-select-outlined:not(.ant-select-disabled) .ant-select-selector {
234
- border-color: #7A869A !important;
235
- box-shadow: none;
236
- outline: 0;
237
- }
238
-
239
- .ant-btn-variant-solid:not(:disabled):not(.ant-btn-disabled):hover{
240
- background-color: #42b040;
241
- }
242
- .ant-select-dropdown{
243
- margin-top: -8px !important;
244
- border-radius: 4px;
245
- box-shadow: 0px 4px 8px -2px #091E4240, 0px 0px 1px 0px #091E424F;
246
- max-height: 368px;
247
- }
248
- .ant-select-prefix{
249
- font-size: 14px;
250
- font-weight: 400;
251
- color: #091E42;
252
- line-height: 20px;
253
- }
254
- .cap-unified-select-header-label{
255
- font-family: ${styledVars.FONT_FAMILY};
256
- font-weight: 500;
257
- font-size: 14px;
258
- line-height: 20px;
259
- letter-spacing: 0px;
260
- }
261
- .cap-unified-select-header-byline-text{
262
- font-family: ${styledVars.FONT_FAMILY};
263
- font-weight: 400;
264
- font-size: 12px;
265
- margin-top: -5px;
266
- letter-spacing: 0px;
267
- color: #97A0AF;
268
- }
269
- .ant-input-affix-wrapper .ant-input-prefix{
270
- left: 12px;
271
- }
272
- .ant-select-selection-item{
273
- background: transparent;
274
- }
275
- .ant-select-multiple .ant-select-selection-wrap{
276
- align-self: center;
277
- }
278
- .cap-unified-tree-select .ant-select-selector:hover{
279
- border: 1px solid #7A869A;
280
- }
281
- .cap-unified-tree-select .ant-select-selector:focus{
282
- border: 1px solid #7A869A;
219
+ .ant-select-outlined:not(.ant-select-disabled):not(
220
+ .ant-select-customize-input
221
+ ):not(.ant-pagination-size-changer):hover
222
+ .ant-select-selector {
223
+ border-color: #7a869a !important;
283
224
  }
284
-
285
- .cap-unified-tree-select .select-popup-container .ant-select-tree-switcher-noop,
286
- .cap-unified-tree-select .multiSelect-popup-container .ant-select-tree-switcher-noop {
287
- display: none;
288
- }
289
- .cap-unified-tree-select .multiSelect-popup-container .ant-select-tree-treenode{
290
- padding-left: 4px;
225
+ .ant-select-tree-treenode.ant-select-tree-treenode-selected {
226
+ background-color: #e9f0fe;
227
+ color: #2466ea;
291
228
  }
292
- .ant-select-tree-treenode.ant-select-tree-treenode-selected{
293
- background-color: #E9F0FE;
294
- color: #2466EA;
229
+ .ant-select-tree-list-holder-inner {
230
+ width: fit-content !important;
231
+ min-width: 100%;
295
232
  }
296
- .cap-unified-select-no-result{
233
+ .cap-unified-select-no-result {
297
234
  display: flex;
298
235
  flex-direction: column;
299
236
  align-items: center;
@@ -302,31 +239,31 @@ export const selectStyles = css`
302
239
  color: #8c8c8c;
303
240
  font-size: 14px;
304
241
  }
305
- .cap-unified-select-no-result-icon{
242
+ .cap-unified-select-no-result-icon {
306
243
  font-size: 36px;
307
244
  margin-bottom: 8px;
308
245
  color: #bfbfbf;
309
246
  }
310
- .cap-unified-select-no-result-text{
247
+ .cap-unified-select-no-result-text {
311
248
  font-weight: 500;
312
249
  }
313
250
  .ant-tree-select:hover .ant-select-selector {
314
- border-color: #7A869A;
251
+ border-color: #7a869a;
315
252
  }
316
253
  .ant-tree-select-focused .ant-select-selector,
317
254
  .ant-tree-select-open .ant-select-selector {
318
- border-color: #7A869A;
255
+ border-color: #7a869a;
319
256
  box-shadow: none;
320
257
  outline: none;
321
258
  }
322
- .cap-unified-select-search-container{
323
- border-bottom: 1px solid #EBECF0 !important;
259
+ .cap-unified-select-search-container {
260
+ border-bottom: 1px solid #ebecf0 !important;
324
261
  line-height: 40px !important;
325
- .ant-input-affix-wrapper{
262
+ .ant-input-affix-wrapper {
326
263
  padding-left: 8px;
327
264
  }
328
265
  }
329
- .cap-unified-select-upload-button{
266
+ .cap-unified-select-upload-button {
330
267
  border: none;
331
268
  padding-left: 15px;
332
269
  }
@@ -335,21 +272,21 @@ export const selectStyles = css`
335
272
  align-items: center;
336
273
  height: 48px;
337
274
  padding: 7px;
338
- border-top: 1px solid #EBECF0;
275
+ border-top: 1px solid #ebecf0;
339
276
  }
340
277
  .cap-unified-select-confirm-button-group {
341
278
  display: flex;
342
279
  padding-left: 8px;
343
280
  align-items: center;
344
281
  width: 100%; /* so it can push the label */
345
- button{
282
+ button {
346
283
  height: 32px;
347
284
  width: 94px;
348
285
  }
349
- .cap-unified-select-confirm-button{
286
+ .cap-unified-select-confirm-button {
350
287
  background-color: #6ebd6e;
351
288
  }
352
- .cap-unified-select-cancel-button{
289
+ .cap-unified-select-cancel-button {
353
290
  border: transparent;
354
291
  box-shadow: none;
355
292
  }
@@ -360,10 +297,7 @@ export const selectStyles = css`
360
297
  font-size: 12px;
361
298
  font-weight: 400;
362
299
  line-height: 16px;
363
- color: #5E6C84;
364
- }
365
- .cap-unified-select-status{
366
- color: #E83135;
300
+ color: #5e6c84;
367
301
  }
368
302
  .cap-unified-select-search-container {
369
303
  .ant-input-affix-wrapper {
@@ -375,12 +309,12 @@ export const selectStyles = css`
375
309
  }
376
310
 
377
311
  .ant-input-affix-wrapper:hover {
378
- border-bottom: 1px solid #7A869A !important;
312
+ border-bottom: 1px solid #7a869a !important;
379
313
  box-shadow: none;
380
314
  }
381
315
 
382
316
  .ant-input-affix-wrapper:focus-within {
383
- border-bottom: 1px solid #091E42 !important;
317
+ border-bottom: 1px solid #091e42 !important;
384
318
  box-shadow: none;
385
319
  outline: none;
386
320
  }
@@ -390,8 +324,29 @@ export const selectStyles = css`
390
324
  box-shadow: none !important;
391
325
  }
392
326
  }
393
- .cap-tooltip-with-info-icon{
394
- margin-top: 2px;
327
+ }
328
+
329
+ &.custom-popup-container {
330
+ /* Multi Select */
331
+ .multiSelect-popup-container {
332
+ .ant-select-tree-list {
333
+ .ant-select-tree-treenode-leaf {
334
+ .ant-select-tree-switcher-noop {
335
+ display: none;
336
+ }
337
+ }
338
+ }
339
+ }
340
+
341
+ /* Single Select */
342
+ .select-popup-container {
343
+ .ant-select-tree-list {
344
+ .ant-select-tree-treenode-leaf {
345
+ .ant-select-tree-switcher-noop {
346
+ display: none;
347
+ }
348
+ }
349
+ }
395
350
  }
396
351
  }
397
- `;
352
+ `;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/blaze-ui",
3
3
  "author": "Capillary Technologies",
4
- "version": "0.1.6-alpha.53",
4
+ "version": "0.1.6-alpha.55",
5
5
  "description": "Capillary UI component library with Ant Design v5",
6
6
  "main": "./index.js",
7
7
  "sideEffects": [