@capillarytech/blaze-ui 0.1.6-alpha.5 → 0.1.6-alpha.51

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.
Files changed (101) hide show
  1. package/.DS_Store +0 -0
  2. package/CapIcon/CapIcon.js +183 -0
  3. package/CapIcon/index.js +3 -0
  4. package/CapIcon/styles.js +76 -0
  5. package/CapInput/CapInput.js +1 -1
  6. package/CapInput/Number.js +1 -1
  7. package/CapInput/Search.js +1 -1
  8. package/CapInput/TextArea.js +1 -1
  9. package/CapLabel/CapLabel.js +101 -81
  10. package/CapLabel/index.js +3 -1
  11. package/CapLabel/styles.js +250 -212
  12. package/CapRow/CapRow.js +111 -10
  13. package/CapRow/index.js +3 -1
  14. package/CapRow/styles.js +47 -6
  15. package/CapSkeleton/CapSkeleton.js +17 -0
  16. package/CapSkeleton/index.js +1 -0
  17. package/CapSpin/CapSpin.js +23 -0
  18. package/CapSpin/index.js +1 -0
  19. package/CapTable/loadable.js +4 -4
  20. package/CapTable/styles.js +1 -1
  21. package/CapTestSelect/CapTestSelect.js +47 -0
  22. package/CapTestSelect/index.js +1 -0
  23. package/CapTooltip/CapTooltip.js +87 -25
  24. package/CapTooltip/index.js +3 -1
  25. package/CapTooltip/styles.js +19 -27
  26. package/CapTooltipWithInfo/CapTooltipWithInfo.js +82 -0
  27. package/CapTooltipWithInfo/index.js +3 -0
  28. package/CapTooltipWithInfo/styles.js +22 -0
  29. package/CapUnifiedSelect/CapUnifiedSelect.js +309 -66
  30. package/CapUnifiedSelect/index.js +1 -4
  31. package/CapUnifiedSelect/styles.js +258 -151
  32. package/assets/upload.svg +3 -0
  33. package/index.js +12 -1
  34. package/package.json +5 -11
  35. package/utils/index.js +1 -0
  36. package/utils/withStyles.js +24 -0
  37. package/CapHeading/CapHeading.js +0 -71
  38. package/CapHeading/index.js +0 -1
  39. package/CapHeading/styles.js +0 -125
  40. package/CapInfoNote/CapInfoNote.js +0 -54
  41. package/CapInfoNote/index.js +0 -1
  42. package/CapInfoNote/styles.js +0 -63
  43. package/CapInput/loadable.js +0 -9
  44. package/CapUnifiedSelect/loadable.js +0 -3
  45. package/dist/235.index.js +0 -2
  46. package/dist/235.index.js.LICENSE.txt +0 -29
  47. package/dist/603.index.js +0 -1
  48. package/dist/CapInput/CapInput.js +0 -66
  49. package/dist/CapInput/Number.js +0 -42
  50. package/dist/CapInput/Search.js +0 -35
  51. package/dist/CapInput/TextArea.js +0 -42
  52. package/dist/CapInput/index.js +0 -15
  53. package/dist/CapInput/messages.js +0 -32
  54. package/dist/CapInput/styles.js +0 -11
  55. package/dist/CapTable/CapTable.js +0 -148
  56. package/dist/CapTable/index.js +0 -9
  57. package/dist/CapTable/loadable.js +0 -23
  58. package/dist/CapTable/styles.js +0 -26
  59. package/dist/LocaleHoc/index.js +0 -40
  60. package/dist/esm/CapHeading/CapHeading.js +0 -41
  61. package/dist/esm/CapHeading/index.js +0 -1
  62. package/dist/esm/CapHeading/styles.js +0 -123
  63. package/dist/esm/CapInfoNote/CapInfoNote.js +0 -62
  64. package/dist/esm/CapInfoNote/index.js +0 -1
  65. package/dist/esm/CapInfoNote/styles.js +0 -6
  66. package/dist/esm/CapInput/CapInput.js +0 -57
  67. package/dist/esm/CapInput/Number.js +0 -35
  68. package/dist/esm/CapInput/Search.js +0 -28
  69. package/dist/esm/CapInput/TextArea.js +0 -35
  70. package/dist/esm/CapInput/index.js +0 -8
  71. package/dist/esm/CapInput/loadable.js +0 -9
  72. package/dist/esm/CapInput/messages.js +0 -25
  73. package/dist/esm/CapInput/styles.js +0 -3
  74. package/dist/esm/CapLabel/CapLabel.js +0 -50
  75. package/dist/esm/CapLabel/index.js +0 -1
  76. package/dist/esm/CapLabel/styles.js +0 -219
  77. package/dist/esm/CapRow/CapRow.js +0 -22
  78. package/dist/esm/CapRow/index.js +0 -1
  79. package/dist/esm/CapRow/styles.js +0 -5
  80. package/dist/esm/CapTable/CapTable.js +0 -140
  81. package/dist/esm/CapTable/index.js +0 -2
  82. package/dist/esm/CapTable/loadable.js +0 -12
  83. package/dist/esm/CapTable/styles.js +0 -17
  84. package/dist/esm/CapTooltip/CapTooltip.js +0 -34
  85. package/dist/esm/CapTooltip/index.js +0 -1
  86. package/dist/esm/CapTooltip/styles.js +0 -6
  87. package/dist/esm/CapUnifiedSelect/CapUnifiedSelect.js +0 -101
  88. package/dist/esm/CapUnifiedSelect/index.js +0 -3
  89. package/dist/esm/CapUnifiedSelect/loadable.js +0 -4
  90. package/dist/esm/CapUnifiedSelect/messages.js +0 -23
  91. package/dist/esm/CapUnifiedSelect/styles.js +0 -15
  92. package/dist/esm/LocaleHoc/index.js +0 -31
  93. package/dist/esm/index.js +0 -11
  94. package/dist/esm/styled/index.js +0 -5
  95. package/dist/esm/styled/variables.js +0 -88
  96. package/dist/esm/translations/en.js +0 -329
  97. package/dist/index.js +0 -39
  98. package/dist/index.js.LICENSE.txt +0 -7
  99. package/dist/styled/index.js +0 -22
  100. package/dist/styled/variables.js +0 -94
  101. package/dist/translations/en.js +0 -335
@@ -1,121 +1,364 @@
1
- // CapUnifiedSelect component using Ant Design v5 Select and TreeSelect directly
2
- import React from 'react';
1
+ // Enhanced CapUnifiedSelect supporting 4 scenarios with advanced features in a single TreeSelect
2
+ import React, { useState, useEffect, useMemo, useCallback, memo } from 'react';
3
3
  import PropTypes from 'prop-types';
4
- import { Select, TreeSelect } from 'antd';
5
- import { SelectWrapper, HeaderWrapper, StyledInfoIcon } from './styles';
6
- import CapLabel from '../CapLabel';
7
- import CapTooltip from '../CapTooltip';
4
+ import classnames from 'classnames';
5
+ import { TreeSelect, Input, Button } from 'antd-v5';
6
+ import styled from 'styled-components';
7
+ import * as styledVars from '../styled/variables';
8
+ import { CapLabel, CapTooltipWithInfo, CapRow, CapIcon } from '../';
9
+ import withStyles from '../utils/withStyles';
10
+ import { SelectWrapper, HeaderWrapper, selectStyles } from './styles';
8
11
 
9
- function CapUnifiedSelect({
12
+ const StyledTreeSelect = styled(TreeSelect)`
13
+ ${selectStyles}
14
+ `;
15
+
16
+ const CapUnifiedSelect = ({
10
17
  type,
11
18
  options = [],
12
- treeData,
13
19
  value,
14
20
  onChange,
15
21
  placeholder = 'Select an option',
16
22
  className,
17
23
  style,
24
+ isError = false,
25
+ errorMessage,
26
+ popoverClassName,
18
27
  allowClear = false,
19
- showSearch = false,
20
- label,
28
+ headerLabel,
29
+ onUpload,
21
30
  tooltip,
31
+ bylineText,
22
32
  disabled = false,
23
- }) {
24
- const selectVirtualizationProps = {
25
- listHeight: 256,
26
- };
33
+ showUpload = false,
34
+ customPopupRender = true,
35
+ showSearch = true,
36
+ searchBasedOn = 'label',
37
+ onConfirm,
38
+ onCancel,
39
+ size = 'm',
40
+ noResultCustomText = 'No results found',
41
+ noResultCustomIcon = 'warning',
42
+ ...rest
43
+ }) => {
44
+
45
+ const [searchText, setSearchText] = useState('');
46
+ const [tempValue, setTempValue] = useState(value);
47
+ const [allSelected, setAllSelected] = useState(false);
48
+ const [dropdownOpen, setDropdownOpen] = useState(false);
49
+
27
50
 
28
- const treeSelectVirtualizationProps = {
29
- listHeight: 256,
51
+ useEffect(() => {
52
+ setTempValue(value);
53
+ }, [value]);
54
+
55
+ const treeSelectVirtualizationProps = useMemo(() => ({
56
+ listHeight: 256,
30
57
  listItemHeight: 32,
31
- };
58
+ }), []);
59
+
60
+ const NoResult = memo(({ noResultCustomText, className, showUpload, options }) => (
61
+ <CapRow
62
+ className={classnames(className, "cap-unified-select-no-result")}
63
+ align="middle"
64
+ gap={8}
65
+ >
66
+ <CapIcon type={noResultCustomIcon} size="m" />
67
+ <CapLabel className="cap-unified-select-no-result-text">{showUpload && options?.length === 0 ? noResultCustomText : 'No results found'}</CapLabel>
68
+ </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
+ }
86
+ };
87
+
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 };
93
+ }
94
+ return null;
95
+ }).filter(Boolean);
96
+
97
+ return loop(data);
98
+ }, [searchBasedOn]);
99
+
100
+ const flattenLeafValues = useCallback(nodes =>
101
+ nodes?.flatMap(node => node?.children ? flattenLeafValues(node.children) : [node?.value]) || [], []);
102
+
103
+ const isMulti = useMemo(() => type === 'multiSelect' || type === 'multiTreeSelect', [type]);
104
+ const isTree = useMemo(() => type === 'treeSelect' || type === 'multiTreeSelect', [type]);
105
+
106
+ const dataSource = useMemo(() => {
107
+ return isTree ? options : options?.map(opt => ({ title: opt?.label, value: opt?.value, key: opt?.key || opt?.value }));
108
+ }, [isTree, options]);
109
+
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]);
123
+
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]);
130
+
131
+ const handleConfirm = useCallback(() => {
132
+ if (onChange) onChange(tempValue);
133
+ setDropdownOpen(false);
134
+ }, [onChange, tempValue]);
135
+
136
+ const handleCancel = useCallback(() => {
137
+ setTempValue(value);
138
+ setDropdownOpen(false);
139
+ }, [value]);
140
+
141
+ const handleTempChange = useCallback(newValue => {
142
+ setTempValue(newValue);
143
+ }, []);
144
+
145
+ const handleDropdownVisibilityChange = useCallback(open => {
146
+ if (open === false) {
147
+ setTempValue(value);
148
+ }
149
+ setDropdownOpen(open);
150
+ }, [value]);
151
+
152
+ const suffix = useMemo(() => {
153
+ const displayValue = dropdownOpen ? tempValue : value;
154
+ return isMulti && Array.isArray(displayValue) && displayValue?.length > 1 ? (
155
+ <>
156
+ <span>+{displayValue.length - 1} more </span>
157
+ <CapIcon type={`${dropdownOpen ? 'up' : 'down'}`} size="s" />
158
+ </>
159
+ ) : (
160
+ <CapIcon type={`${dropdownOpen ? 'up' : 'down'}`} size="s" />
161
+ );
162
+ }, [isMulti, value, tempValue, dropdownOpen]);
163
+
164
+ const prefix = useMemo(() => {
165
+ if (isMulti) {
166
+ if (Array.isArray(tempValue) && tempValue?.length > 0) {
167
+ const firstSelectedValue = tempValue[0];
168
+ const firstSelectedOption = options?.find(opt => opt?.value === firstSelectedValue);
169
+ return firstSelectedOption?.label || null;
170
+ }
171
+ else if (Array.isArray(value) && value?.length > 0) {
172
+ const firstSelectedValue = value[0];
173
+ const firstSelectedOption = options?.find(opt => opt?.value === firstSelectedValue);
174
+ return firstSelectedOption?.label || null;
175
+ }
176
+ }
177
+ return null;
178
+ }, [isMulti, value, tempValue, options]);
32
179
 
33
- const renderHeader = () => {
34
- if (!label && !tooltip) return null;
35
-
180
+ const renderHeader = useCallback(() => {
181
+ if (!headerLabel && !tooltip) return null;
36
182
  return (
37
- <HeaderWrapper className={disabled ? 'disabled' : ''}>
38
- {label && (
39
- <CapLabel type="label16" className={disabled ? 'disabled' : ''}>
40
- {label}
41
- </CapLabel>
42
- )}
183
+ <>
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>}
43
186
  {tooltip && (
44
- <CapTooltip title={tooltip}>
45
- <StyledInfoIcon className={disabled ? 'disabled' : ''} />
46
- </CapTooltip>
187
+ <CapTooltipWithInfo
188
+ title={tooltip}
189
+ className={classnames(disabled ? 'disabled' : '', 'cap-unified-select-header-tooltip')}
190
+ iconProps={{ disabled }}
191
+ />
47
192
  )}
48
193
  </HeaderWrapper>
194
+ <div className="cap-unified-select-header-byline-text">
195
+ {bylineText && <CapLabel className={classnames(disabled ? 'disabled' : '', 'cap-unified-select-header-byline-text')}>{bylineText}</CapLabel>}
196
+ </div>
197
+ </>
49
198
  );
50
- };
199
+ }, [headerLabel, tooltip, bylineText, disabled]);
200
+
201
+ const renderDropdown = useCallback(() => {
202
+ const currentItems = filteredTree;
203
+ const selectedCount = Array.isArray(tempValue)
204
+ ? isTree
205
+ ? tempValue?.filter(val => leafValues?.includes(val))?.length || 0
206
+ : tempValue?.length || 0
207
+ : (tempValue ? 1 : 0);
208
+
209
+ const renderCustomDropdown = useCallback(menu => {
210
+ if (!customPopupRender) return menu;
51
211
 
52
- const renderDropdown = () => {
53
- if (type === 'treeSelect' || type === 'multiTreeSelect') {
54
212
  return (
55
- <TreeSelect
56
- treeData={treeData || options}
57
- value={value}
58
- onChange={onChange}
213
+ <div className={classnames(popoverClassName, `${type}-popup-container`)}>
214
+ {showSearch && (
215
+ <CapRow className={classnames("cap-unified-select-search-container")} align="middle">
216
+ <Input
217
+ prefix={<CapIcon type="search" size="s" style={{ color: styledVars.CAP_G06 }} />}
218
+ placeholder="Search"
219
+ variant="borderless"
220
+ value={searchText}
221
+ onChange={e => setSearchText(e.target.value)}
222
+ />
223
+ </CapRow>
224
+ )}
225
+ {isMulti && showUpload && (
226
+ <CapRow className={classnames("cap-unified-select-upload-container")} align="middle" onClick={onUpload}>
227
+ <CapIcon type="upload" size="s" style={{ color: styledVars.CAP_SECONDARY.base }}/>
228
+ <CapLabel type="label14" className={classnames("cap-unified-select-upload-label")}>Upload</CapLabel>
229
+ </CapRow>
230
+ )}
231
+ {isMulti && currentItems.length > 0 && (
232
+ <CapRow
233
+ className={classnames("cap-unified-select-select-all-container")}
234
+ onClick={handleSelectAll}
235
+ align="middle"
236
+ gap={7}
237
+ >
238
+ <input readOnly type="checkbox" checked={allSelected} className={classnames("cap-unified-select-select-all-checkbox")} onClick={handleSelectAll} />
239
+ <CapLabel type="label14" className={classnames("cap-unified-select-select-all-label")}>Select all</CapLabel>
240
+ </CapRow>
241
+ )}
242
+
243
+ {currentItems.length === 0 ? <NoResult noResultCustomText={noResultCustomText} className={classnames(className, "cap-unified-select-no-result")} showUpload={showUpload} options={options}/> : menu}
244
+
245
+ {currentItems.length > 0 && isMulti && (
246
+ <div className="cap-unified-select-confirm-container">
247
+ <div className="cap-unified-select-confirm-button-group">
248
+ <Button
249
+ type="primary"
250
+ size="small"
251
+ className="cap-unified-select-confirm-button"
252
+ onClick={handleConfirm}
253
+ >
254
+ Confirm
255
+ </Button>
256
+ <Button
257
+ type="text"
258
+ className="cap-unified-select-cancel-button"
259
+ size="small"
260
+ onClick={handleCancel}
261
+ >
262
+ Cancel
263
+ </Button>
264
+ <CapLabel className="cap-unified-select-selected-count">
265
+ {selectedCount} selected
266
+ </CapLabel>
267
+ </div>
268
+ </div>
269
+
270
+ )}
271
+ </div>
272
+ );
273
+ }, [customPopupRender, popoverClassName, type, showSearch, searchText, isMulti, showUpload, currentItems?.length, allSelected, className, noResultCustomText, onUpload, handleSelectAll, handleConfirm, handleCancel]);
274
+
275
+ return (
276
+ <>
277
+ <StyledTreeSelect
278
+ {...rest}
279
+ type={type}
280
+ treeData={filteredTree}
281
+ value={customPopupRender ? tempValue : value}
282
+ onChange={customPopupRender ? handleTempChange : onChange}
59
283
  placeholder={placeholder}
60
- className={className}
284
+ showSearch={false}
285
+ maxTagCount={0}
286
+ maxTagPlaceholder={() => null}
287
+ prefix={tempValue?.length > 0 ? prefix : undefined}
288
+ suffixIcon={suffix}
289
+ className={classnames(`cap-unified-tree-select cap-unified-tree-select-${size}`, className)}
61
290
  style={style}
291
+ status={isError ? 'error' : ''}
62
292
  allowClear={allowClear}
63
- showSearch={showSearch}
64
- multiple={type === 'multiTreeSelect' ? true : false}
293
+ multiple={isMulti}
294
+ treeCheckable={isMulti}
295
+ open={dropdownOpen}
296
+ onOpenChange={handleDropdownVisibilityChange}
297
+ showCheckedStrategy={TreeSelect.SHOW_PARENT}
65
298
  virtual
66
- treeDefaultExpandAll
67
299
  disabled={disabled}
300
+ filterTreeNode={false}
68
301
  {...treeSelectVirtualizationProps}
302
+ popupRender={renderCustomDropdown}
69
303
  />
70
- );
71
- }
72
-
73
- return (
74
- <Select
75
- value={value}
76
- onChange={onChange}
77
- placeholder={placeholder}
78
- className={className}
79
- style={style}
80
- allowClear={allowClear}
81
- showSearch={showSearch}
82
- options={options}
83
- mode={type === 'multiSelect' ? 'multiple' : undefined}
84
- virtual
85
- disabled={disabled}
86
- {...selectVirtualizationProps}
87
- />
304
+ {isError && <CapLabel className={classnames("cap-unified-select-status")} style={{ color: 'red' }}>{errorMessage}</CapLabel>}
305
+ </>
88
306
  );
89
- };
307
+ }, [filteredTree, tempValue, value, prefix, suffix, className, style, isError, errorMessage, allowClear, isMulti, dropdownOpen, customPopupRender, handleTempChange, onChange, disabled, handleDropdownVisibilityChange, treeSelectVirtualizationProps]);
90
308
 
91
309
  return (
92
- <SelectWrapper>
310
+ <SelectWrapper className={classnames(className, 'cap-unified-select-container')}>
93
311
  {renderHeader()}
94
312
  {renderDropdown()}
95
313
  </SelectWrapper>
96
314
  );
97
- }
315
+ };
98
316
 
99
317
  CapUnifiedSelect.propTypes = {
100
318
  type: PropTypes.oneOf(['select', 'multiSelect', 'treeSelect', 'multiTreeSelect']),
101
319
  options: PropTypes.array,
102
- treeData: PropTypes.array,
103
320
  value: PropTypes.any,
104
321
  onChange: PropTypes.func,
105
322
  placeholder: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
106
323
  className: PropTypes.string,
107
324
  style: PropTypes.object,
108
325
  allowClear: PropTypes.bool,
109
- showSearch: PropTypes.bool,
110
- label: PropTypes.string,
326
+ headerLabel: PropTypes.string,
111
327
  tooltip: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
112
328
  disabled: PropTypes.bool,
329
+ customPopupRender: PropTypes.bool,
330
+ showSearch: PropTypes.bool,
331
+ searchBasedOn: PropTypes.oneOf(['label', 'value', 'key']),
332
+ onConfirm: PropTypes.func,
333
+ onCancel: PropTypes.func,
334
+ isError: PropTypes.bool,
335
+ errorMessage: PropTypes.string,
336
+ popupClassName: PropTypes.string,
337
+ showUpload: PropTypes.bool,
338
+ onUpload: PropTypes.func,
339
+ size: PropTypes.oneOf(['s', 'm', 'l', 'xl']),
113
340
  };
114
341
 
115
342
  CapUnifiedSelect.defaultProps = {
116
343
  type: 'select',
344
+ placeholder: 'Select an option',
345
+ searchBasedOn: 'label',
346
+ noResultCustomText: 'No results found',
347
+ noResultCustomIcon: 'warning',
348
+ options: [],
349
+ size: 'm',
117
350
  allowClear: false,
118
- showSearch: false,
351
+ customPopupRender: true,
352
+ showSearch: true,
353
+ className: '',
354
+ popupClassName: '',
355
+ disabled: false,
356
+ showUpload: false,
357
+ isError: false,
358
+ onUpload: () => {},
359
+ onChange: () => {},
360
+ onConfirm: () => {},
361
+ onCancel: () => {}
119
362
  };
120
363
 
121
- export default CapUnifiedSelect;
364
+ export default withStyles(CapUnifiedSelect, selectStyles);
@@ -1,4 +1 @@
1
- import CapUnifiedSelect from './CapUnifiedSelect';
2
- import CapUnifiedSelectLoadable from './loadable';
3
-
4
- export default CapUnifiedSelectLoadable;
1
+ export { default } from './CapUnifiedSelect';